CMake将不同子目录中的静态库链接到一个静态库中
CMake linking static libraries in different subdirectories into one single static library
我用CMake构建了一个由多个嵌套的静态库组成的项目。类似但简单的结构如下图所示:
TestProject:
|-CMakeLists.txt
|-Main.cpp
|-level2
| | - level2.cpp
| | - level2.h
| | - CMakeLists.txt
| | - level1
| | |-level1.cpp
| | |-level1.h
| | |-CMakeLists.txt
现在,我使用CMake分别为每个关卡构建静态库。根据我的测试,每层的静态库只包含该层的.cpp和.h文件。但是,我想在生成每一层的静态库时,将其与上一层引用的库结合起来。比如我建了1级的静态库first.Then,在2级的CMakeLists.txt,我创建2级的静态库依赖于1级的静态库(target_link_libraries (${PROJECT_NAME} LEVEL1) ),然后,我想将级别 2 和级别 1 的库合并到一个名为 level1_2.lib.
的新静态库文件中
这是我在 Level1 中的 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})
这是level2的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方法尝试生成混合库,参考以下几个网站:
但是他们并不能真正解决我的needs.Onlylevel1.lib并且生成了level2.lib
如有任何帮助,我们将不胜感激。
08-21 更新 =================================== ====================
感谢大家 reply.Now 我使用了对象库(引用自 Alex 的回答),并得到了合并的静态 library.Here 我的新代码:
#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)
这是level2的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 的回答略有不同的是:因为我的 level2 库依赖于 level1 库,所以我通过 target_link_libraries(LEVEL2obj LEVEL1obj)
添加了一个库依赖。和Alex的回答略有不同的是,因为我的level2库依赖level1库的生成,所以我通过下面的代码给它添加了一个库依赖。至少现在,它运作良好。
这是一个使用对象库来管理静态(或共享!)库之间的共享对象文件以及如何 link 到它们的最小示例。
在level1/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)
在level2/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)
请注意 level2 linked 到 level1_obj,而不是 level1。
在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 不喜欢没有任何真正源文件的库。如果这是一个问题,您可以将一个空的源文件添加到您的静态库目标。
请务必阅读有关对象库的文档:
- https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#object-libraries
- https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries
- https://cmake.org/cmake/help/latest/command/add_library.html#object-libraries
另外值得注意的是,除非您需要独立于 level1
分发您的 level2
库,否则最好将它们的对象分开并要求 linking两个都。 CMake 中的普通目标 linking 通过传递 linking 机制自动处理此问题。
我用CMake构建了一个由多个嵌套的静态库组成的项目。类似但简单的结构如下图所示:
TestProject:
|-CMakeLists.txt
|-Main.cpp
|-level2
| | - level2.cpp
| | - level2.h
| | - CMakeLists.txt
| | - level1
| | |-level1.cpp
| | |-level1.h
| | |-CMakeLists.txt
现在,我使用CMake分别为每个关卡构建静态库。根据我的测试,每层的静态库只包含该层的.cpp和.h文件。但是,我想在生成每一层的静态库时,将其与上一层引用的库结合起来。比如我建了1级的静态库first.Then,在2级的CMakeLists.txt,我创建2级的静态库依赖于1级的静态库(target_link_libraries (${PROJECT_NAME} LEVEL1) ),然后,我想将级别 2 和级别 1 的库合并到一个名为 level1_2.lib.
的新静态库文件中这是我在 Level1 中的 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})
这是level2的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方法尝试生成混合库,参考以下几个网站:
但是他们并不能真正解决我的needs.Onlylevel1.lib并且生成了level2.lib
如有任何帮助,我们将不胜感激。
08-21 更新 =================================== ====================
感谢大家 reply.Now 我使用了对象库(引用自 Alex 的回答),并得到了合并的静态 library.Here 我的新代码:
#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)
这是level2的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 的回答略有不同的是:因为我的 level2 库依赖于 level1 库,所以我通过 target_link_libraries(LEVEL2obj LEVEL1obj)
添加了一个库依赖。和Alex的回答略有不同的是,因为我的level2库依赖level1库的生成,所以我通过下面的代码给它添加了一个库依赖。至少现在,它运作良好。
这是一个使用对象库来管理静态(或共享!)库之间的共享对象文件以及如何 link 到它们的最小示例。
在level1/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)
在level2/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)
请注意 level2 linked 到 level1_obj,而不是 level1。
在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 不喜欢没有任何真正源文件的库。如果这是一个问题,您可以将一个空的源文件添加到您的静态库目标。
请务必阅读有关对象库的文档:
- https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#object-libraries
- https://cmake.org/cmake/help/latest/command/target_link_libraries.html#linking-object-libraries
- https://cmake.org/cmake/help/latest/command/add_library.html#object-libraries
另外值得注意的是,除非您需要独立于 level1
分发您的 level2
库,否则最好将它们的对象分开并要求 linking两个都。 CMake 中的普通目标 linking 通过传递 linking 机制自动处理此问题。