当前位置: 首页 > article >正文

CMake管理依赖实战:多仓库的无缝集成

随着软件复杂度的增加,单个项目可能需要依赖多个外部库或模块。这些依赖项可能是来自不同的代码仓库,如ATestBTest。为了实现高效的依赖管理,CMake提供了多种方式来处理这种多仓库的情况。下面我们将详细介绍几种常见的方法,并通过实例展示它们的应用场景。

方法一:使用 add_subdirectory(代码强绑定)

示例

假设我们有两个项目ATestBTest,其中BTestATest的一个子模块。

A的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(ATest)

add_subdirectory(BTest)

add_executable(ATest main.cpp)

target_link_libraries(ATest PRIVATE BTest)

B的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(BTest)

add_library(BTest STATIC btest.cpp btest.h)
优点与缺点
  • 优点: 简单直接,适合小型项目。
  • 缺点: 需要将BTest作为子目录包含在ATest中,不够灵活。
应用场景

适用于BTest作为ATest的一部分,且两者紧密耦合的情况。

方法二:使用 find_package(系统级安装)

示例

BTest是一个独立的库时,可以使用find_package来查找并链接它。

B的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(BTest)

add_library(BTest STATIC btest.cpp btest.h)

install(TARGETS BTest DESTINATION lib)
install(FILES btest.h DESTINATION include)

include(CMakePackageConfigHelpers)
write_basic_package_version_file(
    "${PROJECT_BINARY_DIR}/BTestConfigVersion.cmake"
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY AnyNewerVersion
)
configure_package_config_file(
    "BTestConfig.cmake.in"
    "${PROJECT_BINARY_DIR}/BTestConfig.cmake"
    INSTALL_DESTINATION lib/cmake/BTest
)
install(FILES "${PROJECT_BINARY_DIR}/BTestConfig.cmake" "${PROJECT_BINARY_DIR}/BTestConfigVersion.cmake"
        DESTINATION lib/cmake/BTest)

A的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(ATest)

find_package(BTest REQUIRED)

add_executable(ATest main.cpp)

target_link_lraries(ATest PRIVATE BTest::BTest)
优点与缺点
  • 优点: 灵活,适合复用,适合大型项目。
  • 缺点: 需要额外的配置步骤。
应用场景

适用于BTest是一个独立库,并且需要被多个项目复用的情况。

方法三:使用 FetchContent(现代源码集成)

示例

如果希望在构建时动态下载BTest,可以使用FetchContent

A的 CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(ATest)

include(FetchContent)
FetchContent_Declare(
    BTest
    GIT_REPOSITORY https://github.com/example/BTest.git
    GIT_TAG v1.0
)
FetchContent_MakeAvailable(BTest)

add_executable(ATest main.cpp)

target_link_libraries(ATest PRIVATE BTest::BTest)

B的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(BTest)

add_library(BTest STATIC btest.cpp btest.h)

add_library(BTest::BTest ALIAS BTest)
优点与缺点
  • 优点: 自动化程度高,无需手动克隆。
  • 缺点: 构建时需要网络连接,依赖仓库可用性影响构建。
应用场景

适用于BTest是一个外部依赖,但不希望将其作为子模块或本地库的情况。

方法四:使用 ExternalProject(完全控制构建)

示例

对于复杂的构建过程,可以使用ExternalProject

A的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(ATest)

include(ExternalProject)
ExternalProject_Add(
    BTest
    GIT_REPOSITORY https://github.com/example/BTest.git
    GIT_TAG v1.0
    PREFIX ${CMAKE_BINARY_DIR}/BTest
    INSTALL_DIR ${CMAKE_BINARY_DIR}/BTest/install
)

set(BTEST_INCLUDE_DIR ${CMAKE_BINARY_DIR}/BTest/install/include)
set(BTEST_LIBRARY ${CMAKE_BINARY_DIR}/BTest/install/lib/libBTest.a)

add_executable(ATest main.cpp)

target_include_directories(ATest PRIVATE ${BTEST_INCLUDE_DIR})
target_link_libraries(ATest PRIVATE ${BTEST_LIBRARY})

add_dependencies(ATest BTest)

B的 CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(BTest)

add_library(BTest STATIC btest.cpp btest.h)

install(TARGETS BTest DESTINATION lib)
install(FILES btest.h DESTINATION include)
优点与缺点
  • 优点: 自动化程度高,可控制依赖的构建过程。
  • 缺点: 配置复杂,构建时间长。
