CMake到Unix Makefiles中预处理器定义未传播

3
我遇到了一个问题,即在使用 -D 或 add_definitions() 传递任何内容给 CMake 时,CMake 创建的 Makefiles 编译时都没有显示出来。在顶层目录中,我有一个 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()验证了我的逻辑。

但是,当我们使用生成的Makefiles构建时,这些未被定义。无论是在调用Cmake时指定的还是通过add_definitions添加的都不行。

查看add_definitions的文档,我发现:

为当前目录及其子目录中的源文件添加编译器命令行定义。

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

1个回答

12
作为@steveire提到的,一个SSCCE会很有帮助。尽管如此,问题很可能与您的add_subdirectory调用的顺序/位置有关于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来避免。这可以更细粒度地控制预处理器定义; 我们不希望haggis无处泄漏!
假设我们从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 定义 TOPPINGSSIDE 被应用于单个目标库 Two,无论我们在同一个 CMakeList.txt 中定义了多少其他目标。
由于 TOPPINGS 被声明为 PUBLIC,它会使 CMake 将其应用于链接到 Two 的任何其他目标。当我们在顶层的 CMakeLists.txt 中调用 target_link_libraries(MyTestExe One Two) 时,我们就做到了这一点,因此 MyTestExe 也将具有 TOPPINGS 作为 PP 定义,但它不会有 SIDE,因为那是 TwoPRIVATE 定义。

太棒了Fraser。感谢你在回答中提供的详细信息。这是-D传递给CMake(非常类似于PP),以及顺序的组合。 - John Carter

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