None
None

Reputation: 2433

How to use nested OBJECT libraries and how to pass the object lib dependencies?

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?

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

Answers (1)

Alex Reinking
Alex Reinking

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

Related Questions