Reputation: 61
I have a project with multiple targets release
and test
that is linked against a static library which may be compiled with a TEST
macro.
Say I want my release
target to be built without the TEST
macro and the test
target to be built with that macro defined but that macro has to propagate to the linked-against library.
In my main CMakeLists.txt
I have created the targets and defined that macro using target_compile_definitions(mytest PUBLIC TEST)
but obviously the library core
is not recognizing it.
The project tree is as follows:
.
├── CMakeLists.txt
├── core
│ ├── CMakeLists.txt
│ ├── inc
│ │ ├── core_comp1.h
│ │ └── core_comp2.h
│ └── src
│ ├── core_comp1.c
│ └── core_comp2.c
├── lib
│ ├── CMakeLists.txt
│ ├── inc
│ │ ├── ext_comp1.h
│ │ └── ext_comp2.h
│ └── src
│ ├── ext_comp1.c
│ └── ext_comp2.c
├── main.c
├── README.md
└── test.c
The root ./CMakeLists.txt
is as follows:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(cmake_test)
# add the subdirectories
add_subdirectory(core)
add_subdirectory(lib)
# define my targets
set(MY_TARGETS myexe mytest)
# create and link against the libs
foreach(target ${MY_TARGETS})
add_executable(${target})
target_link_libraries(${target} PRIVATE core ext)
endforeach(target ${MY_TARGETS})
# add target specific sources
target_sources(myexe PRIVATE main.c)
target_sources(mytest PRIVATE test.c)
# define the TEST macro for mytest
target_compile_definitions(mytest PUBLIC TEST)
The ./core/CMakeLists.txt
library folder has:
add_library(core
${CMAKE_CURRENT_SOURCE_DIR}/src/core_comp1.c
${CMAKE_CURRENT_SOURCE_DIR}/src/core_comp2.c
)
target_include_directories(core PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/inc
)
target_link_libraries(core PRIVATE ext)
The output of myexe
, the release target
is correct:
Running the release executable
Original core_comp1_display
While that of mytest
is not correct:
Running the test executable
Original core_comp1_display
It should be:
Running the test executable
Test core_comp1_display
I have pushed the project to GitLab at cmake-library-test
The compilation of the myexe
target gives the follows:
[build] [9/12 8% :: 0.032] /usr/bin/gcc -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/lib/src/ext_comp2.c.o -MF CMakeFiles/myexe.dir/lib/src/ext_comp2.c.o.d -o CMakeFiles/myexe.dir/lib/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [9/12 16% :: 0.034] /usr/bin/gcc -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/core/src/core_comp2.c.o -MF CMakeFiles/myexe.dir/core/src/core_comp2.c.o.d -o CMakeFiles/myexe.dir/core/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [9/12 25% :: 0.039] /usr/bin/gcc -I../../lib/inc -g -MD -MT lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o -MF lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o.d -o lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [9/12 33% :: 0.041] /usr/bin/gcc -I../../lib/inc -g -MD -MT lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o -MF lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o.d -o lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [10/12 41% :: 0.043] /usr/bin/gcc -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/lib/src/ext_comp1.c.o -MF CMakeFiles/myexe.dir/lib/src/ext_comp1.c.o.d -o CMakeFiles/myexe.dir/lib/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [10/12 50% :: 0.046] /usr/bin/gcc -I../../core/inc -g -MD -MT core/CMakeFiles/core.dir/src/core_comp2.c.o -MF core/CMakeFiles/core.dir/src/core_comp2.c.o.d -o core/CMakeFiles/core.dir/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [10/12 58% :: 0.049] /usr/bin/gcc -I../../core/inc -g -MD -MT core/CMakeFiles/core.dir/src/core_comp1.c.o -MF core/CMakeFiles/core.dir/src/core_comp1.c.o.d -o core/CMakeFiles/core.dir/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [11/12 66% :: 0.054] /usr/bin/gcc -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/main.c.o -MF CMakeFiles/myexe.dir/main.c.o.d -o CMakeFiles/myexe.dir/main.c.o -c ../../main.c
[build] [11/12 75% :: 0.058] /usr/bin/gcc -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/myexe.dir/core/src/core_comp1.c.o -MF CMakeFiles/myexe.dir/core/src/core_comp1.c.o.d -o CMakeFiles/myexe.dir/core/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [11/12 83% :: 0.110] : && /usr/bin/cmake -E rm -f lib/libmylib.a && /usr/bin/ar qc lib/libmylib.a lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o && /usr/bin/ranlib lib/libmylib.a && :
[build] [11/12 91% :: 0.119] : && /usr/bin/cmake -E rm -f core/libcore.a && /usr/bin/ar qc core/libcore.a core/CMakeFiles/core.dir/src/core_comp1.c.o core/CMakeFiles/core.dir/src/core_comp2.c.o && /usr/bin/ranlib core/libcore.a && :
[build] [12/12 100% :: 0.147] : && /usr/bin/gcc -g CMakeFiles/myexe.dir/main.c.o CMakeFiles/myexe.dir/core/src/core_comp1.c.o CMakeFiles/myexe.dir/core/src/core_comp2.c.o CMakeFiles/myexe.dir/lib/src/ext_comp1.c.o CMakeFiles/myexe.dir/lib/src/ext_comp2.c.o -o myexe core/libcore.a lib/libmylib.a && :
[build] Build finished with exit code 0
Whereas the compilation of mytest
give:
[build] [9/12 8% :: 0.035] /usr/bin/gcc -I../../core/inc -g -MD -MT core/CMakeFiles/core.dir/src/core_comp2.c.o -MF core/CMakeFiles/core.dir/src/core_comp2.c.o.d -o core/CMakeFiles/core.dir/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [9/12 16% :: 0.045] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o -MF CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o.d -o CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [9/12 25% :: 0.047] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -MF CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o.d -o CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [9/12 33% :: 0.049] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/core/src/core_comp2.c.o -MF CMakeFiles/mytest.dir/core/src/core_comp2.c.o.d -o CMakeFiles/mytest.dir/core/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [9/12 41% :: 0.049] /usr/bin/gcc -I../../core/inc -g -MD -MT core/CMakeFiles/core.dir/src/core_comp1.c.o -MF core/CMakeFiles/core.dir/src/core_comp1.c.o.d -o core/CMakeFiles/core.dir/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [10/12 50% :: 0.052] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/test.c.o -MF CMakeFiles/mytest.dir/test.c.o.d -o CMakeFiles/mytest.dir/test.c.o -c ../../test.c
[build] [10/12 58% :: 0.056] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/core/src/core_comp1.c.o -MF CMakeFiles/mytest.dir/core/src/core_comp1.c.o.d -o CMakeFiles/mytest.dir/core/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [10/12 66% :: 0.065] /usr/bin/gcc -I../../lib/inc -g -MD -MT lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o -MF lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o.d -o lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [10/12 75% :: 0.069] /usr/bin/gcc -I../../lib/inc -g -MD -MT lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o -MF lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o.d -o lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [11/12 83% :: 0.127] : && /usr/bin/cmake -E rm -f core/libcore.a && /usr/bin/ar qc core/libcore.a core/CMakeFiles/core.dir/src/core_comp1.c.o core/CMakeFiles/core.dir/src/core_comp2.c.o && /usr/bin/ranlib core/libcore.a && :
[build] [11/12 91% :: 0.139] : && /usr/bin/cmake -E rm -f lib/libmylib.a && /usr/bin/ar qc lib/libmylib.a lib/CMakeFiles/mylib.dir/src/ext_comp1.c.o lib/CMakeFiles/mylib.dir/src/ext_comp2.c.o && /usr/bin/ranlib lib/libmylib.a && :
[build] [12/12 100% :: 0.168] : && /usr/bin/gcc -g CMakeFiles/mytest.dir/test.c.o CMakeFiles/mytest.dir/core/src/core_comp1.c.o CMakeFiles/mytest.dir/core/src/core_comp2.c.o CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -o mytest core/libcore.a lib/libmylib.a && :
[build] Build finished with exit code 0
It is clear that core_comp*.c
and ext_comp*.c
were compiled without -DTEST
Using the suggested INTERFACE
keyword, the flag -DTEST
is passed into all files and the compilation is as follows:
[build] [5/6 16% :: 0.024] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/core/src/core_comp2.c.o -MF CMakeFiles/mytest.dir/core/src/core_comp2.c.o.d -o CMakeFiles/mytest.dir/core/src/core_comp2.c.o -c ../../core/src/core_comp2.c
[build] [5/6 33% :: 0.025] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -MF CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o.d -o CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -c ../../lib/src/ext_comp2.c
[build] [5/6 50% :: 0.038] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o -MF CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o.d -o CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o -c ../../lib/src/ext_comp1.c
[build] [5/6 66% :: 0.041] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/core/src/core_comp1.c.o -MF CMakeFiles/mytest.dir/core/src/core_comp1.c.o.d -o CMakeFiles/mytest.dir/core/src/core_comp1.c.o -c ../../core/src/core_comp1.c
[build] [5/6 83% :: 0.058] /usr/bin/gcc -DTEST -I../../core/inc -I../../lib/inc -g -MD -MT CMakeFiles/mytest.dir/test.c.o -MF CMakeFiles/mytest.dir/test.c.o.d -o CMakeFiles/mytest.dir/test.c.o -c ../../test.c
[build] [6/6 100% :: 0.134] : && /usr/bin/gcc -g CMakeFiles/mytest.dir/test.c.o CMakeFiles/mytest.dir/core/src/core_comp1.c.o CMakeFiles/mytest.dir/core/src/core_comp2.c.o CMakeFiles/mytest.dir/lib/src/ext_comp1.c.o CMakeFiles/mytest.dir/lib/src/ext_comp2.c.o -o mytest && :
[build] Build finished with exit code 0
The libraries core
and mylib
are now transparent and the targets myexe
and mytest
are actually considering the libraries sources are 'their'
Upvotes: 0
Views: 1518
Reputation: 356
One way to achieve similar behavior is to use an interface library and add the source files to the interface library via target_sources().
This doesn't actually propagate the definition down to the library, instead it brings the sources up to the consuming targets. One would want to be sure and only depend on this library via PRIVATE
or else the sources would get compiled for each subsequent dependent.
I wouldn't encourage this solution, but I've had need of it before, so thought I would share.
./CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(example)
add_subdirectory(lib)
add_executable(my_exe main.c)
target_link_libraries(my_exe PRIVATE my_lib)
add_executable(my_test main.c)
target_link_libraries(my_test PRIVATE my_lib)
target_compile_definitions(my_test PRIVATE TEST)
./main.c
#include <stdio.h>
const char * get_string();
int main(int argc, char *argv[]) {
printf("The message is \"%s\"\n", get_string());
return 0;
}
lib/CMakeLists.txt
add_library(my_lib INTERFACE)
target_sources(my_lib INTERFACE message.c)
lib/message.c
#ifdef TEST
const char * get_string(){
return "The test string";
}
#else
const char * get_string(){
return "The normal string";
}
#endif
Upvotes: 1