I have a main
-> that calls a function from object2
-> that calls a function from object1
. Both object2
and object1
are CMake object libraries. Objects are passed along the chain using $<TARGET_OBJECTS:xxx
and usage requirements using target_link_libraries
.
Project structure:
project
|-- main
| |-- main.c
|-- object2
| |-- object2.h
| |-- object2.c
|-- object1
| |-- object1.h
| |-- object1.c
|-- CMakeLists.txt
Contents of
// CMakeLists.txt
project(objlibs)
# Object library 1
add_library(ObjectLibrary1 OBJECT object1/object1.c)
target_include_directories(ObjectLibrary1 INTERFACE object1)
# Object library 2
add_library(ObjectLibrary2 OBJECT object2/object2.c $<TARGET_OBJECTS:ObjectLibrary1>)
target_include_directories(ObjectLibrary2 INTERFACE object2)
target_link_libraries(ObjectLibrary2 PUBLIC ObjectLibrary1)
# Final executable or library
add_executable(MyTarget
main/main.c
$<TARGET_OBJECTS:ObjectLibrary2>
)
target_link_libraries(MyTarget PRIVATE ObjectLibrary2)
Trying to build, I get a linker error.
ld.exe: CMakeFiles/ObjectLibrary2.dir/object2/object2.obj:object2.c:(.text+0x18): undefined reference to `obj1func'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.
I noticed that if I modify the add_executable
statement as follows (i.e. adding the $<TARGET_OBJECTS:ObjectLibrary1>
line), linking goes through without issues.
add_executable(MyTarget
main/main.c
$<TARGET_OBJECTS:ObjectLibrary2>
$<TARGET_OBJECTS:ObjectLibrary1>
)
Since ObjectLibrary2
requires a symbol (the very obj1func
) from ObjectLibrary1
, I would expect that $<TARGET_OBJECTS:ObjectLibrary1>
(as shown in my working try) would be redundant.
CMake version: 3.25.2
// object1.h
#ifndef OBJECT1_H
#define OBJECT1_H
void obj1func(void);
#endif // OBJECT1_H
// object1.c
#include "object1.h"
#include <stdio.h>
void obj1func(void){
printf("obj1func\n");
}
// object2.h
#ifndef OBJECT2_H
#define OBJECT2_H
void obj2func(void);
#endif // OBJECT2_H
// object2.c
#include "object2.h"
#include <stdio.h>
#include "object1.h"
void obj2func(void){
printf("obj2func\n");
obj1func();
}
// main.c
#include <stdio.h>
#include "object2.h"
int main(){
printf("Hello world\n");
obj2func();
}
I have tried the above with all combinations:
- WSL (Ubuntu 20.04.5 LTS), Ninja (1.10.0), clang (10.0.0)
- WSL (Ubuntu 20.04.5 LTS), makefiles (4.2.1), gcc (9.4.0)
- Windows (10 22H2 19045.2486), Visual Studio 16, MSVC (19.29.30146.0)
- Windows (10 22H2 19045.2486), Ninja (1.11.0), clang (15.0.0)
- Windows (10 22H2 19045.2486), makefiles (4.3 for Win32), gcc (12.2.0)
The sequence of cmake
commands is as follows. Out of source, so that I can quickly rm -rf
the build tree/artifacts; building in source makes no difference.
cmake -B build/main -S .
cmake --build build/main --config Debug --verbose --clean-first
In all cases, the issue persists.