Preprocessor definitions not propagating from CMake to Unix Makefiles

Joh*_*ter 2 c++ makefile cmake c-preprocessor

I'm having trouble getting anything I pass to CMake using -D or add_definitions() to show up when compiling the Makefiles that CMake creates.

(Summarized using a trivial example).

At the top level, I have a build.sh script, that starts with:

cmake \
    -G "Unix Makefiles" \
    -DPIZZA=1 \
    -DCMAKE_VERBOSE_MAKEFILE=1 \
    $TOPPINGS \
    ../../src
Run Code Online (Sandbox Code Playgroud)

$TOPPINGS is declared as -DTOPPINGS=ALL previously. I've verified it's correctly getting passed to the above. Based on the value of TOPPINGS, my CmakeLists.txt adds some more preprocessor definitions using add_definitions(). For the sake of discussion we'll say it does:

add_definitions( -DCHEESE=Mozz ) 
add_definitions( -DMEAT=Meat ) 
Run Code Online (Sandbox Code Playgroud)

This generates without a problem. In the CMakeCache.txt they appear:

//No help, variable specified on the command line.
CHEESE:UNINITIALIZED=Mozz
Run Code Online (Sandbox Code Playgroud)

And I've verified my logic using message() in CMakeLists.txt.

But when we build using generated Makefiles, these are not defined. Neither the ones specified on the invocation to Cmake nor those added through add_definitions.

In looking at the documentation for add_definitions I see:

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

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

Fra*_*ser 9

正如@steveire所说,SSCCE会有所帮助.尽管如此,问题很可能与add_subdirectory呼叫相关的add_definitions呼叫顺序/位置有关.


首先,为了清楚起见,CMake设置的变量与预处理器定义没有任何关系,除非您明确地将它们绑定在一起.我的意思是,如果你打电话

cmake -DTOPPINGS=Haggis .
Run Code Online (Sandbox Code Playgroud)

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

add_definitions(-DTOPPINGS=${TOPPINGS})
Run Code Online (Sandbox Code Playgroud)


好的,举个例子,考虑以下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)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,子目录的的CMakeLists.txt"一"定义的目标不会TOPPINGS一个PP定义,因为add_subdirectory(One)在之前来add_definitions调用.如果"一个"使用任何PP定义add_definitions,它们将不会传播回顶级或"两个".

然而,由于add_subdirectory(Two)来自add_definitions通话,(及其任何子目录中)在那里定义的所有目标都会TOPPINGS一个PP定义.

最后,目标MyTestExe也将具有TOPPINGSPP定义,无论add_executable呼叫在何处与呼叫相关add_definitions.


通过使用target_compile_definitions而不是,可以避免一些混乱add_definitions.这样可以更精细地控制PP定义; 我们不希望哈吉斯到处泄漏!

假设我们add_definitions(-DTOPPINGS=Haggis)从CMakeLists.txt中删除该行.现在在子目录"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)
Run Code Online (Sandbox Code Playgroud)

这会导致PP定义TOPPINGS SIDE应用于单个目标库Two,无论我们在同一个CMakeList.txt中定义了多少其他目标.

由于TOPPINGS声明为PUBLIC,它会导致CMake将其应用于任何其他链接目标Two.当我们调用时,我们在顶级CMakeLists.txt中执行此操作target_link_libraries(MyTestExe One Two),因此MyTestExe也将具有TOPPINGSPP定义,但SIDE从那时起它就没有PRIVATETwo.