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 boostCMake集成
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=missingCMake集成
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=defaultDocker化依赖
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"]总结
包管理器对比
| 特性 | vcpkg | Conan | CPM | Hunter |
|---|---|---|---|---|
| 学习曲线 | 简单 | 中等 | 简单 | 中等 |
| 生态系统 | 丰富 | 丰富 | 中等 | 中等 |
| CMake集成 | 优秀 | 优秀 | 原生 | 良好 |
| 跨平台 | 优秀 | 优秀 | 良好 | 良好 |
| 性能 | 良好 | 优秀 | 快速 | 中等 |
选择建议
- 新项目: vcpkg或Conan
- 简单依赖: CPM.cmake
- 复杂项目: Conan
- Windows项目: vcpkg
- 跨平台: Conan
最佳实践
- 版本锁定: 使用精确版本号
- 构建隔离: 避免全局安装
- 缓存策略: 利用CI缓存加速构建
- 依赖审计: 定期检查安全漏洞
- 文档记录: 明确依赖用途和版本要求
未来趋势
- C++20模块: 改变依赖模型
- 标准包管理器: C++官方包管理器
- 构建缓存: 分布式构建缓存
- 安全性: 包签名和验证
包管理是现代C++开发的基础设施,选择合适的包管理器并建立规范的依赖管理流程对项目成功至关重要。