在现代CMake中定义预处理器

6

我目前正在学习CMake,由于在CMake中通常有两种方法可供选择(旧方式和现代方式),因此不想养成坏习惯。

阅读了一些关于CMake预处理器的文档,并查看了以下帖子:Define preprocessor macro through cmake

我得出结论,我可以定义一个预处理器,并使用以下任一选项:

  • add_compile_definitions(FOO)
  • target_compile_definitions(myTarget PRIVATE FOO)
  • add_definitions(-DFOO)

经过一些测试,它们都能正常工作并定义FOO

但我的问题是,我应该使用哪个最“现代”的方式,每个函数之间真正的区别是什么?我注意到唯一的区别是,如果我使用target_compile_definitions(myTarget PUBLIC FOO),那么它会将FOO定义在父目标中。

2个回答

8

现代 CMake 的一般趋势是从全局设置转向目标为中心的设置。仅基于这个规则,target_compile_definitions() 是最现代的方法。它还允许控制设置是否仅用于目标本身(PRIVATE),在使用此目标的其他目标中(INTERFACE),或同时用于两者(PUBLIC)。在内部,它通过修改目标的属性 COMPILE_DEFINITIONSINTERFACE_COMPILE_DEFINITIONS 来工作。

在现代程度上稍次的是 add_compile_definitions()。它将宏定义添加到当前目录和子目录中定义的所有目标;在这方面,它的范围类似于 include_directories()。在内部,它通过修改当前目录的 COMPILE_DEFINITIONS 属性来工作。所以:它仍然使用了正确的“现代”机制,但是是面向目录而不是面向目标的。

在列表底部,我们有非常古老的函数 add_definitions()。在现代 CMake 中,最好避免使用它。虽然旨在指定预处理器定义(因此其名称),但实际上它允许传递任意编译器选项(这也是为什么需要指定 -DFOO 而不仅仅是 FOO 作为其参数的原因)。它试图确定传递的内容是否实际上是预处理器宏定义,如果是,则将它们移动到目录的 COMPILE_DEFINITIONS 属性中。如果它们没有被识别为这样的(对于具有复杂替换字符串的宏可能会发生),则它们将留在标志列表中。


3

确实,target_compile_definitions 是添加预处理宏的最合适方式。

target_compile_definitions(myTarget PUBLIC FOO)的原因也是你应该使用它的原因之一,因为你可以正确地将其定义为每个目标而不是每个文件夹。现在,您可以将这些定义附加到目标上,以便依赖项也声明它们。如果您尝试从不同的文件夹创建目标,则会更清楚地看到此行为,并且实际上比先前非常不可靠的行为更有意义。

例如,在Windows上,所有通常的“exports”宏都应该用这种方式声明,并且是PRIVATE,以便它们不会被传播,因为它们真正是私有定义。


你如何使用 target_compile_definitions 添加类似于 #define VER 3.21 的内容? - Royi
1
target_compile_definitions( myTarget PUBLIC VER=3.21) 应该可以解决问题。 - Matthieu Brucher

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