Home > Blockchain >  Cmake how to set a global definition?
Cmake how to set a global definition?

Time:10-05

I have a simple structure in my project that includes several subfolders/subprojects. The structure is as following:

main
|- CmakeLists.txt
|- include
|- src
|- library
   |- CmakeLists.txt
   |- include
   |- src

The main CmakeLists.txt

project(main)
file(GLOB SRC . src/*.cpp)
file(GLOB INC . include/*.h)

add_executable(${PROJECT_NAME} ${SRC} ${INC})

target_include_directories(${PROJECT_NAME} PUBLIC
  ${CMAKE_CURRENT_SOURCE_DIR}/include

option(ADDS, "", ON)
add_subdirectory(library)
target_link_libraries(${PROJECT_NAME} PRIVATE library)     

and the library's CmakeLists.txt

project(library)
file(GLOB SRC . src/*.cpp)
file(GLOB INC . include/*.h)
add_library(${PROJECT_NAME} SHARED ${SRC} ${INC})

option(ADDS, "Some additional classes", OFF)
if(ADDS)
    message(STATUS "Configure with some extra classes")
    add_definitions(-DWITH_ADDS)
endif()

Actually I need the option to optionally add/compile several additional classes that usually I don't plan to use/compile. In these additional classes I do something like this:

library/add.h

#ifdef WITH_ADDS
class Adds
{
public:
    void doSomething();
}
#endif

and the same in *.cpp file

But now I want to use these additional classes in my main project.

main.cpp

#include "adds.h"

Adds adds;
adds.doSomething();

So I turned the option ON in the main CMakeFiles.txt but unfortunately I get error:

error: ‘Adds ’  does not name a type

After researching I've found that add_definitions() works only in the project where it was defined. So although I've turned the option in my main file the definition WITH_ADDS still hasn't defined on the main project but in the subproject only.

So my question - is there a way to define a preprocessor variable globally. So once defined in a subproject it will be accessible in all other projects/subprojects? Or maybe there is another solution for that?

CodePudding user response:

The "modern cmake" approach is that all flags are encapsulated in the subprojects, and when you link to the subproject with target_link_library(MYEXE libsubproject), all necessary paths, flags, and definitions are propagated to the main project.

To do this, use target_compile_definitions(library PUBLIC ADDS) in the subproject, which will propagate the setting to any users of this target. If your toplevel is manually adding an include path for this subproject, remove it and use the same strategy for include paths: in the subproject, target_include_directories(library PUBLIC ./include), so that any users of the target will inherit this path.

The PUBLIC keyword is what makes the propagation work: it means the setting applies both to building the library, and to users. INTERFACE means only for users, and PRIVATE means only for building the library.

  • Related