Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake conditional preprocessor define on code

Tags:

I'm migrating a makefile project to CMake. The person who wrote the makefile the first time had done a module for writing certain values in an include file.

There's a main config.h file that includes a config_in.h. The config.h file contains something like this:

#ifndef USE_FEATURE_A #define USE_FEATURE_A 0 #endif  #ifndef USE_FEATURE_B #define USE_FEATURE_B 0 #endif 

In the makefile there's a fake target like with_feature_a that writes in config_in.h

#define USE_FEATURE_A 1 

In this way someone can type

make with_feature_a make 

to get the right build.

I want to replicate something like this using this codebase but using CMake. I tried a couple of approaches suggested on the net, but I didn't get it to work.

set_target_properties(with_feature_a PROPERTIES COMPILE_DEFINITIONS      "WITH_FEATURE_A=1" ) 

This isn't working because if I run

make with_feature_a 

I don't see with_feature_a in the preprocessor command line.

The second attempt I made is to write a file directly with the content set to whatever I want, but I didn't understand how to connect the file() command to my target.

I placed this in my CMakeLists.txt

file(WRITE  local/config_in.h      "#define WITH_FEATURE_A 1" ) 

but this isn't executed everytime and I don't know how to set it to a single target.

Any help is appreciated. Thank you for reading all this stuff. Sorry for the long story :)

UPDATE

The solution provided here is a big enhacement on the road to solution. The problem is that is don't allow recursive definitions. I show an example:

in CMakeLists.txt I placed:

if (WITH_FEATURE_A) MESSAGE(STATUS "WITH_FEATURE_A") add_definitions(-DUSE_FEATURE_A=1)     add_definitions(-DWITH_FEABURE_B=1) endif()  if (WITH_FEABURE_B) MESSAGE(STATUS "WITH_FEATURE_B") add_definitions(-DUSE_FEATURE_D=1) endif()   if (WITH_FEABURE_C) MESSAGE(STATUS "WITH_FEATURE_C") add_definitions(-DUSE_FEATURE_D=1) endif()   if (WITH_FEABURE_D) MESSAGE(STATUS "WITH_FEATURE_D") endif() 

in this case if I execute cmake with -DWITH_FEATURE_A=1 I'd love to see in the output:

WITH_FEATURE_A WITH_FEATURE_B WITH_FEATURE_D 

actually this code print just

WITH_FEATURE_A 
like image 836
andyinno Avatar asked Mar 04 '13 11:03

andyinno


People also ask

How do I specify in Cmake?

You can use the command line to set entries in the Cache with the syntax cmake -D var:type=value , just cmake -D var=value or with cmake -C CMakeInitialCache. cmake .

How do you define a variable in Cmake?

Options and variables are defined on the CMake command line like this: $ cmake -DVARIABLE=value path/to/source You can set a variable after the initial `CMake` invocation to change its value. You can also undefine a variable: $ cmake -UVARIABLE path/to/source Variables are stored in the `CMake` cache.

What does Add_definitions do in Cmake?

Add -D define flags to the compilation of source files. Adds definitions to the compiler command line for targets in the current directory, whether added before or after this command is invoked, and for the ones in sub-directories added after.


1 Answers

You can simplify things by avoiding creating the dummy targets and removing the config file. Instead, if you pass the requirements via the command line when you invoke CMake (or via the CMake GUI), you can run make only once.

For example, you could add the following to your CMakeLists.txt:

option(WITH_FEATURE_A "Option description" ON) option(WITH_FEATURE_B "Option description" OFF)  if(WITH_FEATURE_A)   add_definitions(-DUSE_FEATURE_A) endif() if(WITH_FEATURE_B)   add_definitions(-DUSE_FEATURE_B) endif() 

By default, if you just run CMake, it will set the CMake variable WITH_FEATURE_A to ON which consequently adds USE_FEATURE_A as a preprocessor definition to the build. USE_FEATURE_B is undefined in the code.

This would be equivalent to doing #define USE_FEATURE_A in your code.


If you really need the equivalent of

#define USE_FEATURE_A 1 #define USE_FEATURE_B 0 

then in your CMakeLists.txt you can do:

option(WITH_FEATURE_A "Option description" ON) option(WITH_FEATURE_B "Option description" OFF)  if(WITH_FEATURE_A)   add_definitions(-DUSE_FEATURE_A=1) else()   add_definitions(-DUSE_FEATURE_A=0) endif() if(WITH_FEATURE_B)   add_definitions(-DUSE_FEATURE_B=1) else()   add_definitions(-DUSE_FEATURE_B=0) endif() 

To change these defaults from the command line, simply do (e.g.):

cmake . -DWITH_FEATURE_A=OFF -DWITH_FEATURE_B=ON make 

Once a variable has been set via the command line this way, it is cached and will remain unchanged until either it is overwritten with a different value on the command line, or you delete the CMakeCache.txt file in your build root.


Response to update:

As @Peter noted, you appear to be mixing up CMake variables (the WITH_FEATURE... ones) and the preprocessor definitions (the USE_FEATURE... ones). You can as suggested resolve all the dependencies between options first, then set the resulting preprocessor definitions, or in this case where the flow is quite straightforward, just do it all in one go:

if(WITH_FEATURE_A)   message(STATUS "WITH_FEATURE_A")   add_definitions(-DUSE_FEATURE_A=1)   set(WITH_FEATURE_B ON) endif()  if(WITH_FEATURE_B)   message(STATUS "WITH_FEATURE_B")   add_definitions(-DUSE_FEATURE_B=1)   set(WITH_FEATURE_D ON) endif()  if(WITH_FEATURE_C)   message(STATUS "WITH_FEATURE_C")   add_definitions(-DUSE_FEATURE_C=1)   set(WITH_FEATURE_D ON) endif()  if(WITH_FEATURE_D)   message(STATUS "WITH_FEATURE_D")   add_definitions(-DUSE_FEATURE_D=1) endif() 

like image 92
Fraser Avatar answered Sep 28 '22 04:09

Fraser