在CMake中,设置通用编译标志的现代方法是什么?

13 浏览
0 Comments

在CMake中,设置通用编译标志的现代方法是什么?

CMake提供了多种机制来为编译器传递标志:

在现代使用中,是否有一种方法比其他方法更受欢迎?如果是的话,为什么?此外,如何将此方法与多个配置系统(如MSVC)一起使用?

0
0 Comments

现代CMake(版本2.8.12及以上)使用target_compile_options来设置通用编译标志,它在内部使用目标属性。CMAKE__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 "$<$:${MY_DEBUG_OPTIONS}>")
target_compile_options(foo PUBLIC "$<$:${MY_RELEASE_OPTIONS}>")

PUBLIC、PRIVATE和INTERFACE关键字定义了选项的作用域。例如,如果我们使用target_link_libraries将foo链接到bar:

- PRIVATE选项仅适用于目标自身(foo),而不适用于链接它的其他库(消费者)。

- INTERFACE选项仅适用于消费目标bar。

- PUBLIC选项将应用于原始目标foo和消费目标bar。

请注意,target_compile_options是增量操作,因此您可以修改最后一行代码来使其更易读。如果您希望全局使用相同的严格编译标志,最佳的现代方法是通过设置COMPILE_OPTIONS目录属性来初始化目标特定属性。对应属性的手册会告诉您如何设置。在编译选项的情况下,可以使用add_compile_options命令来设置它。需要这种方法的选项通常很少。关于target_compile_options中的PUBLIC关键字的用途,我在答案中添加了额外的解释。如果MY_DEBUG_OPTIONS包含空格,您需要在前面添加SHELL:前缀,例如:target_compile_options(${NAME} PUBLIC $<$:SHELL:${MY_DEBUG_OPTIONS}>)。否则,由于CMake将在双引号中包装编译器选项,您将会遇到编译错误。您能给答案添加一个示例吗?

0