CMake提供了多种机制来将标志传递给编译器:
在现代用法中,有一种方法优于其他方法吗?如果是这样,为什么?此外,如何将此方法与多个配置系统(例如MSVC)一起使用?
CMake提供了多种机制来将标志传递给编译器:
在现代用法中,有一种方法优于其他方法吗?如果是这样,为什么?此外,如何将此方法与多个配置系统(例如MSVC)一起使用?
对于现代CMake(版本2.8.12及以上),您应该使用内部使用目标属性的target_compile_options
。
CMAKE_<LANG>_FLAGS
是全局变量,最容易出错。它还不支持生成器表达式,而这些表达式非常方便。
add_compile_options
基于目录属性,在某些情况下很好,但通常不是指定选项的最自然方式。
target_compile_options
基于每个目标(通过设置COMPILE_OPTIONS
和INTERFACE_COMPILE_OPTIONS
目标属性),这通常会产生最清晰的CMake代码,因为源文件的编译选项由其所属的项目(而不是硬盘上所在的目录)确定。这具有额外的优点,即如果需要,它会自动处理传递的使用要求到相关目标。
虽然它们有点冗长,但基于每个目标的命令允许在不同的构建选项上进行合理的精细控制,并且(根据我的个人经验)最不可能在长期运行中引起头痛问题。
理论上,您也可以直接使用set_target_properties
设置相应的属性,但target_compile_options
通常更易读。
例如,要使用生成器表达式为名为foo
的目标设置编译选项,可以编写:
target_compile_options(foo PUBLIC "$<$<CONFIG:DEBUG>:${MY_DEBUG_OPTIONS}>")
target_compile_options(foo PUBLIC "$<$<CONFIG:RELEASE>:${MY_RELEASE_OPTIONS}>")
PUBLIC
、PRIVATE
和 INTERFACE
这几个关键字定义了选项的作用域,详见文档。例如,如果我们用 target_link_libraries(bar foo)
将 foo
链接到 bar
:
PRIVATE
选项只应用于目标本身(foo
),而不应用于其他链接到它的库(消费者)。INTERFACE
选项只应用于消费目标 bar
PUBLIC
选项将应用于原始目标 foo
和消费目标 bar
PUBLIC
在 target_compile_options
中的作用是将编译选项传递给当前目标及其依赖项。 - Ramana ReddyPUBLIC
关键字的额外解释。 - Stefan ProfanterMY_DEBUG_OPTIONS
包含空格,则需要使用 SHELL:
前缀,例如:target_compile_options(${NAME} PUBLIC $<$<CONFIG:DEBUG>:SHELL:${MY_DEBUG_OPTIONS}>)
。否则,Cmake 将在您的编译器选项周围添加双引号,导致编译错误。 - Nathanael Weiss