如何在 CMake 中指定编译器?

Posted

技术标签:

【中文标题】如何在 CMake 中指定编译器?【英文标题】:How to specify a compiler in CMake? 【发布时间】:2022-01-14 17:55:02 【问题描述】:

我想使用 IAR 编译器。我注意到 CMake 已经有一堆关于这个编译器的文件:

https://github.com/jevinskie/cmake/blob/master/Modules/Compiler/IAR.cmake

从我读到的通用解决方案是在我的CMakeLists.txt 中手动指定所有工具链:

set(CMAKE_C_COMPILER iccarm)
set(CMAKE_CPP_COMPILER iccarm)

CMake 如何将这些定义与“Modules/Compiler/IAR.cmake”联系起来?

我以为我只需要这样做

include("Modules/Compiler/IAR.cmake")

指定 IAR 编译器的正确方法是什么?

当我这样做时

cmake .

它仍然尝试使用gcc 而不是我的 IAR 编译器。为什么?

【问题讨论】:

【参考方案1】:

我看到越来越多的人在CMakeLists.txt project 调用之后设置CMAKE_C_COMPILER 和其他编译器相关变量,我想知道为什么这种方法有时会失效。

实际发生了什么

当 CMake 执行 project() 调用时,它会寻找一个默认编译器可执行文件并确定使用它的方式:默认编译器标志、默认链接器标志、compile features 等。

CMake 将默认编译器可执行文件的路径存储在 CMAKE_C_COMPILER 变量中。

当设置CMAKE_C_COMPILER 变量project() 调用后,此 更改编译器可执行文件:默认标志,所有功能默认编译器保持设置。

AS RESULT:构建项目时,构建系统调用项目指定的编译器可执行文件,但带有参数 适用于默认编译器

正如人们可能猜到的那样,这种方法只有在将默认编译器替换为高度兼容的编译器时才有效。例如。有时用clang 替换gcc 可能会起作用。

这种方法永远行不通,无法用 gcc 替换 cl 编译器(在 Visual Studio 中使用)。当用 cross-compiler 替换 native 编译器时,这也不起作用。

做什么

从不CMakeLists.txt 中设置编译器。

如果您想要,例如,使用 clang 而不是默认的 gcc,那么:

    在配置项目时将-DCMAKE_C_COMPILER=<compiler> 传递给cmake。这样,CMake 将使用此编译器而不是默认编译器,并且在 project() 调用中它将调整指定编译器的所有标志。

    设置CC 环境变量(CXX 用于 C++ 编译器)。 CMake 在选择默认编译器时会检查此变量。

    (仅在极少数情况下)在project() 调用之前设置CMAKE_C_COMPILER 变量。这种方法与第一种方法类似,但会使项目的灵活性降低。

如果上述方法不起作用

如果在命令行 CMake 中设置 CMAKE_C_COMPILER 时出现编译器无法“编译简单项目”的错误,那么您的环境中有问题.. 或者您为所选的 @ 指定了编译器 incompatible 987654322@或平台。

例子:

Visual Studio 生成器可与cl 编译器一起使用,但不能与gcc 一起使用。 MinGW 编译器通常需要MinGW Makefiles 生成器。

不兼容的生成器无法CMakeLists.txt 中修复。需要将正确的-G 选项传递给cmake 可执行文件(或在CMake GUI 中选择正确的生成器)。

交叉编译

交叉编译通常需要设置CMAKE_SYSTEM_NAME变量,这个设置一般应该在toolchain file中完成。那个工具链文件还负责设置一个编译器。

CMakeLists.txt 中设置CMAKE_SYSTEM_NAME 几乎总是错误

【讨论】:

很好地解释了这个问题。顺便说一句,我认为这揭示了 CMake 语言的一个问题。你必须知道他们的算法是如何在命令后面工作的,也就是说,它不遵循声明性模型而不是程序模型。【参考方案2】:

要选择特定的编译器,您有多种解决方案,如 CMake wiki 中所述:

方法一:使用环境变量

对于 C 和 C++,设置 CCCXX 环境变量。不保证此方法适用于所有生成器。 (具体来说,如果你试图设置 Xcode 的GCC_VERSION,这个方法会混淆 Xcode。) 例如:

CC=gcc-4.2 CXX=/usr/bin/g++-4.2 cmake -G "Your Generator" path/to/your/source

方法二:使用cmake -D

使用cmake -D 在命令行上将适当的CMAKE_FOO_COMPILER 变量设置为有效的编译器名称或完整路径。 例如:

cmake -G "Your Generator" -D CMAKE_C_COMPILER=gcc-4.2 -D CMAKE_CXX_COMPILER=g++-4.2 path/to/your/source

方法3(避免):使用set()

使用set() 将适当的CMAKE_FOO_COMPILER 变量设置为列表文件中的有效编译器名称或完整路径。这必须在设置任何语言之前完成(即:在任何project()enable_language() 命令之前)。 例如:

