1. 历史背景与发展历程
Conan是由JFrog公司(以Artifactory二进制仓库管理工具闻名)于2016年推出的开源、跨平台C/C++包管理器。
- 发展背景:C/C++生态长期缺乏统一包管理方案,传统手动方式效率低且依赖关系复杂,不同平台、编译器和配置组合使依赖管理困难。
- 发展历程:
- 2016年:Conan 0.1版本发布,基于Python编写,采用客户端 - 服务器架构。
- 2017年:Conan 1.0正式发布,引入完善配方(recipe)系统和二进制兼容性管理。
- 2019年:ConanCenter成为社区共享包的中心仓库,丰富了可用包。
- 2021年:Conan 2.0开始开发,引入重大架构改进。
- 2023年:Conan 2.0正式发布,改进依赖解析算法、简化配置文件、增强锁文件功能。
2. conan安装
2.1. 通过pip或pipx安装
Conan工具本身是Python开发的,所以可以通过pip或pipx来安装。
2.1.1. pip 安装
1 2 3 4 5 6 7 8 9 10 11
| python3 -m venv ~/conan_env
source ~/conan_env/bin/activate
pip install conan
deactivate
|
说明:
- Ubuntu 23.04+、Debian 12+之后增加了
PEP 668保护机制,为了防止破坏系统的Python环境,需要在虚拟环境下安装。
- 每次使用 conan 需要先激活环境
2.1.2. pipx 安装(推荐)
1 2 3 4 5 6 7 8 9
| sudo apt install pipx pipx ensurepath
pipx install conan
conan --version
|
2.1.3. pipx 与 pip 的区别
| 特性 |
pip |
pipx |
| 用途 |
安装 Python 包(库、框架、工具) |
专门安装和运行 Python 应用(命令行工具) |
| 安装方式 |
直接安装到 Python 环境 |
每个工具独立隔离的虚拟环境 |
| 依赖管理 |
所有包共享同一环境(可能冲突) |
每个工具独立环境,依赖隔离 |
| 主要使用场景 |
开发 Python 项目时安装依赖库 |
安装 Python 编写的命令行工具(如 conan, black, pytest) |
| 命令执行 |
需要手动添加到 PATH 或激活环境 |
自动将命令链接到 PATH,直接可用 |
| 卸载 |
可能遗留依赖,影响其他包 |
完整卸载,不影响其他工具 |
2.2. 通过平台默认的包管理器安装
2.2.1. Ubuntu/Debian
1 2 3 4 5 6 7
| sudo apt update sudo apt upgrade
sudo apt install conan
conan --version
|
2.2.2. macOS
1 2 3 4 5 6
| /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install conan
conan --version
|
2.2.3. Windows
1 2 3 4
| choco install conan
conan --version
|
说明: Chocolatey(choco)是Windows平台的命令行包管理器,类似于Ubuntu的apt或macOS的Homebrew。
3. 核心功能
3.1. 依赖管理
- 自动下载和安装 C/C++ 库依赖
- 处理依赖关系树和版本冲突
- 支持传递依赖(依赖的依赖)
3.2. 多平台支持
- 操作系统:Windows, Linux, macOS, Android, iOS
- 编译器:GCC, Clang, MSVC, MinGW
- CPU架构:x86, x86_64, ARM, ARM64
3.3. 二进制包管理
- 预编译二进制包,避免源码重复编译
- 通过设置(settings)区分不同平台、编译器、构建类型、架构等。
- 支持二进制兼容性检测,自动匹配可用的预编译包。
- 本地缓存机制,加速构建
3.4. 可与多种构建系统集成
- CMake(最常用)
- Visual Studio (MSBuild)
- Makefiles, Autotools
- Meson, Bazel, etc.
3.5. 多仓库支持
- 支持多个远程仓库,可混合使用公共仓库(ConanCenter)和私有仓库。
- 支持JFrog Artifactory、GitLab、自建服务器等作为仓库后端。
3.6. 依赖解析与版本管理
- 支持语义化版本(semver)约束,如
pkg/[>=1.0 <2.0]。
- 支持多种依赖类型:
requires、tool_requires(构建工具依赖)、test_requires。
- 提供锁文件(lockfile)机制,确保可重现的依赖版本。
3.7. 可扩展的配方系统
- 使用Python编写包配方(conanfile.py),可定制包的构建、打包、依赖逻辑。
- 支持生成多种构建系统集成文件(如CMake的
conan_toolchain.cmake、conanbuildinfo.cmake)。
3.8. 虚拟环境管理
- 可创建虚拟运行环境,自动设置PATH、LD_LIBRARY_PATH等环境变量。
- 支持虚拟构建环境,隔离构建工具链。
4. 架构与核心概念
4.1. 核心组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ┌─────────────────────────────────────────────┐ │ Conan 生态系统 │ ├─────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────────┐ │ │ │ Client │────▶│ Remote │ │ │ │ (conan) │ │ Repositories│ │ │ └────┬─────┘ └──────────────┘ │ │ │ │ │ ▼ │ │ ┌──────────┐ ┌──────────────┐ │ │ │ Local │ │ Profiles │ │ │ │ Cache │ │ │ │ │ └──────────┘ └──────────────┘ │ │ │ │ ┌──────────-┐ ┌──────────────┐ │ │ │ Recipes │ │ Generators │ │ │ │(conanfile)│ │ │ │ │ └──────────-┘ └──────────────┘ │ └─────────────────────────────────────────────┘
|
4.2. 重要概念详解
| 概念 |
说明 |
示例 |
| Recipe(配方) |
定义如何获取、构建、打包库 |
conanfile.py |
| Profile(配置) |
定义编译环境设置 |
编译器版本、架构、构建类型 |
| Package(包) |
特定配置下构建的二进制文件 |
openssl/1.1.1 |
| Reference(引用) |
包的完整标识 |
zlib/1.2.11@conan/stable |
| Revision(修订版) |
配方或包的版本 |
da39a3ee5e6b4b0d |
| Channel(通道) |
包的质量标识 |
stable, testing |
5. Conan 文件详解
5.1. conanfile.txt(简单项目)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| [requires]
fmt/10.1.0 spdlog/1.12.0 openssl/3.0.0
[options]
fmt:shared=True openssl:openssl_rand=True
[generators]
CMakeDeps CMakeToolchain VirtualBuildEnv
[imports]
bin, *.dll -> ./bin lib, *.dylib -> ./lib
|
5.2. conanfile.py(高级/创建包)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| from conan import ConanFile from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout from conan.tools.files import copy, get import os
class MyLibraryConan(ConanFile): name = "mylibrary" version = "1.0.0" description = "My awesome C++ library" url = "https://github.com/myuser/mylibrary" license = "MIT" requires = "fmt/10.1.0" settings = "os", "compiler", "build_type", "arch" options = { "shared": [True, False], "fPIC": [True, False] } default_options = { "shared": False, "fPIC": True } exports_sources = "CMakeLists.txt", "src/*", "include/*" def layout(self): cmake_layout(self) def generate(self): tc = CMakeToolchain(self) tc.variables["MY_LIBRARY_VERSION"] = self.version tc.generate() def build(self): cmake = CMake(self) cmake.configure() cmake.build() def package(self): cmake = CMake(self) cmake.install() copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses")) def package_info(self): self.cpp_info.libs = ["mylibrary"] self.cpp_info.includedirs = ["include"] self.cpp_info.libdirs = ["lib"] if self.options.shared: self.cpp_info.defines.append("MYLIBRARY_SHARED")
|
5.3. Profile 文件示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| [settings] os=Linux os_build=Linux arch=x86_64 arch_build=x86_64 compiler=gcc compiler.version=11 compiler.libcxx=libstdc++11 build_type=Release
[options]
*:shared=False
[conf]
tools.cmake.cmaketoolchain:generator=Ninja tools.build:compiler_executables={"cxx": "/usr/bin/g++-11"}
[buildenv]
CC=/usr/bin/gcc-11 CXX=/usr/bin/g++-11
|
6. 常用命令详解
6.1. 包管理命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| conan search "boost*" --remote=conancenter conan search zlib/1.2.11@
conan inspect zlib/1.2.11 conan get zlib/1.2.11 conanfile.py
conan download fmt/10.1.0
conan list conan cache path fmt/10.1.0
conan remove fmt/10.1.0 conan remove "*"
|
6.2. 构建命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| conan install . --build=missing conan install . -s build_type=Debug -s arch=x86_64
conan build .
conan create . user/channel conan create . --build=missing -s build_type=Release
conan export . user/channel
conan upload mylibrary/1.0.0 --remote=myremote
|
6.3. 配置管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| conan profile detect conan profile list conan profile show default conan profile new myprofile --detect conan profile update settings.compiler=gcc myprofile
conan remote list conan remote add myrepo https://myrepo.com conan remote remove myrepo conan remote update myrepo https://newurl.com
conan config home conan config install <url>
|
6.4. 依赖图分析
1 2 3 4 5 6 7 8 9
| conan graph info . --format=html > deps.html conan graph info . --format=dot > deps.dot
conan graph info . --graph=graph.html
conan graph info . --build=missing
|
7. 与 CMake 集成详解
7.1. 项目结构
1 2 3 4 5 6 7
| myproject/ ├── CMakeLists.txt ├── conanfile.txt ├── build/ │ └── (conan install 在这里运行) └── src/ └── main.cpp
|
7.2. CMakeLists.txt 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| cmake_minimum_required(VERSION 3.15) project(MyProject CXX)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(fmt REQUIRED) find_package(spdlog REQUIRED) find_package(OpenSSL REQUIRED)
add_executable(myapp src/main.cpp)
target_link_libraries(myapp PRIVATE fmt::fmt spdlog::spdlog OpenSSL::SSL OpenSSL::Crypto )
target_compile_features(myapp PRIVATE cxx_std_17)
|
7.3. 构建流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| mkdir build && cd build conan install .. --build=missing cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake cmake --build . --config Release
conan install . --build=missing conan build .
conan install . --build=missing cmake --preset conan-default cmake --build --preset conan-default
|
7.4. 多配置构建
1 2 3 4 5 6 7 8 9
| conan install . -s build_type=Debug --build=missing cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug cmake --build . --config Debug
conan install . -s build_type=Release --build=missing cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release cmake --build . --config Release
|
8. 高级功能
8.1. 版本管理
1 2 3 4 5 6 7 8 9 10 11 12 13
| class MyPkg(ConanFile): version = "1.0.0" def set_version(self): with open("VERSION") as f: self.version = f.read().strip() def set_version(self): self.version = os.getenv("PKG_VERSION", "0.0.0")
|
8.2. 条件依赖
1 2 3 4 5 6 7 8 9 10 11 12 13
| class MyPkg(ConanFile): requires = "zlib/1.2.11" def requirements(self): if self.options.with_ssl: self.requires("openssl/3.0.0") if self.settings.os == "Windows": self.requires("winpcap/4.1.3") options = { "with_ssl": [True, False] }
|
8.3. 测试包
1 2 3 4 5 6 7 8 9 10 11 12 13
| from conan import ConanFile from conan.tools.build import can_run
class TestPackage(ConanFile): settings = "os", "arch", "compiler", "build_type" def requirements(self): self.requires(self.tested_reference_str) def test(self): if can_run(self): self.run("test_package", env="conanrun")
|
1 2 3 4 5 6 7 8
| #include <mylibrary.h> #include <iostream>
int main() { std::cout << "Version: " << mylibrary::version() << std::endl; return 0; }
|
8.4. 锁定文件(Lockfiles)
1 2 3 4 5 6 7 8
| conan lock create conanfile.txt --lockfile=conan.lock
conan install . --lockfile=conan.lock
conan lock create conanfile.txt --lockfile=conan.lock --update
|
8.5. 工作空间(Workspace)
1 2 3 4 5 6 7 8 9 10 11 12 13
| workspace: root: . settings: - os - compiler packages: - path: libs/libA - path: libs/libB - path: apps/app1 layout: flat
|
9. 实际应用示例
9.1. 示例1:简单应用使用依赖
conanfile.txt
1 2 3 4 5 6 7
| [requires] fmt/10.1.0 spdlog/1.12.0
[generators] CMakeDeps CMakeToolchain
|
main.cpp
1 2 3 4 5 6 7 8
| #include <fmt/core.h> #include <spdlog/spdlog.h>
int main() { fmt::print("Hello, {}!\n", "Conan"); spdlog::info("Welcome to Conan"); return 0; }
|
构建脚本
1 2 3 4 5 6
| #!/bin/bash mkdir -p build && cd build conan install .. --build=missing cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release cmake --build . ./myapp
|
9.2. 示例2:创建和使用自己的包
创建库
1 2 3 4 5 6 7 8 9
| mkdir mymath && cd mymath
conan create . user/testing
mkdir ../myapp && cd ../myapp
conan install . --build=missing
|
9.3. 示例3:交叉编译
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| cat > android_profile << EOF [settings] os=Android os.api_level=21 arch=armv8 compiler=clang compiler.version=14 build_type=Release
[conf] tools.android:ndk_path=/path/to/android-ndk EOF
conan install . -pr=android_profile --build=missing
|
10. 最佳实践
10.1. 项目结构建议
1 2 3 4 5 6 7 8 9 10 11
| project/ ├── conanfile.py # 根目录配方 ├── CMakeLists.txt ├── cmake/ │ └── conan_toolchain.cmake ├── src/ │ └── ... ├── test_package/ # 测试包 │ ├── conanfile.py │ └── test_package.cpp └── build/ # 构建目录
|
10.2. 性能优化
1 2 3 4 5 6 7 8
| conan install . --build=missing -c tools.build:jobs=8
conan config set tools.build:compiler_cache=ccache
conan remote add my_local http://localhost:8081
|
10.3. 调试技巧
1 2 3 4 5 6 7 8 9 10 11
| conan install . -vvv
conan install . --keep-build
conan graph info . --build=missing
conan inspect fmt/10.1.0 -a=settings -a=options
|
11. 常见问题解决
11.1. 依赖冲突
1 2 3 4 5 6 7 8 9 10
| [requires] boost/[>=1.75 <1.80]
[requires] openssl/1.1.1 curl/7.84.0 [overrides] openssl/1.1.1
|
11.2. 找不到头文件
1 2 3 4 5 6
| find_package(fmt REQUIRED) target_link_libraries(myapp fmt::fmt)
target_include_directories(myapp PRIVATE ${CONAN_INCLUDE_DIRS})
|
11.3. 符号未定义错误
1 2 3 4 5
| target_link_libraries(myapp PRIVATE libA libB)
conan install . -o *:shared=True
|
12. 与其他包管理工具的比较
| 特性 |
Conan |
vcpkg |
Hunter |
CMake FetchContent |
| 跨平台 |
✅ |
✅ |
✅ |
✅ |
| 预编译包 |
✅ |
✅ |
❌ |
❌ |
| 自定义包 |
✅ |
困难 |
✅ |
✅ |
| 多版本共存 |
✅ |
❌ |
有限 |
❌ |
| 企业私有仓库 |
✅ |
有限 |
❌ |
❌ |
| 学习曲线 |
中等 |
低 |
高 |
低 |
Conan 适用于需要精细控制、多版本管理、企业级私有仓库的场景。对于简单项目,vcpkg 或 FetchContent 可能更简单。
13. 相关文档
C/C++包管理工具vcpkg