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

标签 c++ makefile cmake c-preprocessor

在编译 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 调用相对于 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 调用之后,所有在其中定义的目标(及其任何子目录)< em>将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

关于c++ - 预处理器定义不会从 CMake 传播到 Unix Makefile,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27812662/

相关文章:

makefile - 在 GNUMakefile 路径中使用 $ 文字

linux - 运行 MPI fortran 代码示例 make 文件

makefile - makefile 符号 $@ 和 $< 是什么意思?

c - 无法使用make编译C源文件。 CMake错误找不到源文件,但它们在那里

linker - 在 cmake 中链接名为 "debug"的库

c++ - 为什么在声明对象 std::vector 但从未使用时编译器不发出警告?

c++ - 跨 conservativeResize 将 ColXpr 维护为 MatrixXf

c++ - putc 在 C++ 中实现为宏?

cmake - 将 cmake 更改为二进制目录

c++ - libtorch:如何从tensorRT fp16半类型指针创建张量?