Skip to content

C++ 包管理

概述

包管理是现代软件开发的重要组成部分,它简化了第三方库的获取、编译和集成过程。C++生态系统中有多种包管理解决方案,本章介绍主流的包管理器和依赖管理最佳实践。

📦 vcpkg包管理器

安装和基本使用

bash
# 克隆vcpkg仓库
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg

# Windows
.\bootstrap-vcpkg.bat

# Linux/macOS
./bootstrap-vcpkg.sh

# 集成到系统
./vcpkg integrate install

# 搜索包
./vcpkg search boost
./vcpkg search json

# 安装包
./vcpkg install boost
./vcpkg install nlohmann-json
./vcpkg install fmt

# 查看已安装包
./vcpkg list

# 移除包
./vcpkg remove boost

CMake集成

cmake
# 方法1:工具链文件
# cmake -DCMAKE_TOOLCHAIN_FILE=vcpkg/scripts/buildsystems/vcpkg.cmake

# 方法2:环境变量
# export VCPKG_ROOT=/path/to/vcpkg

# CMakeLists.txt
find_package(fmt CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(Boost REQUIRED COMPONENTS system filesystem)

add_executable(myapp main.cpp)

target_link_libraries(myapp PRIVATE 
    fmt::fmt
    nlohmann_json::nlohmann_json
    Boost::system
    Boost::filesystem
)

vcpkg.json清单模式

json
{
  "name": "my-application",
  "version": "1.0.0",
  "description": "My C++ application",
  "homepage": "https://github.com/user/my-app",
  "documentation": "https://github.com/user/my-app/wiki",
  "license": "MIT",
  "dependencies": [
    {
      "name": "boost-system",
      "version>=": "1.82.0"
    },
    {
      "name": "nlohmann-json",
      "version>=": "3.11.2"
    },
    "fmt",
    "spdlog",
    {
      "name": "openssl",
      "platform": "!uwp"
    }
  ],
  "builtin-baseline": "3426db05b996481ca31e95fff3734cf23e0f51bc",
  "overrides": [
    {
      "name": "boost",
      "version": "1.82.0"
    }
  ],
  "features": {
    "tools": {
      "description": "Build development tools",
      "dependencies": [
        "gtest",
        "benchmark"
      ]
    }
  }
}

自定义端口

cmake
# ports/mylib/portfile.cmake
vcpkg_from_github(
    OUT_SOURCE_PATH SOURCE_PATH
    REPO myuser/mylib
    REF v1.0.0
    SHA512 1234567890abcdef...
    HEAD_REF master
)

vcpkg_cmake_configure(
    SOURCE_PATH "${SOURCE_PATH}"
    OPTIONS
        -DBUILD_EXAMPLES=OFF
        -DBUILD_TESTS=OFF
)

vcpkg_cmake_build()
vcpkg_cmake_install()

vcpkg_cmake_config_fixup(
    CONFIG_PATH lib/cmake/mylib
)

file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")

vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")

🍃 Conan包管理器

安装和基本使用

bash
# 安装Conan
pip install conan

# 检测配置文件
conan profile detect --force

# 搜索包
conan search boost
conan search openssl

# 创建conanfile.txt
[requires]
boost/1.82.0
openssl/[^1.1]
zlib/1.2.13

[generators]
CMakeDeps
CMakeToolchain

[options]
boost:shared=True
openssl:shared=False

# 安装依赖
conan install . --build=missing

# 使用特定配置文件
conan install . -pr:b=default -pr:h=my_profile --build=missing

CMake集成

cmake
# CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(MyApp)

# 包含Conan生成的文件
include(${CMAKE_BINARY_DIR}/conan_toolchain.cmake)

find_package(Boost REQUIRED COMPONENTS system filesystem)
find_package(OpenSSL REQUIRED)
find_package(ZLIB REQUIRED)

add_executable(myapp main.cpp)

target_link_libraries(myapp 
    Boost::system 
    Boost::filesystem
    OpenSSL::SSL 
    OpenSSL::Crypto
    ZLIB::ZLIB
)

conanfile.py

python
from conan import ConanFile
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps

class MyAppConan(ConanFile):
    name = "myapp"
    version = "1.0"
    
    # 包配置
    settings = "os", "compiler", "build_type", "arch"
    options = {"shared": [True, False], "fPIC": [True, False]}
    default_options = {"shared": False, "fPIC": True}
    
    # 依赖
    def requirements(self):
        self.requires("boost/1.82.0")
        self.requires("openssl/[^1.1]")
        self.requires("fmt/9.1.0")
    
    def build_requirements(self):
        self.test_requires("gtest/1.14.0")
    
    def layout(self):
        cmake_layout(self)
    
    def generate(self):
        deps = CMakeDeps(self)
        deps.generate()
        tc = CMakeToolchain(self)
        tc.generate()
    
    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()
    
    def package(self):
        cmake = CMake(self)
        cmake.install()
    
    def package_info(self):
        self.cpp_info.libs = ["myapp"]

自定义配置文件

ini
# myprofile
[settings]
os=Linux
arch=x86_64
compiler=gcc
compiler.version=11
compiler.libcxx=libstdc++11
build_type=Release

[options]

[buildenv]

[runenv]

[conf]
tools.system.package_manager:mode=install
tools.system.package_manager:sudo=True

🏗️ CPM.cmake

基本使用

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

# 添加依赖
CPMAddPackage("gh:nlohmann/json@3.11.2")
CPMAddPackage("gh:gabime/spdlog@1.12.0")

CPMAddPackage(
    NAME fmt
    GITHUB_REPOSITORY fmtlib/fmt
    GIT_TAG 9.1.0
    OPTIONS "FMT_INSTALL ON"
)

CPMAddPackage(
    NAME Catch2
    GITHUB_REPOSITORY catchorg/Catch2
    VERSION 3.4.0
    OPTIONS "CATCH_INSTALL_DOCS OFF"
)

# 使用依赖
target_link_libraries(myapp PRIVATE 
    nlohmann_json::nlohmann_json 
    spdlog::spdlog
    fmt::fmt
    Catch2::Catch2WithMain
)

高级配置

cmake
# CPM缓存
set(CPM_SOURCE_CACHE $ENV{HOME}/.cache/CPM)

# 本地包优先
set(CPM_USE_LOCAL_PACKAGES ON)

# 条件添加
if(BUILD_TESTING)
    CPMAddPackage("gh:google/googletest@1.14.0")
endif()

# 版本约束
CPMAddPackage(
    NAME boost_algorithm
    URL https://github.com/boostorg/algorithm/archive/boost-1.82.0.tar.gz
    VERSION 1.82.0
    OPTIONS "BUILD_TESTING OFF"
)

# 源码修改
CPMAddPackage(
    NAME MyLibrary 
    GITHUB_REPOSITORY user/mylibrary
    GIT_TAG main
    PATCH_COMMAND git apply ${CMAKE_CURRENT_SOURCE_DIR}/patches/mylib.patch
)

🔧 Hunter包管理器

基本配置

cmake
# CMakeLists.txt
include("cmake/HunterGate.cmake")

HunterGate(
    URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz"
    SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd"
)

project(MyProject)

# 查找包
hunter_add_package(Boost COMPONENTS system filesystem)
hunter_add_package(OpenSSL)
hunter_add_package(nlohmann_json)

find_package(Boost CONFIG REQUIRED system filesystem)
find_package(OpenSSL REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)

# 链接
target_link_libraries(myapp 
    Boost::system 
    Boost::filesystem
    OpenSSL::SSL
    nlohmann_json::nlohmann_json
)

自定义Hunter配置

cmake
# cmake/Hunter/config.cmake
hunter_config(
    Boost
    VERSION 1.82.0
    CMAKE_ARGS 
        BUILD_SHARED_LIBS=OFF
        BOOST_BUILD_DYNAMIC_VSRUNTIME=OFF
)

hunter_config(
    OpenSSL
    VERSION 1.1.1
    CMAKE_ARGS
        OPENSSL_NO_TESTS=ON
)

📋 依赖管理最佳实践

版本管理策略

json
// package-lock.json概念
{
  "dependencies": {
    "boost": {
      "version": "1.82.0",
      "resolved": "https://github.com/boostorg/boost/releases/tag/boost-1.82.0",
      "integrity": "sha512-..."
    },
    "fmt": {
      "version": "9.1.0", 
      "resolved": "https://github.com/fmtlib/fmt/releases/tag/9.1.0",
      "integrity": "sha512-..."
    }
  }
}

多环境配置

bash
# 开发环境
conan install . -pr:b=default -pr:h=debug --build=missing

# 生产环境  
conan install . -pr:b=default -pr:h=release --build=missing

# 交叉编译
conan install . -pr:b=default -pr:h=armv8 --build=missing

依赖冲突解决

python
# conanfile.py
def requirements(self):
    # 版本冲突解决
    self.requires("boost/1.82.0", override=True)
    self.requires("openssl/[^1.1]")
    
    # 条件依赖
    if self.settings.os == "Windows":
        self.requires("winsdk/10.0")
    elif self.settings.os == "Linux":
        self.requires("linux-headers/5.4")

def configure(self):
    # 选项配置
    if self.options.shared:
        self.options["boost"].shared = True
        self.options["openssl"].shared = True

🔗 集成策略

混合包管理

cmake
# 优先级策略:vcpkg > Conan > 系统包 > 源码构建

# 1. 尝试vcpkg
find_package(fmt CONFIG QUIET)

if(NOT fmt_FOUND)
    # 2. 尝试Conan
    find_package(fmt REQUIRED)
endif()

if(NOT fmt_FOUND)
    # 3. 尝试系统包
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(fmt REQUIRED fmt)
endif()

if(NOT fmt_FOUND)
    # 4. 从源码构建
    include(FetchContent)
    FetchContent_Declare(fmt 
        GIT_REPOSITORY https://github.com/fmtlib/fmt.git
        GIT_TAG 9.1.0
    )
    FetchContent_MakeAvailable(fmt)
endif()

CI/CD集成

yaml
# .github/workflows/build.yml
- name: Setup vcpkg
  uses: lukka/run-vcpkg@v11
  with:
    vcpkgGitCommitId: '${{ env.VCPKG_COMMIT_ID }}'

- name: Configure CMake
  run: |
    cmake -B build \
      -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake \
      -DCMAKE_BUILD_TYPE=Release

- name: Cache Conan packages
  uses: actions/cache@v3
  with:
    path: ~/.conan2
    key: conan-${{ runner.os }}-${{ hashFiles('conanfile.txt') }}

- name: Install Conan dependencies
  run: |
    conan install . --build=missing -pr:b=default

Docker化依赖

dockerfile
# Dockerfile.deps
FROM ubuntu:22.04 as deps

RUN apt-get update && apt-get install -y \
    cmake ninja-build g++ git python3-pip

# 安装vcpkg
RUN git clone https://github.com/Microsoft/vcpkg.git /vcpkg
RUN /vcpkg/bootstrap-vcpkg.sh

# 安装依赖
COPY vcpkg.json /workspace/
WORKDIR /workspace
RUN /vcpkg/vcpkg install

# 主构建阶段
FROM deps as build
COPY . /workspace
RUN cmake -B build -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake
RUN cmake --build build

FROM ubuntu:22.04 as runtime
RUN apt-get update && apt-get install -y libssl1.1
COPY --from=build /workspace/build/myapp /usr/local/bin/
CMD ["myapp"]

总结

包管理器对比

特性vcpkgConanCPMHunter
学习曲线简单中等简单中等
生态系统丰富丰富中等中等
CMake集成优秀优秀原生良好
跨平台优秀优秀良好良好
性能良好优秀快速中等

选择建议

  • 新项目: vcpkg或Conan
  • 简单依赖: CPM.cmake
  • 复杂项目: Conan
  • Windows项目: vcpkg
  • 跨平台: Conan

最佳实践

  • 版本锁定: 使用精确版本号
  • 构建隔离: 避免全局安装
  • 缓存策略: 利用CI缓存加速构建
  • 依赖审计: 定期检查安全漏洞
  • 文档记录: 明确依赖用途和版本要求

未来趋势

  • C++20模块: 改变依赖模型
  • 标准包管理器: C++官方包管理器
  • 构建缓存: 分布式构建缓存
  • 安全性: 包签名和验证

包管理是现代C++开发的基础设施,选择合适的包管理器并建立规范的依赖管理流程对项目成功至关重要。

本站内容仅供学习和研究使用。