在现代 CMake 中定义预处理器

Defining preprocessor in modern CMake

我目前正在学习 CMake,不想养成坏习惯,因为在 CMake 中总是有两种方法可以做某事(我所见的旧方法和现代方法)

在阅读了一些关于 CMake 中的预处理器的文档并检查了这个 post 之后: Define preprocessor macro through cmake

我得出的结论是我可以将预处理器定义为:

经过一些测试后,它们实际上都按预期工作并定义 FOO

但现在我的问题是什么是我最应该使用的 "modern" 方式以及每个功能之间的真正区别是什么,我注意到的唯一区别是如果我使用 target_compile_definitions(myTarget PUBLIC FOO) 它然后在父目标中定义 FOO

现代 CMake 的总趋势是从全局设置转向以目标为中心的设置。仅根据此规则,target_compile_definitions() 是最现代的方法。它还允许控制设置是仅在目标中使用 (PRIVATE),在使用此目标的其他目标中使用 (INTERFACE),还是在两者中使用 (PUBLIC)。在内部,它通过修改目标的属性 COMPILE_DEFINITIONSINTERFACE_COMPILE_DEFINITIONS.

来工作

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

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

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

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

例如,在 Windows 上,所有常见的 "exports" 宏都应以这种方式声明,并且 PRIVATE 因此它们不会传播,因为它们实际上是私有定义。