问题:是否可以将多个对象库合并为一个更大的对象库?
考虑以下简单项目。
libA.cpp
被编译成对象库LibA.Obj
,libB.cpp
被编译成对象库LibB.Obj
。我想要一个对象库 LibAB.Obj
,它由 LibA.Obj
和 LibB.Obj
组成,并且我想链接它以生成单个共享库。
MyProject
├── CMakeLists.txt
└── src
├── libA.cpp
└── libB.cpp
如果我想将两个库 A 和 B 链接到一个单元中,我可以通过将它们声明为对象库来实现:
cmake_minimum_required(VERSION 3.21)
project(ObjectLibExample)
add_library(LibA.Obj OBJECT src/libA.cpp)
add_library(LibB.Obj OBJECT src/libB.cpp)
add_library(LibAB SHARED $<TARGET_OBJECTS:LibA.Obj> $<TARGET_OBJECTS:LibB.Obj>)
这按预期工作,一切都建立起来。
出于我将很快解释的原因,我想将多个对象库合并到一个单元中:
cmake_minimum_required(VERSION 3.21)
project(ObjectLibExample)
add_library(LibA.Obj OBJECT src/libA.cpp)
add_library(LibB.Obj OBJECT src/libB.cpp)
# Using LibAB.Obj as a source should be equivilant to using both LibA.Obj and LibB.Obj
add_library(LibAB.Obj OBJECT $<TARGET_OBJECTS:LibA.Obj> $<TARGET_OBJECTS:LibB.Obj>)
add_library(LibAB SHARED $<TARGET_OBJECTS:LibAB.Obj>)
这里,
LibAB.Obj
应该是一个对象库,收集了LibA.Obj
和LibB.Obj
的来源。
由于某种原因,CMake 表现得好像
LibAB.Obj
没有提供任何源,并且构建失败。
我目前正在努力重新组织现有项目以具有模块化结构。它将有模块 A、B 和 C,每个模块都有子模块。
你可以想象目录结构是这样的:
MyProject
├── A
│ ├── A1
│ ├── A2
│ └── A3
├── B
│ ├── B1
│ ├── B2
│ └── B3
└── C
├── C1
├── C2
└── C3
每个子模块代表一个库,构成更大整体的一部分,构建系统最终应将所有内容链接到一个库中。
这种结构的原因有两个:
例如,
MyProject/A/A1
看起来像这样:
MyProject/A/A1
├── bench
├── CMakeLists.txt
├── examples
├── src
└── test
我最初的计划是让每个模块包含一个链接所有各自子模块的对象库,所有模块在根目录下静态链接在一起以生成单个库,
MyProject.so
。
每个子模块还将生成一个特定于该子模块的库(例如,
MyProject/A/A1
将生成MyProject.A.A1.so
),测试、基准代码和示例将链接到该库。这将允许更快的迭代,而不需要重新构建整个项目。
不幸的是,由于上述原因,这种最初的方法失败了。
add_library(OBJECT)
的文档:
对象库编译源文件,但不会将其对象文件存档或链接到库中。
[...]
对象库可能只包含编译源、头文件和其他不会影响普通库链接的文件(例如.txt)。
您尚未提供任何可编译的源代码,因此预计会出现致命错误,表明对象库未按预期方式使用。
从 cmake 3.12 开始,可能的解决方法是创建一个
INTERFACE
库并以 INTERFACE
可见性链接对象库。
add_library(LibAB INTERFACE)
target_link_libraries(LibAB.Obj INTERFACE LibA.Obj LibB.Obj)
add_library(LibAB SHARED)
target_link_libraries(LibAB PRIVATE LibAB.Obj)
这确实会阻止您使用
$<TARGET_OBJECTS:LibAB.Obj>
。
对我有用的是正常链接传递对象库,然后使用此函数递归添加其目标对象:
function(add_target_objects TARGET_NAME LIBRARY_NAME)
target_sources(${TARGET_NAME} PRIVATE $<TARGET_OBJECTS:${LIBRARY_NAME}>)
# recurse into library dependencies
get_target_property(libs ${LIBRARY_NAME} LINK_LIBRARIES)
if(libs)
foreach(lib ${libs})
add_target_objects(${TARGET_NAME} ${lib})
endforeach()
endif()
endfunction()
add_library(LibA.Obj OBJECT src/libA.cpp)
add_library(LibB.Obj OBJECT src/libB.cpp)
add_library(LibAB.Obj OBJECT)
target_link_libraries(LibAB.Obj PRIVATE LibA.Obj LibB.Obj)
add_library(LibAB SHARED)
add_target_objects(LibAB LibAB.Obj)