Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

233
Views
CMake nested OBJECT library dependencies

I created a project with some nested library dependencies using the OBJECT library type. The motivation for this is to avoid link order issues with static libraries.

I have a simple directory structure as follows:

├── bar
│   ├── bar.c
│   └── bar.h
├── foo
│   ├── foo.c
│   └── foo.h
├── main.c
└── CMakeLists.txt

foo depends on bar, and main depends on foo. For example,

bar.c

#include "bar.h"

#include <stdio.h>

void bar(void) {
  printf("woot woot\n");
}

foo.c

#include "foo.h"

#include "bar.h"

void foo(void) {
  bar();
}

main.c

#include "foo.h"

int main() {
  foo();
  return 0;
}

The CMakeLists.txt

cmake_minimum_required(VERSION 3.18)

project(myproj)

enable_language(C ASM)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)

# build bar
add_library(bar OBJECT ${PROJECT_SOURCE_DIR}/bar/bar.c)
target_include_directories(bar PUBLIC ${PROJECT_SOURCE_DIR}/bar)

# build foo, depends on bar
add_library(foo OBJECT ${PROJECT_SOURCE_DIR}/foo/foo.c)
target_include_directories(foo PUBLIC ${PROJECT_SOURCE_DIR}/foo)
target_link_libraries(foo PUBLIC bar)

# build executable, depends on foo
add_executable(myexe ${PROJECT_SOURCE_DIR}/main.c)
target_link_libraries(myexe PUBLIC foo)

My expectation is that myexe would inherit the bar dependency from foo when it links to it. However, this is not the case it seems. When the code is compiled, main.o only links to foo.o, and thus there is an undefined reference to bar. However, if I change the library types from OBJECT to STATIC everything works fine. Why does this happen?

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Object libraries cannot be chained this way. You must link directly (not transitively) to an object library to acquire its object files. As it says in the documentation,

Object Libraries may "link" to other object libraries to get usage requirements, but since they do not have a link step nothing is done with their object files. [...] In other words, when Object Libraries appear in a target's INTERFACE_LINK_LIBRARIES property they will be treated as Interface Libraries, but when they appear in a target's LINK_LIBRARIES property their object files will be included in the link too.

I agree it defies all reason, though.


However, you can manually propagate the object files via target_link_libraries(INTERFACE) and the $<TARGET_OBJECTS> generator expression as of 3.21 (doing so was buggy in earlier versions, and the even-hacker target_sources may be used in earlier versions, too).

Do note that this is a bit of a hack, since there are some cases that will break. Notably, if a library target links to such a target publicly, then the object files will propagate again. So... be careful.

Still, here's a corrected version of your example build:

cmake_minimum_required(VERSION 3.21)
project(myproj LANGUAGES C ASM)

set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use")
option(CMAKE_C_STANDARD_REQUIRED "Enforce strict C standard selection" ON)
option(CMAKE_C_EXTENSIONS "Allow compiler-specific C extensions" OFF)

# build bar
add_library(bar OBJECT bar/bar.c)
target_include_directories(
  bar PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/bar>"
)

# build foo, depends on bar
add_library(foo OBJECT foo/foo.c)
target_include_directories(
  foo PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/foo>"
)
target_link_libraries(foo PUBLIC bar "$<TARGET_OBJECTS:bar>")

# build executable, depends on foo
add_executable(myexe main.c)
target_link_libraries(myexe PRIVATE foo)

At the command line:

$ cmake -G Ninja -S . -B build 
...
$ cmake --build build -- -nv
[1/4] /usr/bin/cc  -I/path/to/bar -std=c11 -MD -MT CMakeFiles/bar.dir/bar/bar.c.o -MF CMakeFiles/bar.dir/bar/bar.c.o.d -o CMakeFiles/bar.dir/bar/bar.c.o -c /path/to/bar/bar.c
[2/4] /usr/bin/cc  -I/path/to/foo -I/path/to/bar -std=c11 -MD -MT CMakeFiles/foo.dir/foo/foo.c.o -MF CMakeFiles/foo.dir/foo/foo.c.o.d -o CMakeFiles/foo.dir/foo/foo.c.o -c /path/to/foo/foo.c
[3/4] /usr/bin/cc  -I/path/to/foo -I/path/to/bar -std=c11 -MD -MT CMakeFiles/myexe.dir/main.c.o -MF CMakeFiles/myexe.dir/main.c.o.d -o CMakeFiles/myexe.dir/main.c.o -c /path/to/main.c
[4/4] : && /usr/bin/cc   CMakeFiles/foo.dir/foo/foo.c.o CMakeFiles/myexe.dir/main.c.o -o myexe  CMakeFiles/bar.dir/./bar/bar.c.o && :
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!