传递编译器选项 cmake

Posted

技术标签:

【中文标题】传递编译器选项 cmake【英文标题】:Passing compiler options cmake 【发布时间】:2017-05-31 12:02:01 【问题描述】:

我知道如何使用 cmake 命令传递编译器选项

set(CMAKE_CXX_FLAGS "-Wall -Wno-dev -Wl,-rpath=/home/abcd/libs/")

还有什么方法可以从命令行传递选项,这将覆盖 CMakeList.txt 选项,例如 -

cmake -Wl,-rpath=/home/abcd/newlibs/ path/to/CMakeLists.txt

cmake -D CMAKE_CXX_FLAGS="-Wno-dev -Wl,-rpath=/home/abcd/libs/" path/to/CMakeLists.txt

我的主要问题是我想知道如何附加标志以及如何从命令行覆盖现有的编译器标志。

【问题讨论】:

-Wno-dev 是一个CMake 选项-Wall 是一个编译选项-Wl 开始链接选项。它们的传递方式不同。虽然 编译选项链接器选项 有一些共同点,但 CMake 选项 与它们无关。 【参考方案1】:

是的,您可以附加编译器和链接器选项。但是在 CMake 中您必须区分两件事:第一次调用生成构建环境,以及在更改 CMakeList.txt 文件或依赖项后重新生成该构建环境的所有连续调用。

以下是一些可能性(不包括更复杂的toolchain 变体):

附加编译器标志

    缓存的CMAKE_CXX_FLAGS 变量的初始内容是由CMake 在操作系统/工具链检测期间设置的CMAKE_CXX_FLAGS_INITCXXFLAGS 环境变量中设置的任何内容的组合。所以你可以先调用:

    cmake -E env CXXFLAGS="-Wall" cmake ..
    

    以后的 CMake 会期望用户直接修改 CMAKE_CXX_FLAGS 缓存的变量来附加一些东西,例如通过使用像 ccmake 这样的编辑器和 CMake 提交。

    您可以轻松引入自己的构建类型,例如 ALL_WARNINGS。附加了构建类型的特定部分:

     cmake -DCMAKE_CXX_FLAGS_ALL_WARNINGS:STRING="-Wall" -DCMAKE_BUILD_TYPE=ALL_WARNINGS ..
    

附加链接器标志

链接器选项或多或少等同于编译器选项。只是 CMake 的变量名称取决于目标类型(EXESHAREDMODULE)。

    CMAKE_EXE_LINKER_FLAGS_INITCMAKE_SHARED_LINKER_FLAGS_INITCMAKE_MODULE_LINKER_FLAGS_INIT 与环境变量 LDFLAGS 结合到 CMAKE_EXE_LINKER_FLAGSCMAKE_SHARED_LINKER_FLAGSCMAKE_MODULE_LINKER_FLAGS

    所以你可以调用:

    cmake -E env LDFLAGS="-rpath=/home/abcd/libs/" cmake ..
    

    见上文。

    附加了构建类型的特定部分:

    cmake -DCMAKE_SHARED_LINKER_FLAGS_MY_RPATH:STRING="-rpath=/home/abcd/libs/" -DCMAKE_BUILD_TYPE=MY_RPATH ..
    

替代品

请注意,CMake 确实提供了特殊变量来以独立于平台的方式设置编译器/链接器标志。所以你不需要知道具体的编译器/链接器选项。

这里有一些例子:

CMAKE_CXX_STANDARD CMAKE_POSITION_INDEPENDENT_CODE CMAKE_BUILD_RPATH CMAKE_INSTALL_RPATH_USE_LINK_PATH

很遗憾,编译器的警告级别没有(yet)

参考文献

Change default value of CMAKE_CXX_FLAGS_DEBUG and friends in CMake How to set warning level in CMake?

【讨论】:

不幸的是,cmake -E env CXXFLAGS="..." .. 的方法在 Windows 上不起作用 - 即使在使用管理权限运行该工具时也会显示错误“访问被拒绝”。【参考方案2】:

我的回答旨在证明一件事:

CMAKE_C_FLAGSCMAKE_CXX_FLAGS 等命令行选项始终追加且永不覆盖。

它来了。

准备文件夹hello_world下的文件

你好.c

#include <stdio.h>


int main(int argc, char* argv[]) 
    printf("Hello World!\n");
#ifdef DEFINED_IN_CMAKELISTS
    printf("You are here because you defined DEFINED_IN_CMAKELISTS in CMakeLists and it is not overwritten.\n");
#else
    printf("You are here because CLI CMAKE_C_FLAGS overwrote DEFINED_IN_CMAKELISTS, or you have NOT defined DEFINED_IN_CMAKELISTS.\n");
#endif 
#ifdef DEFINED_IN_CLI
    printf("You are here because you defined DEFINED_IN_CLI when running cmake -DCMAKE_C_FLAGS.\n");
#else
    printf("You are here because you have NOT defined DEFINED_IN_CLI when running cmake -DCMAKE_C_FLAGS.\n");
#endif // #ifdef DEFINED_IN_CLI
    return 0;


CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1 FATAL_ERROR)
project(Hello)

set(HELLO_SRCS Hello.c)

add_executable(Hello $HELLO_SRCS)

set(CMAKE_C_FLAGS "$CMAKE_C_FLAGS -DDEFINED_IN_CMAKELISTS")

生成 CMake 文件

