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.