John Carter
John Carter

Reputation: 7015

Preprocessor definitions not propagating from CMake to Unix Makefiles

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

$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 ) 

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

//No help, variable specified on the command line.
CHEESE:UNINITIALIZED=Mozz

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.

Is this the source of my problem? I.e.: The definitions are only being added for the directory I'm running CMake from, or is it being added for everything in ../../src (and below) and the problem is elsewhere? If this is the case, is there a way to manually specify these definitions should apply to ../../src and below?

Upvotes: 3

Views: 5300

Answers (1)

Fraser
Fraser

Reputation: 78458

As @steveire mentioned, an SSCCE would be helpful. Nonetheless, there's a good chance that the problem is related to the order/location of your add_subdirectory calls in relation to the add_definitions calls.


First, just to be clear, variables set by CMake don't have any bearing on preprocessor definitions unless you explicitly tie them together. What I mean is that if you call

cmake -DTOPPINGS=Haggis .

or have set(TOPPINGS Haggis) in your CMakeLists.txt, the preprocessor won't see any Haggis unless you also have something like

add_definitions(-DTOPPINGS=${TOPPINGS})


OK, so for an example, consider the following 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)

In this case, targets defined in the CMakeLists.txt of subdir "One" won't have TOPPINGS as a PP definition since add_subdirectory(One) comes before the add_definitions call. If "One" sets any PP definitions using add_definitions, they won't propagate back up to the top-level or to "Two".

However, since add_subdirectory(Two) comes after the add_definitions call, all targets defined in there (and any of its subdirs) will have TOPPINGS as a PP definition.

Finally, the target MyTestExe will also have TOPPINGS as a PP definition, regardless of where the add_executable call comes in relation to the add_definitions call.


Some of this confusion can possibly be avoided by using target_compile_definitions instead of add_definitions. This gives much more fine-grained control of PP definitions; we don't want haggis leaking everywhere!

Say we remove the line add_definitions(-DTOPPINGS=Haggis) from the CMakeLists.txt. Now in the CMakeLists.txt of subdir "Two", we can do:

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)

This causes the PP definitions TOPPINGS and SIDE to be applied to the single target library Two, regardless of how many other targets we may define in the same CMakeList.txt.

Since TOPPINGS is declared as PUBLIC, it causes CMake to apply it to any other target which links Two. We're doing that in the top-level CMakeLists.txt when we call target_link_libraries(MyTestExe One Two), so MyTestExe will also have TOPPINGS as a PP definition, but it won't have SIDE since that's PRIVATE to Two.

Upvotes: 12

Related Questions