CMake中的set_target_properties是否会覆盖CMAKE_CXX_FLAGS?

70

在我的CMake项目开始时,我会将通用编译标志设置在变量CMAKE_CXX_FLAGS中,如下所示:

set(CMAKE_CXX_FLAGS "-W -Wall ${CMAKE_CXX_FLAGS}")

接下来,我需要添加额外的特定于配置的编译标志(存储在BUILD_FLAGS中)。我可以使用以下命令来实现吗:

set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})

还是我必须手动添加CMAKE_CXX_FLAGS:

set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BUILD_FLAGS}")

如何防止BUILD_FLAGS 覆盖 CMAKE_CXX_FLAGS?


2
我相信它们被附加到了CMAKE_CXX_FLAGS,你可以通过调用详细的make文件“make target VERBOSE=1”来验证这一点。 - Ramon Zarazua B.
2个回答

72

自2013年以来,被接受的答案仍在使用,但已过时。
该答案基于CMake v2.8.12、v3.3和v3.13的新功能。

自CMake-2.8.12(2013)以来

有两个新命令用于设置CMAKE_CXX_FLAGS

cmake-2.8.12以来,最新版本的文档没有太多变化:

在您的情况下,您可以使用:

target_compile_options(${TARGET} PRIVATE ${BUILD_FLAGS})

或者,如果你只有一个目标:

add_compile_options(${BUILD_FLAGS})

更多例子

target_compile_options(mylib PRIVATE   -O2) # only internal
target_compile_options(mylib INTERFACE -gl) # only external
target_compile_options(mylib PUBLIC    -g)  # same as PRIVATE + INTERFACE

# multiple targets and flags
target_compile_options(mylib1 mylib2 PRIVATE -Wall -Wextra)

target_compile_options(    mylib PUBLIC -DUSEXX)  # Bad
target_compile_definitions(mylib PUBLIC -DUSEXX)  # OK

add_compile_options(-Wall -Wextra) # for all targets in current directory
add_compile_options(-DUSEXX)       # Bad
add_definitions(-DUSEXX)           # OK

弃用的COMPILE_FLAGS

cmake-3.0文档COMPILE_FLAGS标记为已弃用:

COMPILE_FLAGS

编译此目标源时使用的附加标志。

COMPILE_FLAGS属性设置了在目标内部构建源时使用的额外编译器标志。 使用COMPILE_DEFINITIONS传递其他预处理器定义。

此属性已弃用。请改用COMPILE_OPTIONS属性或target_compile_options命令。

如果您仍然想使用set_target_properties(),可以使用COMPILE_OPTIONS代替COMPILE_FLAGS

set_target_properties(${TARGET} PROPERTIES COMPILE_OPTIONS ${BUILD_FLAGS})

自 CMake-3.3 (2015) 起

Anton Petrov 建议使用 生成器表达式,正如 ar31 的回答中所介绍的。

CMake 的 生成器表达式 可以将你的 ${BUILD_FLAGS} 应用于:

  • 使用 $<COMPILE_LANGUAGE:CXX>(也可以是 CCUDA 等)的 C++ 语言
  • 使用 $<CXX_COMPILER_ID:Clang> 的 Clang 编译器
    (也可以是 gccGNU 或 Visual C++ 的 MSVC 等,请参见完整列表
    (如果语言为 C,请改用 $<C_COMPILER_ID:Clang>
  • 以及更多的 支持的 C++ 特性编译器版本...(请参见文档

在你的情况下,你可以使用:

target_compile_options(${TARGET} PRIVATE
          $<$<COMPILE_LANGUAGE:CXX>:${BUILD_FLAGS_FOR_CXX}>
          $<$<COMPILE_LANGUAGE:C>:${BUILD_FLAGS_FOR_C}>)

或者是关于编译器:

target_compile_options(${TARGET} PRIVATE
          $<$<CXX_COMPILER_ID:Clang>:${BUILD_FLAGS_FOR_CLANG}>
          $<$<CXX_COMPILER_ID:GNU>:${BUILD_FLAGS_FOR_GCC}>
          $<$<CXX_COMPILER_ID:MSVC>:${BUILD_FLAGS_FOR_VISUAL}>)

自CMake-3.13 (2018)以来

一个新的函数target_link_options()允许向链接器传递选项,正如Craig Scott所提到的。

C和C++文件使用不同的选项

最好的方法是区分C文件和C++文件,使用两个不同的目标。


1
如果您有混合目标怎么办?例如C和C++。如何仅为C目标设置选项? - Martin
嗨@Martin。我不知道有没有一种目标可以混合使用C和C++文件,并针对每种源文件使用不同的选项。我建议将此目标拆分为两个:一个用于C源代码,另一个用于C ++。...好的,我开始在我的答案中添加一个部分,以提出解决这种复杂情况的方法... - oHo
1
为什么我不能像使用 LINK_FLAGS 一样使用 set_target_properties() 函数?它似乎永远不会接受多个标志(即使是以列表形式)。 - Royi
1
@olibre 请查看此答案 https://dev59.com/cmUp5IYBdhLWcg3wtZPt#21561742 以获取特定语言选项。正确的方法是使用生成器表达式。 - Anton Petrov
1
$<$<COMPILE_LANGUAGE:C>:${BUILD_FLAGS_FOR_CXX}> is probably a mistake, it should rather be $<$<COMPILE_LANGUAGE:C>:${BUILD_FLAGS_FOR_C}> - Adam Romanek
显示剩余8条评论

61

使用第一个:

set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS ${BUILD_FLAGS})
BUILD_FLAGS 中存储的标志会在编译 TARGET 的源代码时附加到 CMAKE_CXX_FLAGS 后面。虽然文档中有提示,但我只是试了一下来确保它的有效性。

COMPILE_FLAGS

   Additional flags to use when compiling this target's sources. 
   
   The COMPILE_FLAGS property sets additional compiler flags used to
   build sources within the target.  Use COMPILE_DEFINITIONS to
   pass additional preprocessor definitions.
完整的命令行将相当于:
${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${COMPILE_FLAGS} -o foo.o -c foo.cc

正如 Ramon 所说,您始终可以使用 make VERBOSE=1 进行检查。


1
你说得对,非常感谢你(还有Ramon)。我之前也不知道VERBOSE参数,现在学习CMake实际处理我的命令就容易多了。 - Milan Hanus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接