Issue
I'm looking for a way to reflect sub project's preprosessor macro definition to the parent project.
I wrote minimal and executable example to demonstrate the issue:
Let's say I have the following files:
The parent project has CMakeLists.txt and parent.cpp in the current directoy.
The sub project has CMakeLists.txt, sub.hpp, and sub.cpp in the sub
directory. It is third party's project (e.g. some open source software)
./CMakeLists.txt .......A
parent.cpp .......B
sub/CMakeLists.txt ...C
sub.hpp ..........D
sub.cpp ..........E
The parent project's CMakeLists.txt (A) is as follows:
cmake_minimum_required(VERSION 3.10)
project(parent)
add_subdirectory(sub)
include_directories(sub)
add_executable(parent parent.cpp)
And parent.cpp (B) is
#include "sub.hpp"
int main() {
print();
}
It simply calls sub's print() function.
cmake_minimum_required(VERSION 3.10)
The sub project's CMakeLists.txt (C) is
project(sub)
message(STATUS ${OPTION1})
add_executable(sub sub.cpp)
if (OPTION1)
target_compile_definitions(sub PUBLIC PP_OPTION1)
endif ()
The preprosessor macro PP_OPTION1
is conditionally defined by cmake option OPTION1
.
sub.hpp (D) is
#include <iostream>
inline void print() {
#if defined(PP_OPTION1)
std::cout << "PP_OPTION1 set" << std::endl;
#else
std::cout << "PP_OPTION1 not set" << std::endl;
#endif
}
It refers to PP_OPTION1 and chooses output message.
sub.cpp (E) is the same as parent.cpp (B).
#include "sub.hpp"
int main() {
print();
}
When I execute the following command in the current directory:
mkdir build
cd build
cmake -DOPTION1=ON ..
cmake --build .
Then two binaries parent
and sub
are built.
When I execute parent, then I got
PP_OPTION1 not set"
When I execute sub/sub, then I got
PP_OPTION1 set"
This is because PP_OPTION1 is only set for sub project. Is there any good way to reflect the PP_OPTION1 definition to the parent project?
I can achieve it using -DCMAKE_CXX_FLAGS="-DPP_OPTION1"
. It could be a workaround. But if conditionally defined preprosessor macro by the cmake option is automatically reflected to the parent project, it is nice.
Solution
Usually you attach this kind of info to a target linked to the targets that are supposed to gain access to this info. The fact that you're building an executable instead of a library in the subdir means you'll have to introduce an additional target for this.
sub/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# attach info to interface target
add_library(sub-interface INTERFACE)
target_include_directories(sub-interface INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
if (OPTION1)
target_compile_definitions(sub-interface INTERFACE PP_OPTION1)
endif ()
add_executable(sub sub.cpp)
# add info of sub-interface target
target_link_libraries(sub PRIVATE sub-interface)
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(parent)
add_subdirectory(sub)
add_executable(parent parent.cpp)
# add info of sub-interface target (compile define + include dir)
target_link_libraries(parent PRIVATE sub-interface)
Answered By - fabian Answer Checked By - Pedro (WPSolving Volunteer)