如何设置CMake与clang进行Windows嵌入式ARM的交叉编译



我正在尝试生成Ninja makefile,以便使用Clang为ARM Cortex A5 CPU交叉编译C++项目。我为CMake创建了一个工具链文件,但似乎有一个错误或缺少什么东西,我找不到。当使用下面的工具链文件调用CMake时,我会得到以下错误。

CMake命令:

cmake-DCMAKE_TOOLCHAIN_FILE="..\Src\Build\TOOLCHAIN clang arm.cmake"-GNinja。。\Src\

输出:

C编译器标识为Clang 7.0.0 CMake错误,位于C:\Users/user/spoop/apps/CMake/31.14/share/CMake-3.13/Module/CMakeDetermineCompilerId.CMake:802(消息):Clang编译器工具

"C:\Program Files\LLVM/bin/clang.exe">

目标是MSVC ABI,但具有类似GNU的命令行接口。不支持此操作。改为使用"clang cl",例如通过设置环境中的"CC=clang cl"。此外,使用MSVC命令行环境。调用堆栈(最近的调用优先):
C:\Users/user/spoop/apps/cmake/31.34/share/cmake-3.13/Modules/CmakeDetermineCompiler.cmake:113(CMAKE_DIAGNOSE_UNSUPPORTED_CLANG)CMakeLists.txt:2(项目)

--配置不完整,出现错误!

CMake工具链文件(工具链clang arm.CMake):

set(CMAKE_CROSSCOMPILING TRUE)
SET(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
# Clang target triple
SET(TARGET armv7-none-eabi)
# specify the cross compiler
SET(CMAKE_C_COMPILER_TARGET ${TARGET})
SET(CMAKE_C_COMPILER clang)
SET(CMAKE_CXX_COMPILER_TARGET ${TARGET})
SET(CMAKE_CXX_COMPILER clang++)
SET(CMAKE_ASM_COMPILER_TARGET ${TARGET})
SET(CMAKE_ASM_COMPILER clang)
# C/C++ toolchain
SET(TOOLCHAIN "C:/Program Files (x86)/GNU Tools ARM Embedded/7 2018-q2-update")
SET(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN ${TOOLCHAIN})
SET(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN ${TOOLCHAIN})
# specify compiler flags
SET(ARCH_FLAGS "-target armv7-none-eabi -mcpu=cortex-a5")
SET(CMAKE_C_FLAGS "-Wall -Wextra ${ARCH_FLAGS}" CACHE STRING "Common flags for C compiler")
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -std=c++11 -fno-exceptions -fno-threadsafe-statics ${ARCH_FLAGS}" CACHE STRING "Common flags for C++ compiler")

我使用了CMake和Clang文档以及来自网络的一些随机链接来创建工具链文件。整个项目使用ARM GCC for Windows进行了良好的编译,因此工具链文件似乎是拼图中唯一缺失的部分。

编辑

我试图通过强制编译器来绕过CMake编译器检查。我将带有SET(CMAKE_C_COMPILER clang)、SET(CMAKE_CXX_COMPILER clang++)等的行替换为:

CMAKE_FORCE_C_COMPILER(clang Clang)
CMAKE_FORCE_CXX_COMPILER(clang++ Clang)

错误保持不变。

编辑

我可以用clang-target arm none-eabi成功地编译一个hello-world示例。所以问题似乎出在CMake上。我在CMake问题跟踪器中创建了一个错误。

工具版本:

  • clang 7.0.0版(标签/RERELEASE_700/最终版本)
  • cmake版本3.13.4

我的问题通过对错误报告的回复得到了回答,但我在这里添加了答案,以便将所有信息放在一个地方以供将来参考。

简而言之:如果您从llvm.org安装clang,CMake目前不支持使用clang/crang++命令行接口。如果您想使用clang-crang++接口(这是ARM交叉编译所必需的),则必须通过msys2安装clang。

详细

Clang on Windows有两个不同的命令行界面:

  • clang/crang++默认接口,它试图与GCCs gcc/g++兼容,并以GNU ABI为目标
  • clang cl,它试图与Microsoft的Visual C++编译器cl.exe兼容,并以MSVC ABI为目标

为了交叉编译ARM,您需要clang/crang++接口。问题是CMake支持不同的接口,这取决于您安装Clang的方式(有关更多详细信息,请参阅CMake问题跟踪器中的错误):

  • 如果从llvm.org安装Clang,CMake只支持Clang-cl接口
  • 如果您通过msys2安装Clang,CMake支持Clang/crang++接口

下面是我所做的:

  1. 安装msys2
  2. 用pacman安装Clang和CMake。msys2中有两个clang包,一个是mingw32版本,另一个是mingw64版本。我使用了mingw64包(mingw-w64-x86_64-clang)
  3. 启动mingw64 shell并运行CMake并从那里进行构建

工具链文件

我的原始工具链文件有两个问题,花了很长时间才修复。所以我希望这能为其他人节省一些时间:

  1. 目标三元组(例如arm none-eabi)需要与GCC binutils的前缀完全匹配。我的binutils的前缀是arm none-eabi(例如arm none-eabi-ar),所以我不得不相应地更改目标三元组
  2. CMAKE_TRY_COMPILE_TARGET_TYPE需要更改为STATIC_LIBRARY,以防止CMAKE在编译检查期间运行链接器

这是我使用的最后一个工具链文件(你也可以在这个GitHub repo中找到一个很好的工具链文件示例):

cmake_minimum_required(VERSION 3.13)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)
if(DEFINED ENV{GCC_ARM_TOOLCHAIN})
set(GCC_ARM_TOOLCHAIN $ENV{GCC_ARM_TOOLCHAIN})
else()
set(GCC_ARM_TOOLCHAIN "C:/Users/user/tools/gcc-arm-none-eabi-7-2018-q2-update-win32")
endif()
LIST(APPEND CMAKE_PROGRAM_PATH ${GCC_ARM_TOOLCHAIN})
# Specify the cross compiler
# The target triple needs to match the prefix of the binutils exactly
# (e.g. CMake looks for arm-none-eabi-ar)
set(CLANG_TARGET_TRIPLE arm-none-eabi)
set(GCC_ARM_TOOLCHAIN_PREFIX ${CLANG_CLANG_TARGET_TRIPLE})
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET ${CLANG_TARGET_TRIPLE})
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET ${CLANG_TARGET_TRIPLE})
set(CMAKE_ASM_COMPILER clang)
set(CMAKE_ASM_COMPILER_TARGET ${CLANG_TARGET_TRIPLE})
# Don't run the linker on compiler check
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
# Specify compiler flags
set(ARCH_FLAGS "-mcpu=cortex-a5 -mthumb -mfpu=neon-vfpv4 -mfloat-abi=hard -mno-unaligned-access")
set(CMAKE_C_FLAGS "-Wall ${ARCH_FLAGS}" CACHE STRING "Common flags for C compiler")
set(CMAKE_CXX_FLAGS "-Wall -std=c++17 -fno-exceptions -fno-rtti -fno-threadsafe-statics ${ARCH_FLAGS}" CACHE STRING "Common flags for C++ compiler")
set(CMAKE_ASM_FLAGS "-Wall ${ARCH_FLAGS} -x assembler-with-cpp" CACHE STRING "Common flags for assembler")
set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,-Map,kernel.map,--gc-sections -fuse-linker-plugin -Wl,--use-blx --specs=nano.specs --specs=nosys.specs" CACHE STRING "")
# C/C++ toolchain
set(GCC_ARM_SYSROOT "${GCC_ARM_TOOLCHAIN}/${GCC_ARM_TOOLCHAIN_PREFIX}")
# set(CMAKE_SYSROOT ${GCC_ARM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${GCC_ARM_SYSROOT})
# Search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# For libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

