传递编译器选项 cmake

我知道如何使用 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

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

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

这应该工作,问题是,如果你 find_package()的一些包,也改变了 CMAKE_CXX_FLAGS,那么它将不仅部分工作。

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

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

附加编译器标志

  1. 缓存的 CMAKE_CXX_FLAGS变量的初始内容是由 CMake 自己在操作系统/工具链检测期间设置的 CMAKE_CXX_FLAGS_INIT和在 CXXFLAGS环境变量中设置的任何内容的组合。所以你可以先打电话给:

    cmake -E env CXXFLAGS="-Wall" cmake ..
    
  2. Later CMake would expect that the user modifies the CMAKE_CXX_FLAGS cached variable directly to append things e.g. by using an editor like ccmake commit with CMake.

  3. You can easily introduce your own build type like ALL_WARNINGS. The build type specific parts are appended:

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

Append Linker Flags

The linker options are more or less equivalent to the compiler options. Just that CMake's variable names depend on the target type (EXE, SHARED or MODULE).

  1. The CMAKE_EXE_LINKER_FLAGS_INIT, CMAKE_SHARED_LINKER_FLAGS_INIT or CMAKE_MODULE_LINKER_FLAGS_INIT do combine with the evironment variable LDFLAGS to CMAKE_EXE_LINKER_FLAGS, CMAKE_SHARED_LINKER_FLAGS and CMAKE_MODULE_LINKER_FLAGS.

    So you can e.g call:

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

  3. Build type specific parts are appended:

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

Alternatives

Just be aware that CMake does provide special variable to set complier/linker flags in a platform independent way. So you don't need to know the specific compiler/linker option.

Here are some examples:

Unfortunately there is none for the compiler's warning level (yet)

References

也许这能行

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

就像上面提到的 Tomaz。 嗯

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

CMAKE_C_FLAGSCMAKE_CXX_FLAGS这样的命令行选项总是附加并且从不覆盖。

来了。

准备文件夹 hello_world下的文件

你好

#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中已有的选项。

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

显然,如果您从命令行运行该参数-您需要格外小心引号(另见 给你)

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""" "

因此,如果 include path 包含空格,并且需要引号,但是您还需要引号 CMAKE_CXX_FLAGS,最后以单引号字符(")开始引号,并且当您需要引号时,您需要放置三个引号字符。(""")

总的来说有点奇怪,花了点时间才弄明白。

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

add_compile_options($ENV{MY_CXXFLAG})

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

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

或者你还有什么其他选择。在这个简单的例子中,环境变量的标志字符串仍然存在一些问题,例如不止一个选项。但是在 CMakeLists.txt 中使用字符串处理来美化它应该不是什么大问题。