预处理器定义不会从 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
因为那是 PRIVATE
到 Two
.
在编译 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
因为那是 PRIVATE
到 Two
.