CMake 中的传递对象库

问题描述 投票:0回答:2

问题:是否可以将多个对象库合并为一个更大的对象库?

考虑以下简单项目。

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
没有提供任何源,并且构建失败。

  • 为什么会出现这种情况?
  • 这是一个错误吗?
  • 有哪些解决方法?

enter image description here

动机/背景

我目前正在努力重新组织现有项目以具有模块化结构。它将有模块 A、B 和 C,每个模块都有子模块。

你可以想象目录结构是这样的:

MyProject
├── A
│   ├── A1
│   ├── A2
│   └── A3
├── B
│   ├── B1
│   ├── B2
│   └── B3
└── C
    ├── C1
    ├── C2
    └── C3

每个子模块代表一个库,构成更大整体的一部分,构建系统最终应将所有内容链接到一个库中。

这种结构的原因有两个:

  • 每个子模块形成一个有凝聚力的单元。它有自己的测试、基准测试和示例代码
  • 子模块应该为其功能提供一个干净的 API,即使内部结构有点复杂。

例如,

MyProject/A/A1
看起来像这样:

MyProject/A/A1
├── bench
├── CMakeLists.txt
├── examples
├── src
└── test

我最初的计划是让每个模块包含一个链接所有各自子模块的对象库,所有模块在根目录下静态链接在一起以生成单个库,

MyProject.so

每个子模块还将生成一个特定于该子模块的库(例如,

MyProject/A/A1
将生成
MyProject.A.A1.so
),测试、基准代码和示例将链接到该库。这将允许更快的迭代,而不需要重新构建整个项目。

不幸的是,由于上述原因,这种最初的方法失败了。

c++ cmake compilation build-system object-library
2个回答
0
投票

根据

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>


0
投票

对我有用的是正常链接传递对象库,然后使用此函数递归添加其目标对象:

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)
© www.soinside.com 2019 - 2024. All rights reserved.