Reputation: 2433
I have three libraries, each in a different folder.
LibParent add_library(${PROJECT_NAME} STATIC LibParent.cpp $<TARGET_OBJECTS:LibChild-obj>))
LibChild add_library(${PROJECT_NAME}-obj OBJECT LibChild.cpp $<TARGET_OBJECTS:LibBase-obj>))
LibBase add_library(${PROJECT_NAME}-obj OBJECT LibBase.cpp)
The top CMakeLists.txt
has:
add_subdirectory(LibBase)
add_subdirectory(LibChild)
add_subdirectory(LibParent)
The problem is that using the LibParent.a
in an app, I get undefined reference to LibBase::...
.
How can I pass the LibBase
's dependencies to every CMake target using LibChild-obj
?
LibChild-obj
should include both the LibBase
and the object of LibChild
LibParent
does not call directly LibBase
, only LibChild
's functions
I'd like to avoid adding $<TARGET_OBJECTS:LibBase-obj>
in the LibParent
since it doesn't call it directly.
I also would like to stick with OBJECT libraries when I don't need a STATIC library.
The goal is to deliver only LibParent.a
containing LibChild
AND LibChild
's dependency LibBase
so that the LibChild's functions can call LibBase's functions.
I think it's important to mention the CMake version: >3.17
Upvotes: 1
Views: 101
Reputation: 19916
The goal is to deliver only LibParent.a containing LibChild AND LibChild's dependency LibBase so that the LibChild's functions can call LibBase's functions.
You're almost there... here are the build files:
# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(example)
add_subdirectory(LibBase)
add_subdirectory(LibChild)
add_subdirectory(LibParent)
add_executable(test main.cpp)
target_link_libraries(test PRIVATE LibParent)
# ./LibBase/CMakeLists.txt
add_library(LibBase OBJECT base.cpp)
target_include_directories(
LibBase
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
)
# ./LibChild/CMakeLists.txt
add_library(LibChild OBJECT child.cpp)
target_include_directories(
LibChild
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
)
target_link_libraries(LibChild PUBLIC LibBase)
# ./LibParent/CMakeLists.txt
add_library(LibParent parent.cpp)
target_include_directories(
LibParent
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
)
target_link_libraries(LibParent PRIVATE LibChild LibBase)
Here are some dummy source files:
// Lib{Base,Child,Parent}/{base,child,parent}.cpp
#include <cstdio>
#include "{base,child,parent}.h" // only contains do_{..} decl.
void do_{base,child,parent}() {
do_{base,child}(); // parent calls child, child calls base
puts("{base,child,parent}");
}
// main.cpp
#include <parent.h>
int main () {
do_parent();
return 0;
}
Console interaction:
$ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
...
$ $ cmake --build build/ --verbose
[1/6] /usr/bin/c++ -I/home/alex/test/LibParent -I/home/alex/test/LibChild -I/home/alex/test/LibBase -O3 -DNDEBUG -MD -MT CMakeFiles/test.dir/main.cpp.o -MF CMakeFiles/test.dir/main.cpp.o.d -o CMakeFiles/test.dir/main.cpp.o -c /home/alex/test/main.cpp
[2/6] /usr/bin/c++ -I/home/alex/test/LibBase -O3 -DNDEBUG -MD -MT LibBase/CMakeFiles/LibBase.dir/base.cpp.o -MF LibBase/CMakeFiles/LibBase.dir/base.cpp.o.d -o LibBase/CMakeFiles/LibBase.dir/base.cpp.o -c /home/alex/test/LibBase/base.cpp
[3/6] /usr/bin/c++ -I/home/alex/test/LibChild -I/home/alex/test/LibBase -O3 -DNDEBUG -MD -MT LibChild/CMakeFiles/LibChild.dir/child.cpp.o -MF LibChild/CMakeFiles/LibChild.dir/child.cpp.o.d -o LibChild/CMakeFiles/LibChild.dir/child.cpp.o -c /home/alex/test/LibChild/child.cpp
[4/6] /usr/bin/c++ -I/home/alex/test/LibParent -I/home/alex/test/LibChild -I/home/alex/test/LibBase -O3 -DNDEBUG -MD -MT LibParent/CMakeFiles/LibParent.dir/parent.cpp.o -MF LibParent/CMakeFiles/LibParent.dir/parent.cpp.o.d -o LibParent/CMakeFiles/LibParent.dir/parent.cpp.o -c /home/alex/test/LibParent/parent.cpp
[5/6] : && /usr/bin/cmake -E rm -f LibParent/libLibParent.a && /usr/bin/ar qc LibParent/libLibParent.a LibChild/CMakeFiles/LibChild.dir/child.cpp.o LibBase/CMakeFiles/LibBase.dir/base.cpp.o LibParent/CMakeFiles/LibParent.dir/parent.cpp.o && /usr/bin/ranlib LibParent/libLibParent.a && :
[6/6] : && /usr/bin/c++ -O3 -DNDEBUG CMakeFiles/test.dir/main.cpp.o -o test LibParent/libLibParent.a && :
$ ./build/test
base
child
parent
$ nm build/LibParent/libLibParent.a
child.cpp.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 r .LC0
U puts
U _Z7do_basev
0000000000000000 T _Z8do_childv
base.cpp.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 r .LC0
U puts
0000000000000000 T _Z7do_basev
parent.cpp.o:
U _GLOBAL_OFFSET_TABLE_
0000000000000000 r .LC0
U puts
U _Z8do_childv
0000000000000000 T _Z9do_parentv
The final library indeed includes all objects.
Upvotes: 1