如何将一个CMake对象库链接到另一个CMake对象库?
关于CMake对象库依赖传递的链接问题
问题场景
调用链:main 调用 object2 的函数,object2 调用 object1 的函数。object2 和 object1 均为CMake对象库(object libraries),通过$<TARGET_OBJECTS:xxx>传递对象文件,用target_link_libraries设置依赖关系,但构建时出现链接错误。
项目结构
project |-- main | |-- main.c |-- object2 | |-- object2.h | |-- object2.c |-- object1 | |-- object1.h | |-- object1.c |-- CMakeLists.txt
初始CMakeLists.txt内容
// 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)
链接错误信息
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.
临时解决方法
手动在add_executable中添加$<TARGET_OBJECTS:ObjectLibrary1>即可正常链接:
add_executable(MyTarget main/main.c $<TARGET_OBJECTS:ObjectLibrary2> $<TARGET_OBJECTS:ObjectLibrary1> )
但从依赖关系逻辑来看,这一步应该是多余的——ObjectLibrary2已经依赖ObjectLibrary1,理应自动传递对象文件。
源码文件内容
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(); }
测试环境
- 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)
构建命令
cmake -B build/main -S . cmake --build build/main --config Debug --verbose --clean-first
所有环境下均出现相同问题。
问题原因与正确写法
CMake对象库的target_link_libraries仅会传递使用要求(如头文件路径、编译选项),不会自动传递依赖对象库的文件本身。初始写法中,虽然ObjectLibrary2的源列表里包含了$<TARGET_OBJECTS:ObjectLibrary1>,但CMake不会将这些嵌套的对象文件自动传递到引用ObjectLibrary2的最终可执行目标中。
推荐写法:直接将对象库作为源文件
不需要手动使用$<TARGET_OBJECTS:xxx>,直接把对象库添加到可执行目标的源列表中,CMake会自动处理所有依赖的对象文件:
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_include_directories(ObjectLibrary2 INTERFACE object2) target_link_libraries(ObjectLibrary2 PUBLIC ObjectLibrary1) # Final executable add_executable(MyTarget main/main.c ObjectLibrary2 ObjectLibrary1 ) target_link_libraries(MyTarget PRIVATE ObjectLibrary2)
补充说明
不要在对象库的add_library中嵌套$<TARGET_OBJECTS:>,这种写法不仅无法传递对象文件到上层目标,还可能导致重复编译问题(当多个目标引用该对象库时)。
内容的提问来源于stack exchange,提问作者thekyria
相关产品推荐
相关产品推荐