这里有一个替代答案,它使用CMake使用GCC工具链而不是clang为嵌入式ARM进行交叉编译,还使用普通的旧make而不是Ninja。我知道这并不能直接回答这个问题,但它是嵌入式ARM的一个非常合理的替代方案,而且我们现在使用的许多基于Eclipse的供应商工具链都是基于GCC而不是LLVM/clang的。

首先从安装最新的"GNU MCU Eclipse ARM Embedded GCC"工具链https://github.com/gnu-mcu-eclipse/arm-none-eabi-gcc/releases(注意:没有安装程序,只需解压缩到您想要的位置即可)。

接下来,使用上提供的安装程序安装最新的MSYS2/MinGWhttps://www.msys2.org/.

由于某些原因,MSYS2的默认安装不包括make。因此,在使用pacman按照安装说明更新默认软件包后,执行"pacman-S make"来安装make。

在MSYS2中有一个可用的cmake构建。然而,它不包括MSYS或MinGW的生成器(不知道为什么),而且(或者因为)在查找外部GCC工具链时似乎存在问题,即使在命令行或工具链文件中明确提供了完整路径也是如此。因此,该解决方案使用CMake的原生Window构建,可在https://cmake.org/download/,而不是cmake的MSYS2版本。

默认情况下,MSYS shell不会继承Windows环境,因此本机Windows CMake不会在MSYS shell路径上。简单的解决方案是在命令行上指定cmake的完整路径。在我的案例中,我在C:\GNU MCU Eclipse/ARM Embedded GCC/8.2.1-1.4-20190214-0604中有GCC交叉编译器工具链。因此,cmake的完整命令如下所示。

/c/Program Files/CMake/bin/cmake.exe -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm-none-eabi.cmake "-DTOOLCHAIN_PREFIX=C:/GNU MCU Eclipse/ARM Embedded GCC/8.2.1-1.4-20190214-0604" -G "MSYS Makefiles" ../

在这里,该命令是从项目根目录下一级的构建目录执行的,而一个同级cmake目录包含指定的工具链文件。注意,反斜杠对于转义cmake.exe路径中的任何空格都是必要的,但在作为参数传递给cmake的引用路径中不使用。

您也可以运行cmake并从普通的旧Windows命令行(cmd.exe)进行右键操作,只要cmake和msys-bin目录都在Windows路径上即可。在这种情况下,不需要指定cmake的完整路径。然而,PowerShell没有成功。

最新更新