C将不同子目录中的静态库链接到单个静态库中

我使用CMake构建了一个由多个嵌套的静态库组成的项目。类似但简单的结构如下图所示:

TestProject:
|-CMakeLists.txt
|-Main.cpp
|-level2
|    | - level2.cpp
|    | - level2.h
|    | - CMakeLists.txt
|    | - level1
|    |     |-level1.cpp
|    |     |-level1.h
|    |     |-CMakeLists.txt
现在,我使用CMake分别为每个级别构建静态库。根据我的测试,每一层的静态库只包含该层的.cpp和.h文件。但是,在生成每一层的静态库时,我想将其与前一层引用的库结合起来。例如,我首先构建了1级的静态库。然后,在2级的CMakeLists.txt中,我依赖于1级的静态库创建了2级的静态库(TARGET_LINK_LIBRARY(${PROJECT_NAME}Level 1)),然后,我想将2级和1级的库合并到一个名为Level 1_2.lib的新的静态库文件中。

这是我在级别1中的CMakeLists.txt:

cmake_minimum_required(VERSION 3.5)

#projcet name
project(LEVEL1 LANGUAGES CXX)

add_library( ${PROJECT_NAME} add.cpp)

# Add the include directories of user-written sources.
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})

这是Level 2的CMakelists.txt。

cmake_minimum_required(VERSION 3.5)

project(LEVEL2 LANGUAGES CXX)

add_subdirectory(level1)

add_library( ${PROJECT_NAME} addplus.cpp)
target_link_libraries(${PROJECT_NAME} LEVEL1)
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})

find_program(MSVC_LIB_TOOL lib.exe)
set(LIBNAME "level1_2.lib")
add_custom_command(
    TARGET examplelib POST_BUILD
    COMMAND ${MSVC_LIB_TOOL} /OUT:${LIBNAME} $<TARGET_FILE:LEVEL2> $<TARGET_FILE:LEVEL1>
    DEPENDS LEVEL1 LEVEL2
    COMMENT "Combining libs..."
    )
add_custom_target(combinedLib
    ALL
    DEPENDS ${LIBNAME}
    )

我使用ADD_CUSTOM_COMMAND和ADD_CUSTOM_TARGET方法尝试生成混合库,引用了以下几个网站:

CMake linking libraries into one single library

CMake Project Structure: How do I properly merge libraries together and include them in multiple executables

但它们并不能真正解决我的需求。只生成了Level 1.lib和Level 2.lib。

如有任何帮助,我们将不胜感激。

08-21=======================================================

更新

感谢大家的回复。现在我使用了对象库(引用Alex的答案),并获得了合并后的静态库。这是我的新代码:

#CMakeLists.txt in level1

cmake_minimum_required(VERSION 3.5)

#projcet name
project(LEVEL1 LANGUAGES CXX)


# Generate lib
add_library( LEVEL1obj OBJECT add.cpp)


# Add the include directories of user-written sources.
target_include_directories(LEVEL1obj PUBLIC ${PROJECT_SOURCE_DIR})

add_library(${PROJECT_NAME})

target_link_libraries(${PROJECT_NAME} PUBLIC LEVEL1obj)

这是Level 2的CMakelists.txt。

#CMakeLists.txt in level2
cmake_minimum_required(VERSION 3.5)

#projcet name
project(LEVEL2 LANGUAGES CXX)


add_subdirectory(level1)

add_library( LEVEL2obj OBJECT addplus.cpp addplus.h)

# Add the include directories of user-written sources.
target_include_directories(LEVEL2obj PUBLIC ${PROJECT_SOURCE_DIR})

target_link_libraries(LEVEL2obj LEVEL1obj)


add_library( ${PROJECT_NAME})

target_link_libraries(${PROJECT_NAME} PUBLIC LEVEL1obj LEVEL2obj)

这是测试项目中的顶级CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(TestCppLib)

file(GLOB SRC "${PROJECT_SOURCE_DIR}/*.cpp")

add_subdirectory(level2)

add_executable(${PROJECT_NAME} ${SRC})

target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})

target_link_libraries(${PROJECT_NAME} PRIVATE LEVEL2)
与Alex的答案略有不同的是:因为我的Leve2库依赖于Level 1库,所以我通过target_link_libraries(LEVEL2obj LEVEL1obj)向其添加了库依赖项。与Alex的答案略有不同的是,因为我的Level 2库依赖于Level 1库生成,所以我通过以下代码向其添加了一个库依赖项。至少目前,它运行良好。


解决方案

这里是一个使用对象库管理静态(或共享!)之间共享对象文件的最小示例。库以及如何链接到它们。

在Level 1/CMakeLists.txt:

add_library(level1_obj OBJECT level1.cpp level1.h)
target_include_directories(level1_obj PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>")

add_library(level1)
target_link_libraries(level1 PUBLIC level1_obj)

在Level 2/CMakeLists.txt

add_subdirectory(level1)

add_library(level2_obj OBJECT level2.cpp level2.h)
target_include_directories(level2_obj PUBLIC "$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>")

add_library(level2)
target_link_libraries(level2 PUBLIC level1_obj level2_obj)

请注意,级别2链接到级别1_obj,而不是级别1。

在Main/CMakeLists.txt:

cmake_minimum_required(VERSION 3.21)
project(TestProject)

add_subdirectory(level2)

add_executable(app Main.cpp)
target_link_libraries(app PRIVATE level2)
需要注意的一个错误是,Xcode不喜欢没有任何实际源文件的库。如果这是一个问题,您可以向静态库目标添加一个空的源文件。

请务必阅读有关对象库的文档:

  1. https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#object-libraries
  2. https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries
  3. https://cmake.org/cmake/help/latest/command/add_library.html#object-libraries
还值得注意的是,除非您需要独立于level1分发level2库,否则最好将它们的对象分开,并要求链接到两者。CMake中的普通目标链接通过可传递链接机制自动处理此问题。

相关文章