【问题标题】:cmake - Global linker flag setting (for all targets in directory)cmake - 全局链接器标志设置(用于目录中的所有目标)
【发布时间】:2015-09-21 15:05:11
【问题描述】:

我想将链接器标志传递给我项目中的所有子项目(子目录 CMakeList)。

在切换到新的 cmake 3.3 之前,我使用了以下运行良好的代码 (cmake 3.2),为编译和链接添加了标志:

set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -stdlibc++")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -stdlibc++")

在 cmake 3.3 中,这不再有效,并且仅为编译步骤设置标志。我更新了 CMakeList 以使用更“现代”的 cmake 语法:

set(MY_DEBUG_OPTIONS -g -stdlib=libstdc++ -Wfatal-errors)
set(MY_RELEASE_OPTIONS -O3 -stdlib=libstdc++ -Wfatal-errors)

add_compile_options(
  "$<$<CONFIG:DEBUG>:${MY_DEBUG_OPTIONS}>"
  "$<$<CONFIG:RELEASE>:${MY_RELEASE_OPTIONS}>")

这为所有子项目设置编译标志,是否有类似的方法为链接器标志执行此操作?我知道可以使用target_link_librariescommand 在目标基础上添加链接器标志,但找不到其他任何东西。

我尝试使用 CMAKE_SHARED_LINKER_FLAGS(以及 exe、模块等对应的 var)变量但没有成功。

更新:

事实证明,这与 cmake 版本无关,除了第一个 make 命令外,CMAKE_CXX_FLAGS_XXXvariables 可以正常工作。如果第二次运行make(在 CmakeList 中进行了修改),则会出现标志。

我想我在使用简单的 CMakeList 进行测试时找到了一个解决方案:如果在 project 命令之后声明了标志,它就会按预期工作。我不知道这是 cmake 本身的要求还是只是一种奇怪的行为。

cmake_minimum_required (VERSION 3.2)

set(PROJECT Test_Project)

# Not working (on first run)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -stdlib=libstdc++ -Wfatal-errors")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -stdlib=libstdc++ -Wfatal-errors")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -stdlib=libstdc++ -Wfatal-errors")

project(${PROJECT})

# Declare here instead...

add_executable(Test test.cpp)

MESSAGE( STATUS "Config flags : " ${CMAKE_CXX_FLAGS_RELEASE})

使用:

cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release .

【问题讨论】:

  • 我想知道为什么您的第一种方法应该停止使用 CMake 3.3。所以我检查了CMakeCXXInformation.cmake中的CMAKE_CXX_LINK_EXECUTABLE和CMAKE_CXX_CREATE_SHARED_LIBRARY之类的代码更改。但是没有什么明显的,所以你能否在你的目标 make 环境中添加一些细节?看起来像GNU,但是你用的是什么版本/口味/操作系统?
  • 你是对的,我错了,cmake 3.2 也有问题。我做了一个非常简单的“Hello world”项目,问题是:我第一次在cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release . 之后运行make,除了cmake 默认标志(例如-O3、-DNDEBUG 用于发布构建)之外没有其他标志。然后,如果我更新 CMakeList 文件(例如,在标志字符串中添加一个空格),cmake 现在会正确添加所有标志。 (在带有 xcode 工具链的 os x yosemite 上)
  • 好的,那么这与CMake cross-compiling: C flags from toolchain file ignored 的问题相同。有关一些背景信息,请参阅my answer there。简而言之,只需将变量 set() 命令放在 project() 命令之后即可。
  • 是的,这就是我最终要做的。感谢您提供背景信息!
  • 不客气。我添加了一个答案来涵盖调查结果、示例代码和背景信息。

标签: c++ linker cmake


【解决方案1】:

您的问题与特定的 CMake 版本无关。

CMake 中的所有链接器/编译器标志变量都是一样的。因为这些变量是缓存变量并使用project()/enable_language() 命令设置(详情参见here),您要么必须

  1. 在project() 命令之前用set(... CACHE ...) 预填充缓存
  2. 一般使用set(... CACHE ... FORCE)强制/覆盖
  3. 将set() 移动到project() 命令之后以隐藏或附加到缓存的变量

以下是CMAKE_EXE_LINKER_FLAGS 的示例,显示了所有三个变体:

CMakeLists.txt

cmake_minimum_required(VERSION 2.8)

# 1. prefill
#set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map" CACHE INTERNAL "")

project(Test_Project CXX)

# 2. force
set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map" CACHE INTERNAL "" FORCE)

# 3. hide
#set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map")
# 3. or append
#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=output.map")

# TODO: Remove, this is just for testing
file(WRITE "foo.cpp" "int main() {}") 

add_executable(${PROJECT_NAME} foo.cpp)

无论这些变量的值在您的任何给定CMakeLists.txt 文件的末尾,都将作为默认值应用于同一CMakeLists.txt 文件中的所有相应目标(请参阅CMAKE - setting compile flags for libraries 和What's the CMake syntax to set and use variables?)。

第一个变体的缺点是它实际上只是初始值。第二个和第三个变体很可能需要一个if (CMAKE_COMPILER_IS_GNUCXX),所以我更喜欢第二个变体,将这些设置移动到它自己的初始缓存文件中:

MyGNUSettings.cmake

set(CMAKE_CXX_FLAGS "-stdlib=libstdc++ -Wfatal-errors" CACHE INTERNAL "" FORCE)
set(CMAKE_CXX_FLAGS_DEBUG "-g" CACHE INTERNAL "" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE "-O3" CACHE INTERNAL "" FORCE)
set(CMAKE_EXE_LINKER_FLAGS "-Wl,-Map=output.map" CACHE INTERNAL "" FORCE)

使用例如

cmake -G "Unix Makefiles" -C MyGNUSettings.cmake -DCMAKE_BUILD_TYPE=Release  .

是的 - 对于全局和每个编译器设置 - 我更喜欢全局缓存变量而不是 add_compile_options() 命令。我认为add_compile_options() 没有替换全局变量,主要是为了防止人们将编译器选项放在add_definitions() 命令中。

【讨论】:

  • 谢谢,很好的解释,我更新了我的 CMakeList 以考虑到这一点。不确定我是否应该更新问题标题。
  • 也许只是从标题中删除“CMake 3.3”部分?
  • 我不认为工具链文件应该(ab)用于设置可能应该进入某些 CMakeLists.txt 文件的此类标志。请参阅cmake.org/cmake/help/v3.10/manual/cmake-toolchains.7.html,其中工具链文件的用途仅针对交叉编译场景进行描述,设置诸如CMAKE_SYSTEM_NAME、CMAKE_C_COMPILER 等。
  • @letmaik 工具链文件不仅用于交叉编译场景。它可以添加对 CMake 不直接支持/识别的所有编译器工具链的支持。通过添加CMAKE_SYSTEM_NAME 来定义交叉编译。但你是对的,我更新了我的答案,在这种情况下推荐初始缓存文件而不是工具链文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-23
  • 2023-01-25
相关资源
最近更新 更多