set(CMAKE_C_COMPILER "gcc-4.2")
set(CMAKE_CXX_COMPILER "/usr/bin/g++-4.2")

project("YourProjectName")

该 wiki 未提供应避免使用第三种方法的原因...

【讨论】:

我不明白为什么要避免使用第三种方法。使用第一种方法,用户必须知道他想要使用的编译器,这不应该是这种情况,因为该项目仅使用指定的编译器构建。对于第二个目标,用户必须编写很长的一行来配置项目。我更喜欢将方法 2 的命令放在 bash 文件中。这让我很困惑。 3d 方法的缺点是它硬编码不仅是一个编译器,还有一个路径。或要求用户在PATH 下拥有编译器。在任何情况下,用户都应该知道使用的是哪个编译器。 您可以传递编译器的名称,而无需设置它的完整路径。在这种情况下,它会在 PATH 环境变量中搜索 CMake 常见问题解答页面已移动 here。请编辑。 “path/to/your/source”是指CMake源码目录还是gcc/g++编译器源码目录?【参考方案3】:

您需要创建一个工具链文件,并使用 CmakeForceCompiler 模块。

以下是使用 IAR 进行裸机 ARM 开发的示例工具链文件:

include(CMakeForceCompiler)

set(CMAKE_SYSTEM_NAME Generic) # Or name of your OS if you have one
set(CMAKE_SYSTEM_PROCESSOR arm) # Or whatever
set(CMAKE_CROSSCOMPILING 1)

set(CMAKE_C_COMPILER iccarm) # Change the arm suffix if appropriate
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) # Required to make the previous line work for a target that requires a custom linker file

最后一行是必要的,因为 CMake 将尝试使用编译器编译测试程序以确保其正常工作并从预处理器定义中获取一些版本信息。如果没有这一行,CMake 将对测试程序使用 add_executable(),您将收到错误“C 编译器“XXX”无法编译简单的测试程序。”这是因为测试程序无法链接,因为它没有您的自定义链接器文件(我假设裸机开发,因为这是 IAR 通常用于)。这一行告诉 CMake 使用 add_library() 代替,这使得测试在没有链接器文件的情况下成功。此解决方法的来源:this CMake mailing list post。

然后,假设您的工具链文件名为 iar-toolchain.cmake,调用 CMake 如下:

cmake -DCMAKE_TOOLCHAIN_FILE=iar-toolchain.cmake .

【讨论】:

开发者怎么知道必须写cmake -DCMAKE_TOOLCHAIN_FILE=iar-toolchain.cmake .。在使用 GNU Make 的传统方式中,开发人员看到Makefile 他点击了make,这很简单。使用 CMake 它看起来有点复杂:( 你可以制作一个包装脚本来调用cmake。我在所有项目的根目录下都有一个名为 build.sh 的脚本 我收到The CMAKE_FORCE_C_COMPILER macro is deprecated @nowox 确实已弃用。我已经看到这些警告有一段时间了,但是当我尝试更改它时,我收到了错误:“C 编译器 XXX 无法编译简单的测试程序”。当时我找不到解决方案,所以我一直在接受警告。感谢您,我再次查看并找到了解决方法,请参阅我的编辑!【参考方案4】:

如果您不想使用 PC 的标准编译器,则必须为 CMake 提供编译器的路径。您可以通过环境变量、工具链文件或 CMake 命令行中的直接定义来执行此操作(参见例如 CMake Error at CMakeLists.txt:30 (project): No CMAKE_C_COMPILER could be found)。

将编译器的名称/路径放入您的 CMakeLists.txt 会阻止您的项目跨平台。

CMake 确实通过编译 special C/C++ files 来检查编译器 ID。因此无需手动包含来自Module/CompilerModule/Platform

这将由 CMake 根据其编译器和平台检查自动完成。

参考文献

CMake: In which Order are Files parsed (Cache, Toolchain, …)? CMake GitLab Commit: Add support files for C, C++ and ASM for the IAR toolchain.

【讨论】:

我还需要设置CMAKE_C_COMPILER还是有其他方法?如果我这样做cmake .,它仍然会尝试使用gcc @nowox 您必须为 CMake 提供编译器的路径。您可以通过环境变量、工具链文件或 CMake 命令行中的直接定义来执行此操作(参见例如 here)。将其放入您的 CMakeLists.txt 会阻止您的项目跨平台。【参考方案5】:

您可以像这样拨打cmake

cmake -DCMAKE_C_COMPILER=iccarm ...

cmake -DCMAKE_CXX_COMPILER=...

【讨论】:

以上是关于如何在 CMake 中指定编译器?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 DPC++ 编译器选项中指定 C++ 标准版本?

cmake 在Windows 命令行怎么指定编译器

CMAKE怎么编译LAPACK

如何在 CMake 中指定链接类型?

如何在 pom.xml 文件中指定 Java 编译器版本?

如何在 pom.xml 文件中指定 Java 编译器版本?