$ mkdir _build && cd _build && cmake ..
-- The C compiler identification is AppleClang 11.0.3.11030032
-- The CXX compiler identification is AppleClang 11.0.3.11030032
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/me/Desktop/_dev/playground/cmake/hello_world/_build

制作并运行

$ make
Scanning dependencies of target Hello
[ 50%] Building C object CMakeFiles/Hello.dir/Hello.c.o
[100%] Linking C executable Hello
[100%] Built target Hello
$ ./Hello
Hello World!
You are here because you defined DEFINED_IN_CMAKELISTS in CMakeLists and it is not overwritten.
You are here because you have NOT defined DEFINED_IN_CLI when running cmake -DCMAKE_C_FLAGS.

从命令行定义新的编译器选项

$ cmake -DCMAKE_C_FLAGS="-DDEFINED_IN_CLI" ..
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/me/Desktop/_dev/playground/cmake/hello_world/_build

制作并运行

$ make
[ 50%] Building C object CMakeFiles/Hello.dir/Hello.c.o
[100%] Linking C executable Hello
[100%] Built target Hello
$ ./Hello 
Hello World!
You are here because you defined DEFINED_IN_CMAKELISTS in CMakeLists and it is not overwritten.
You are here because you defined DEFINED_IN_CLI when running cmake -DCMAKE_C_FLAGS.

结论

从上面的测试中,你可以看到即使没有使用类似的硬附加

-DCMAKE_C_FLAGS="$CMAKE_C_FLAGS -DDEFINED_IN_CLI"

,CMake 仍将 CLI 选项附加到 CMakeLists.txt 中已有的内容。

【讨论】:

超级答案。这个应该被评为#1。 实验有部分误导!在我的环境(Windows 10、CMake 3.21.4、VS2019)中查看CMakeCache.txt 时,默认标志为CMAKE_C_FLAGS:STRING=/DWIN32 /D_WINDOWS /W3,而当指定命令行选项时,这些标志变为CMAKE_C_FLAGS:STRING=-DDEFINED_IN_CLI,这是完全不同的故事。 【参考方案3】:
cmake -D CMAKE_CXX_FLAGS="-Wno-dev -Wl,-rpath=/home/abcd/libs/" path/to/CMakeLists.txt

这应该可以工作,问题是如果你find_package() 某些包也更改了CMAKE_CXX_FLAGS,那么它不仅会部分工作。

【讨论】:

好吧,我猜这也是为了覆盖。但是如何将选项附加到现有选项。这里“=”不起作用。 对不起,我不知道如何通过命令行附加变量。 MAYBE CMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS NewFlag" 将从命令行工作。 这应该不会起作用,因为可能 shell 会将 $SOMETOKEN 解释为 shell 变量的 shell 扩展。然而,单引号可能有效,尚未测试。【参考方案4】:

也许这会起作用 -

cmake -DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS) -DYOUR_CUSTOM_DEFINE=1" <rest of original cmake cmdline>

就像上面提到的 Tomaz。 -m

【讨论】:

不鼓励仅使用代码回答。请添加一些解释,说明这是如何解决问题的,或者这与现有答案有何不同。 From Review 语法稍有不同,使用 () 而不是上面显示的 。我进行了测试以验证它是否正常工作。此方法将指定的内容添加到现有的 CXX_FLAGS 中,并且不会覆盖它。【参考方案5】:

这里的大多数答案都是有效的,但我也偶然发现了如何通过 CMAKE_CXX_FLAGS 并添加包含空间的包含目录(Windows)。

显然,如果您从命令行运行该参数 - 您需要格外小心引用(另请参阅 here)

cmake ... -DCMAKE_CXX_FLAGS="-fms-compatibility-version=19.00 --target=i686--windows -X -I """C:\Program Files (x86)\Windows Kits\10\Include\10.0.18362.0\um""" "

因此,如果包含路径包含空格,并且需要引用,但您还需要引用 CMAKE_CXX_FLAGS,它以单引号字符 (") 开头的引号结束,并且无论何时需要引号 - 您而是放置三个引号字符。 (""")

这总体上有点奇怪。花了一段时间才弄清楚。

【讨论】:

【参考方案6】:

我只是使用 $ENV() 运算符来获取环境变量,例如在 CMakeLists.txt 中:

add_compile_options($ENVMY_CXXFLAG)

唯一的问题是 $ENV() 只能在配置阶段读取,因此 cmake 看不到当前构建阶段的环境设置。但是重新配置是由更改的 cmake 文件触发的,所以我只使用 touch 来模拟更改。下面是一个命令行示例:

touch CMakeLists.txt && MY_CXXFLAG="-D DEBUG" cmake --build build --config Debug

或您使用的其他选项。对于这个简单的示例,环境变量的标志字符串仍然存在一些怪癖,例如不止一种选择。但是在CMakeLists.txt中进行字符串处理来美化这一点应该不是什么大问题。

【讨论】:

以上是关于传递编译器选项 cmake的主要内容,如果未能解决你的问题,请参考以下文章

CMake传递的变量编译器无法编译简单的程序

CMake CheckCXXCompilerFlag用法(CMake set()函数CMake set函数)(-std=gnu++14`编译选项)

CMake 默认编译链接选项

C - CMAKE

cmake常用编译选项

使用多个 -DCMAKE_CXX_FLAGS 选项编译 CMake