传递编译器选项 cmake

     2023-02-17     132

关键词:

【中文标题】传递编译器选项 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默认编译和链接的参数设置CMakeLists.txt文件内容:cmake_minimum_required(VERSION3.2)message(STATUS"CMAKE_C_FLAGS="${CMAKE_C_FLAGS})message(STATUS"CMAKE_C_FLAGS_DEBUG="${CMAKE_C_FLAGS_DEBUG})message(STATUS"CMAKE_C 查看详情

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

】CMake传递的变量编译器无法编译简单的程序【英文标题】:CMakePassedvariablescompilerisnotabletocompileasimpleprogram【发布时间】:2017-07-2821:24:10【问题描述】:我正在尝试使用CMake交叉编译应用程序。当我对交叉编译器的路径进行硬编... 查看详情

cmake构建类型和编译选项

https://hijk.tech/cmake-tutorial/05/ 查看详情

cmake常用编译选项(代码片段)

1、openmp加载,cmake3.9之后内置了openmpfind_package(OpenMP)if(OPENMP_FOUNDOROpenMP_CXX_FOUND)  set(CMAKE_C_FLAGS"$CMAKE_C_FLAGS$OpenMP_C_FLAGS")set(CMAKE_CXX_FLAGS"$CMAKE_CXX_FLAGS$OpenMP_CXX_FLAGS")se 查看详情

使用多个 -DCMAKE_CXX_FLAGS 选项编译 CMake

】使用多个-DCMAKE_CXX_FLAGS选项编译CMake【英文标题】:compilingCMakewithmultiple-DCMAKE_CXX_FLAGSoptions【发布时间】:2016-01-2005:51:48【问题描述】:我正在用一些默认选项编译CMake,第一个是-DCMAKE_CXX_FLAGS=-std=c++11。使用CMake的其他编译也抱... 查看详情

在 cmake 中将目标文件名作为编译定义传递

】在cmake中将目标文件名作为编译定义传递【英文标题】:Passtargetfilenameascompiledefinitionincmake【发布时间】:2014-12-0815:03:34【问题描述】:我有许多目标的CMakeLists.txt,并且目标定义了特定于配置的后缀。另外我想知道程序中可执... 查看详情

cmake中添加-fpic编译选项方法

合并openjpeg/soxr/vidstab/snappy等多个cmake库时,为了解决下述问题:relocationR_X86_64_32against`.text‘cannotbeusedwhenmakingasharedobject;recompilewith-fPIC分别验证过以下二种方法第一种(笔者所采用的,因需修改原始CMakeLists.txt文件,感觉不太方便... 查看详情

cmake基础教程(17)add_compile_options添加编译选项(-g-werror)(代码片段)

...别的:add_compile_options命令添加的编译选项是针对所有编译器的(包括c和c++编译器),而set命令设置CMAKE_C_FLAGS或CMAKE_CXX_FLAGS变量则是分别只针对c和c++编译器的。例如下面的代码判断编译器类型,如果是gcc编译器,... 查看详情

4.cmake系列-项目添加编译选项(代码片段)

目录1.项目目录结构2.相关代码2.1add模块2.2sub模块2.3example模块2.4顶层CMakeLists.txt3.配置&编译1.项目目录结构test3├──add│??├──add.c│??├──add.h│??└──CMakeLists.txt├──build├──CMakeLists.txt├──config.h.in├──example... 查看详情

cmake库依赖关系的传递

...其实它的原型是:可以通过PRIVATE|PUBLIC|INTERFACE设置依赖的传递性.摘抄一下官方文档的描述:其实大白话就是:好了,大家以后再使用target_link_libraries()的时候就可以加上PRIVATE关键字,这样C就不会链接A了。需要注意:根据CMP0023... 查看详情

cmake指定自己安装的g++或gcc编译器

Linux系统下。有时候有自己安装的编译器和系统安全编译器,而在Cmake生成对应Makefile时,往往倾向于用系统装的g++或gcc不用自己安装的编译器。解决办法是,使用CMake中的选项指定自己安装的编译器即可。具体... 查看详情

cmake指定自己安装的g++或gcc编译器

Linux系统下。有时候有自己安装的编译器和系统安全编译器,而在Cmake生成对应Makefile时,往往倾向于用系统装的g++或gcc不用自己安装的编译器。解决办法是,使用CMake中的选项指定自己安装的编译器即可。具体... 查看详情

cmake指定自己安装的g++或gcc编译器

Linux系统下。有时候有自己安装的编译器和系统安全编译器,而在Cmake生成对应Makefile时,往往倾向于用系统装的g++或gcc不用自己安装的编译器。解决办法是,使用CMake中的选项指定自己安装的编译器即可。具体... 查看详情

CMAKE 使用环境变量而不将它们作为命令行参数传递?

...我在RHEL5上使用模块,并在我的机器上安装了各种版本的编译器/binutils。因此,我最终定义了指向我的工具的环境变量并相应地更新了路径,因此RHEL5附带的旧工具不 查看详情

如何在子项目中忽略 CMake 编译器定义

】如何在子项目中忽略CMake编译器定义【英文标题】:HowtoignoreCMakeCompilerDefinitionsinsubprojects【发布时间】:2018-05-0221:07:08【问题描述】:我有一个包含多个第三方库的主项目。我刚刚添加了一个新的第3方项目。我面临的问题是新... 查看详情

在linux上交叉编译opencv踩过的坑

...出配置窗口,选最后一个,然后next。3、输入自己的交叉编译器路径,第三方库路径,finish4、等一会,cmake会出现编译选项,自行修改我也不太清楚这里面每一个组件的具体用途,就根据网上别人给出的选项作了修改找到BUILD_ZLIB... 查看详情

在 CMake 项目中动态更改编译器标志

】在CMake项目中动态更改编译器标志【英文标题】:ChangingcompilerflagsontheflyinaCMakeproject【发布时间】:2013-11-2821:01:30【问题描述】:我有一个大型cmake项目,目前完全是为生产而构建的;默认的gcc标志选项类似于-fpic-s-O3。用不同... 查看详情

如何确定可以传递给编译器选项的最小值和最大值?

】如何确定可以传递给编译器选项的最小值和最大值?【英文标题】:HowcanIdeterminetheminandmaxvaluethatIcanpasstoacompileroption?【发布时间】:2016-08-1113:17:03【问题描述】:有没有办法确定我可以传递给编译器选项的最小值和最大值。例... 查看详情