预处理器定义不会从 CMake 传播到 Unix Makefile

Preprocessor definitions not propagating from CMake to Unix Makefiles

在编译 CMake 创建的 Makefile 时,我无法使用 -D 或 add_definitions() 显示传递给 CMake 的任何内容。

(用一个简单的例子总结)。

在顶层,我有一个 build.sh 脚本,它以:

开头
cmake \
    -G "Unix Makefiles" \
    -DPIZZA=1 \
    -DCMAKE_VERBOSE_MAKEFILE=1 \
    $TOPPINGS \
    ../../src

$TOPPINGS 之前声明为 -DTOPPINGS=ALL。我已经验证它已正确传递给上面的内容。基于 TOPPINGS 的值,我的 CmakeLists.txt 使用 add_definitions() 添加了更多预处理器定义。为了便于讨论,我们会说它确实如此:

add_definitions( -DCHEESE=Mozz ) 
add_definitions( -DMEAT=Meat ) 

这生成没有问题。在 CMakeCache.txt 他们出现:

//No help, variable specified on the command line.
CHEESE:UNINITIALIZED=Mozz

而且我已经使用 CMakeLists.txt 中的 message() 验证了我的逻辑。

但是当我们使用生成的 Makefile 进行构建时,这些都没有定义。既不是在调用 Cmake 时指定的,也不是通过 add_definitions.

添加的

在查看 add_definitions 的文档时,我看到:

Adds definitions to the compiler command line for sources in the current directory and below.

这是我问题的根源吗?即:仅为我运行 CMake 的目录添加定义,或者是否为 ../../src(及以下)中的所有内容添加定义,而问题出在其他地方?如果是这种情况,是否有办法手动指定这些定义应适用于 ../../src 及以下?

如@steveire 所述,SSCCE 会很有帮助。尽管如此,问题很有可能与您的 add_subdirectory 调用中的 order/location 有关 add_definitions 调用。


首先,明确一点,CMake 设置的变量与预处理器定义没有任何关系,除非您明确地将它们联系在一起。我的意思是如果你调用

cmake -DTOPPINGS=Haggis .

或者在你的 CMakeLists.txt 中有 set(TOPPINGS Haggis),预处理器不会看到任何 Haggis 除非你也有类似

的东西
add_definitions(-DTOPPINGS=${TOPPINGS})


好的,举个例子,考虑以下 CMakeLists.txt:

cmake_minimum_required(VERSION 3.1)
project(MyTest)
add_executable(MyTestExe main.cpp)
add_subdirectory(One)
add_definitions(-DTOPPINGS=Haggis)
add_subdirectory(Two)
target_link_libraries(MyTestExe One Two)

在这种情况下,子目录 "One" 的 CMakeLists.txt 中定义的目标 不会 TOPPINGS 作为 PP 定义,因为 add_subdirectory(One) 出现在 add_definitions 调用之前。如果 "One" 使用 add_definitions 设置任何 PP 定义,它们将不会传播回顶层或 "Two"。

但是,由于 add_subdirectory(Two) 在 调用 add_definitions 之后 出现,因此其中定义的所有目标(及其任何子目录) TOPPINGS 作为 PP 定义。

最后,目标 MyTestExe 也将具有 TOPPINGS 作为 PP 定义,无论 add_executable 调用与 add_definitions 调用相关。


使用 target_compile_definitions 而不是 add_definitions 可能会避免一些混淆。这为 PP 定义提供了更细粒度的控制;我们不想羊杂碎漏得到处都是!

假设我们从 CMakeLists.txt 中删除行 add_definitions(-DTOPPINGS=Haggis)。现在在子目录 "Two" 的 CMakeLists.txt 中,我们可以做:

add_library(Two two.hpp two.cpp)
# Note, we don't need to use -D here, but it doesn't matter if you do
target_compile_definitions(Two PUBLIC TOPPINGS=Haggis PRIVATE SIDE=Whisky)

这会导致 PP 定义 TOPPINGS SIDE 应用于单个目标库 Two,而不管其他目标库有多少我们可以在相同的 CMakeList.txt.

中定义目标

由于 TOPPINGS 被声明为 PUBLIC,它导致 CMake 将它应用到链接 Two 的任何其他目标。当我们调用 target_link_libraries(MyTestExe One Two) 时,我们在顶层 CMakeLists.txt 中这样做,因此 MyTestExe 也将 TOPPINGS 作为 PP 定义,但它不会 SIDE 因为那是 PRIVATETwo.