应用场景

适用于BTest的构建过程复杂且需要自动化的情况。

方法五:使用 CPM.cmake(动态Git集成)

适用场景
  • 需要灵活控制依赖版本。
  • 避免本地存储依赖代码。

CPM.cmake 是一个轻量级的CMake脚本,它利用了CMake内建的FetchContent模块,但提供了更多功能,如版本控制、缓存机制等关键特性。通过简单的命令,即可将CPM引入现有项目,立即享有强大的依赖管理功能。

实现步骤
BTest/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(BTest LANGUAGES CXX VERSION 1.0.0)

add_library(BTest STATIC src/b.cpp)
target_include_directories(BTest PUBLIC include)
ATest/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(ATest LANGUAGES CXX)

include(cmake/CPM.cmake)  # 下载CPM脚本

CPMAddPackage(
  NAME BTest
  GIT_REPOSITORY "https://github.com/your/BTest.git"
  GIT_TAG v1.0.0
)

add_executable(ATest src/main.cpp)
target_link_libraries(ATest PRIVATE BTest)
优点与缺点
  • 优点:

    • 版本灵活控制:可以精确指定依赖库的版本号或Git标签,确保项目的稳定性和可追溯性。
    • 轻量化和即插即用:无需安装额外工具,仅需下载一个CPM.cmake脚本文件即可使用。
    • 跨平台支持:适用于任何操作系统,无论是Windows、Linux还是macOS都能无缝工作。
  • 缺点:

    • 需要网络访问:所有依赖库最初都要从网上下载构建,如果离线使用则需设置环境变量CPM_SOURCE_CACHE来缓存依赖。
应用场景

适用于需要对依赖库进行精确版本控制,并且希望避免在本地存储依赖代码的场景。例如,在持续集成环境中,每次构建时都需要确保获取到确切版本的依赖,保证构建的可复现性。

比较与选择

方法优点缺点场景
add_subdirectory简单直接,易于实现需要将BTest放在ATest的目录下,不够灵活BTestATest的子模块或子目录的情况
find_package灵活,适合复用需要额外的配置步骤BTest是独立库,需要被多个项目复用的情况
FetchContent自动下载依赖,无需手动操作构建时需要网络连接,依赖仓库可用性影响构建BTest是外部依赖,但不希望将其作为子模块或本地库的情况
ExternalProject自动化程度高,可控制依赖的构建过程配置复杂,构建时间长BTest的构建过程复杂且需要自动化的情况
CPM.cmake版本灵活控制,轻量化,跨平台支持需要网络访问,初次构建可能较慢需要灵活控制依赖版本,避免本地存储依赖代码的场景

结论

选择合适的方法取决于具体的需求和项目规模。

  • 对于简单的项目,add_subdirectory可能是最简单的选择;
  • 而对于更复杂的项目,特别是当依赖项是独立的库时,find_packageFetchContent则更为适用。
  • 如果依赖项的构建过程特别复杂,则 CPMExternalProject可能是一个更好的选择。

http://www.kler.cn/a/556587.html

相关文章:

  • PHP建立MySQL持久化连接(长连接)及mysql与mysqli扩展的区别
  • 【Python爬虫(31)】解锁Python多线程编程:从入门到实战
  • CPU、SOC、MPU、MCU--详细分析四者的区别
  • 基于SpringBoot的学生用品采购系统设计与实现的设计与实现(源码+SQL脚本+LW+部署讲解等)
  • Linux 本地部署 Deepseek-R1 大模型!
  • C# ConcurrentBag 使用详解
  • 什么是DeFi (去中心化金融)
  • 解决弹窗中form表单中按下tab键不切换的问题
  • 神经网络剪枝技术的重大突破:sGLP-IB与sTLP-IB
  • MTK-Android13-包安装器PackageInstaller 静默安装实现
  • 直播美颜SDK的底层技术解析:图像处理与深度学习的结合
  • 【详细讲解在STM32的UART通信中使用DMA机制】
  • 51单片机-8X8LED点阵
  • RagFlow+Ollama 构建RAG私有化知识库
  • python自动化制作常规的日报数据可视化
  • SpringBoot:解决前后端请求跨域问题(详细教程)
  • Blender小技巧和注意事项
  • CSS Grid 布局学习笔记
  • vue 判断一个属性值,如果是null或者空字符串或者是空格没有值的情况下,赋值为--
  • 国产编辑器EverEdit - 如何在EverEdit中管理工程?