【问题标题】:Preprocessor definitions not propagating from CMake to Unix Makefiles未从 CMake 传播到 Unix Makefile 的预处理器定义
【发布时间】:2015-01-07 04:58:42
【问题描述】:

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

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

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

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

$TOPPINGS 之前被声明为 -DTOPPINGS=ALL。我已经验证它正确地传递到上面。基于 TOPINGS 的值,我的 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 的文档时,我看到:

将定义添加到编译器命令行中的源代码 当前目录及以下目录。

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

【问题讨论】:

    标签: c++ makefile cmake c-preprocessor


    【解决方案1】:

    正如@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 可以避免这种混淆。这对 PP 定义提供了更细粒度的控制;我们不希望羊杂碎到处泄漏!

    假设我们从 CMakeLists.txt 中删除了行 add_definitions(-DTOPPINGS=Haggis)。现在在 subdir "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,因为那是 PRIVATE Two.

    【讨论】:

    • 很棒的弗雷泽。感谢您回答的详细信息。它是传递给 CMake 的 -D (隐匿多少看起来像 PP)和排序的组合。
    猜你喜欢
    • 2018-09-12
    • 2012-02-19
    • 2019-08-27
    • 1970-01-01
    • 1970-01-01
    • 2018-02-10
    • 1970-01-01
    • 2017-11-08
    相关资源
    最近更新 更多