Conan 使用手册
- Conan 是一个开源的、跨平台的、去中心化的 C++ 包管理器,旨在简化 C++ 项目的依赖管理和项目构建过程。
- Conan 允许开发者轻松地查找、安装和管理第三方库和工具,通过它可以安装、解决构建依赖,更重要的是可以直接集成到构建系统中。
- 本文记录了从零开始上手 Conan 的过程,帮助更多 C++ 开发者了解和上手这一现代化的包管理器,从依赖配置的苦海中解脱出来。
Conan 入门认知
Conan 解决什么问题
C++ 项目通常会遇到这些依赖管理问题:
- 不同平台、编译器、构建类型下需要不同的二进制库。
- 第三方库本身还依赖其他库,手动维护传递依赖很麻烦。
- Debug、Release、静态库、动态库、运行时库等配置容易混用。
- 团队和 CI 环境需要复用一致的依赖版本和构建配置。
Conan 的目标是把这些问题统一到包管理模型中:通过 recipe 描述如何构建包,通过 profile 描述构建环境,通过 remote 分发二进制包。
Conan 1.x 与 Conan 2.x 的区别
新项目建议直接学习 Conan 2.x。Conan 2.x 相比 Conan 1.x 更强调:
- 更清晰的 host/build 双 profile 模型。
- 更推荐
CMakeDeps和CMakeToolchain。 - 更严格的 recipe API。
- 更适合可复现构建和 CI 集成。
如果阅读旧资料,需要注意 cmake_find_package、conan_basic_setup() 等 Conan
1.x 用法已经不是 Conan 2.x 的推荐路径。
包管理、构建系统、依赖管理的关系
Conan 负责依赖解析、下载、构建和包管理;CMake 负责生成项目构建系统;编译器和链接器负责真正生成目标产物。
常见流程是:
1 | conan install . --output-folder=build --build=missing |
Conan 的核心概念
recipe:描述如何获取源码、配置、构建、打包和导出信息的脚本,通常是conanfile.py。package:由 recipe 生成的二进制包,和平台、架构、编译器、构建类型、选项等有关。profile:描述当前构建环境和目标环境的配置文件。remote:远程包仓库,例如 ConanCenter 或公司私有仓库。cache:本地 Conan 缓存,保存 recipe、源码、构建结果和二进制包。
环境准备
安装 Conan
Conan 是 Python 工具,可以通过 pipx、pip、uv 等方式安装。下面使用 uv 安装:
1 | apt update && apt install curl -y |
Conan 需要 Python 环境支持。使用
uv tool install conan可以把 Conan 作为独立命令行工具安装。
初始化默认 profile
首次使用 Conan 时,先生成默认 profile:
1 | conan profile detect |
conan profile detect 会根据本机环境推断默认编译器、系统、架构和构建类型。
检查本机编译环境
重点确认:
- 编译器名称和版本是否符合预期。
compiler.cppstd是否需要显式指定。build_type是Debug还是Release。- CMake 使用的是 Makefile、Ninja 还是 IDE 生成器。
Conan 本地缓存目录说明
Conan 会把 recipe、源码、构建目录、二进制包等内容存放在本地缓存中。常用命令:
1 | conan cache path |
第一个 Conan 项目
创建一个最小 C++ 项目
假设项目结构如下:
1 | hello-conan/ |
编写 conanfile.txt
conanfile.txt 适合简单消费第三方依赖:
1 | [requires] |
其中:
[requires]声明项目需要的第三方库。[generators]声明 Conan 需要生成哪些构建系统辅助文件。
使用 conan install 安装依赖
1 | conan install . --output-folder=build --build=missing |
常用参数:
--output-folder=build:指定 Conan 生成文件输出目录。--build=missing:本地和远程没有匹配二进制包时,允许从源码构建。
使用 CMake 构建项目
1 | cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake |
如果使用 Ninja:
1 | cmake -S . -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake |
运行程序并验证依赖是否生效
构建完成后运行目标程序,确认链接和运行时依赖都正常。如果使用动态库,还需要注意运行时库路径是否正确。
Conan 与 CMake 集成
CMakeToolchain 的作用
CMakeToolchain 会生成 conan_toolchain.cmake,用于把 Conan
profile 中的编译器、架构、构建类型、C++ 标准等信息传递给 CMake。
CMakeDeps 的作用
CMakeDeps 会为依赖生成 CMake 查找文件,让项目可以使用:
1 | find_package(nlohmann_json REQUIRED) |
find_package() 与 Conan 生成文件
Conan 并不替代 CMake 的
find_package()。它负责生成 CMake 能理解的包配置文件,CMake 再通过 find_package()
找到这些依赖。
CMake Presets 集成
Conan 可以生成或配合 CMake Presets 使用。使用 presets 后,构建命令可以简化为:
1 | cmake --preset conan-release |
Profile 详解
Profile 是什么
Profile 是 Conan 构建配置的核心,用来描述当前项目要在什么环境下构建,以及构建出来的包面向什么目标环境。
settings:系统、架构、编译器、构建类型
典型 settings:
1 | [settings] |
options:控制依赖构建选项
Options 用来控制包的可变行为,例如是否构建动态库:
1 | [options] |
conf:工具链和构建配置
conf 用于配置 Conan 工具链和辅助工具行为,例如指定 CMake 生成器:
1 | [conf] |
Host Profile 与 Build Profile
Conan 2.x 区分:
- build profile:构建工具运行所在环境。
- host profile:最终产物运行所在环境。
普通本机构建时二者通常一致;交叉编译时二者不同。
Debug / Release 多配置管理
建议为不同构建类型准备独立 profile 或明确传参:
1 | conan install . -s build_type=Debug --output-folder=build-debug --build=missing |
交叉编译 Profile 示例
交叉编译时需要分别指定 build 和 host:
1 | conan install . -pr:b=default -pr:h=linux-armv8 --build=missing |
依赖管理
添加第三方依赖
在 conanfile.txt 中添加:
1 | [requires] |
在 conanfile.py 中添加:
1 | def requirements(self): |
固定版本与版本范围
生产项目建议优先固定版本,避免上游变化影响构建。版本范围适合内部库快速迭代,但需要配合 lockfile。
传递依赖
如果 A 依赖 B,项目依赖 A 时,Conan 会自动解析 B。遇到版本冲突时,需要显式 override 或调整依赖版本。
依赖冲突与版本覆盖
当多个依赖要求同一个库的不同版本时,Conan 会尝试解析依赖图。必要时可以在上层项目强制指定版本。
requires 与 tool_requires
requires:目标程序链接或运行所需依赖。tool_requires:构建过程中使用的工具,例如 protobuf 编译器、代码生成器、CMake、Ninja。
静态库与动态库切换
常见方式是在 profile 或命令行中设置:
1 | conan install . -o "*:shared=True" --build=missing |
Conan 二进制模型
Source Recipe 与 Binary Package 的区别
同一个 recipe 可以在不同配置下生成多个 binary package。例如同一个 zlib/1.3.1
可以生成 Linux/GCC/Release/x86_64 和 Windows/MSVC/Debug/x86_64 两个不同二进制包。
Package ID 是什么
Package ID 是 Conan 用来区分二进制包的标识。它由 settings、options、依赖信息等共同决定。
settings 如何影响二进制包
这些 settings 通常会影响二进制兼容性:
osarchcompilercompiler.versioncompiler.libcxxbuild_type
options 如何影响二进制包
例如 shared=True 和 shared=False 通常会生成不同 package
ID,因为动态库和静态库的产物不同。
--build=missing 的行为
--build=missing 表示:当本地缓存和远程仓库都没有匹配当前 package
ID 的二进制包时,Conan 可以使用 recipe 从源码构建。
为什么会出现 missing binary
常见原因:
- 当前 profile 和远程已有包的 profile 不一致。
- 编译器版本不同。
- Debug/Release 不同。
- options 不同。
- 远程仓库没有上传该配置的二进制包。
编写自己的 Conan 包
从 conanfile.txt 过渡到 conanfile.py
conanfile.txt 适合简单消费依赖;conanfile.py
适合需要条件逻辑、打包、导出组件、处理构建过程的项目。
conanfile.py 基本结构
1 | from conan import ConanFile |
requirements()、layout()、generate()
requirements():声明运行或链接依赖。layout():定义源码、构建目录、生成文件目录的布局。generate():生成 CMake、环境变量、依赖查找文件等辅助文件。
build()、package()、package_info()
build():执行构建。package():把头文件、库文件、资源文件复制到包目录。package_info():声明消费者需要链接的库、组件、CMake target 等信息。
使用 conan create 创建包
1 | conan create . --build=missing |
conan create 会把当前 recipe 导出到本地缓存,并构建出一个可被其他项目消费的包。
编写 test_package
test_package
用于验证包能否被外部项目正常消费。它通常包含一个最小 C++ 程序和 CMake 项目。
打包头文件、库文件和资源文件
常见做法是在 package() 中复制:
1 | from conan.tools.files import copy |
Remote 与私有仓库
ConanCenter 的作用
ConanCenter 是官方公共包仓库,提供大量开源 C/C++ 库的 recipe 和二进制包。
添加和管理 remote
1 | conan remote list |
登录私有仓库
1 | conan remote login company <username> |
密码或 token 不建议写入脚本,应通过 CI secret 或本机安全输入传入。
上传包
1 | conan upload "mytestproj/0.1" -r=company --confirm |
下载和复用二进制包
消费端执行 conan install
时,如果本地缓存没有匹配包,Conan 会从配置的 remote 查找并下载。
企业内部包命名规范
建议统一:
- 包名使用小写和连字符。
- 版本遵循语义化版本或公司内部版本规则。
- 内部库和第三方库镜像使用不同 namespace 或 remote。
版本管理与可复现构建
Recipe Revision 与 Package Revision
Conan 不只关心包名和版本,也关心 recipe 内容和二进制包内容的修订。recipe 改变后,即使版本号不变,也可能产生新的 revision。
Lockfile 的作用
Lockfile 用来锁定依赖图,确保后续构建使用相同版本和 revision。
1 | conan lock create conanfile.py --lockfile-out=conan.lock |
固定依赖版本
生产项目建议在主干或发布分支固定依赖版本,减少隐式升级风险。
团队共享 Conan 配置
可以通过 conan config install 分发统一配置:
1 | conan config install https://example.com/company-conan-config.git |
共享内容通常包括 profiles、remotes、settings、global.conf 等。
CI 中保证构建一致性
CI 中应明确:
- Conan 版本。
- profile 内容。
- remote 顺序。
- lockfile。
- 是否允许
--build=missing。
CI/CD 集成
CI 中安装 Conan
CI 中可以使用 pipx、pip 或 uv 安装 Conan,并固定 Conan 主版本。
构建矩阵设计
常见构建矩阵:
- 操作系统:Linux、Windows、macOS。
- 编译器:GCC、Clang、MSVC。
- 构建类型:Debug、Release。
- 链接方式:shared、static。
缓存 Conan 包
CI 可以缓存 Conan 本地目录以减少下载和重复构建时间,但需要注意缓存 key 要包含 profile、lockfile 和 Conan 版本。
缺包时自动构建
内部库可以在 CI 中执行:
1 | conan create . --build=missing |
构建成功后上传私有仓库
1 | conan upload "mytestproj/0.1" -r=company --confirm |
消费端只下载二进制包
对于应用项目,CI 可以禁止本地源码构建依赖,确保只使用已经验证过的二进制包。
高级场景
交叉编译
交叉编译重点是区分 build profile 和 host profile,并确保工具链文件、sysroot、编译器路径、目标平台 ABI 配置一致。
Android / iOS / Embedded 场景
移动端和嵌入式场景通常需要自定义 profile,并在 conf 中设置 CMake
toolchain、sysroot 或 SDK 路径。
多组件包
一个包可以导出多个组件,例如 boost::filesystem、boost::system。自定义包也可以在
package_info() 中定义组件。
editable 开发模式
editable
模式适合本地同时开发多个库,让消费者直接使用源码目录中的库,而不是缓存中的包。
1 | conan editable add . mylib/0.1 |
Monorepo 中使用 Conan
Monorepo 可以把公共依赖交给 Conan,把仓库内部模块交给 CMake target 或 Conan editable 模式,避免每次修改都重新打包。
自定义工具链和构建系统
如果项目不是 CMake,也可以使用 Conan 生成依赖信息,然后和 Meson、MSBuild、Autotools 或自定义构建脚本集成。
常见问题排查
missing binary 问题
先检查当前 profile 和远程已有包是否匹配,再决定是修改配置、上传对应二进制包,还是使用
--build=missing 从源码构建。
find_package 找不到包
排查方向:
- 是否使用了
CMakeDeps。 - 是否执行了
conan install。 - CMake 是否使用了 Conan 生成目录。
- 包导出的 CMake 名称是否和
find_package()一致。
Debug / Release 混用问题
Debug 和 Release 产物不要混放在同一个构建目录。推荐使用 build-debug 和 build-release
两个目录。
静态库和动态库链接问题
检查 *:shared、目标库导出的链接依赖、运行时库路径,以及 Windows 下的 .dll 复制问题。
ABI 不兼容问题
重点检查编译器版本、C++ 标准库 ABI、compiler.libcxx、运行时库和编译选项。
编译器版本不匹配问题
Conan profile 中的编译器版本必须和实际使用的编译器一致,否则可能找不到二进制包或产生 ABI 风险。
本地缓存清理与重建
常用命令:
1 | conan remove "pkg/*" -c |
清理缓存前要确认是否有未上传的内部包。
实战项目
使用 Conan 管理一个 CLI 工具项目
适合练习 conanfile.txt、CMakeDeps、CMakeToolchain 和基础 CMake 集成。
使用 Conan 管理一个 CMake 库项目
适合练习 conanfile.py、layout()、generate()、build()。
打包自己的公共库
适合练习 package()、package_info()、test_package 和 package id。
上传到私有仓库
适合练习 remote 登录、权限、上传、二进制复用。
在另一个项目中消费该库
最终目标是让另一个项目只通过 requires 声明依赖,并从 remote 下载可复用二进制包。
Conan 1.x 常用流程和命令
Conan 1.x 的典型使用场景
Conan 1.x 仍然常见于老项目、历史 CI、企业内部私有包仓库和旧版 CMake 集成中。新项目建议优先使用 Conan 2.x,但维护旧项目时需要能看懂 Conan 1.x 的流程和命令。
Conan 1.x 常见特征:
- 使用
conan profile new和conan profile update创建、修改 profile。 - 使用
cmake、cmake_find_package、cmake_find_package_multi等旧 generator。 - CMake 项目中经常出现
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)和conan_basic_setup()。 - 包引用经常使用
name/version@user/channel格式。
安装和版本检查
安装 Conan 1.x 时需要显式固定版本,避免装到 Conan 2.x:
1 | python3 -m pip install "conan<2" |
如果本机同时维护 Conan 1.x 和 Conan 2.x 项目,建议使用虚拟环境、pipx
或容器隔离不同版本。
初始化 profile
Conan 1.x 中常用 profile new 生成默认 profile:
1 | conan profile new default --detect |
修改 profile 中的配置:
1 | conan profile update settings.compiler.libcxx=libstdc++11 default |
也可以直接编辑 profile 文件:
1 | conan profile path default |
消费第三方依赖的常用流程
最小 conanfile.txt 示例:
1 | [requires] |
安装依赖:
1 | mkdir build |
Conan 1.x 的 cmake generator 会生成
conanbuildinfo.cmake,CMakeLists.txt 中通常这样使用:
1 | include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) |
使用 cmake_find_package 集成 CMake
如果希望使用 CMake 原生的 find_package(),Conan 1.x 常用 cmake_find_package:
1 | [requires] |
安装和构建:
1 | conan install . -if build --build=missing |
CMakeLists.txt 中使用:
1 | find_package(fmt REQUIRED) |
多配置生成器,例如 Visual Studio,常用 cmake_find_package_multi:
1 | [generators] |
使用 conanfile.py 管理依赖
Conan 1.x 的 conanfile.py 示例:
1 | from conans import ConanFile, CMake |
执行:
1 | conan install . -if build --build=missing |
创建自己的 Conan 1.x 包
典型流程:
1 | conan new hello/0.1 -t |
Conan 1.x 常见包引用格式:
1 | hello/0.1@demo/testing |
其中:
hello是包名。0.1是版本。demo是 user。testing是 channel。
上传和下载私有包
管理 remote:
1 | conan remote list |
上传包:
1 | conan upload hello/0.1@demo/testing -r company --all |
下载或安装依赖时指定 remote:
1 | conan install . -r company --build=missing |
搜索、查看和清理本地缓存
搜索本地或远程包:
1 | conan search |
查看包信息:
1 | conan inspect fmt/8.1.1 |
清理缓存:
1 | conan remove "fmt/*" -f |
常用命令速查
| 场景 | Conan 1.x 命令 |
|---|---|
| 查看版本 | conan --version |
| 创建 profile | conan profile new default --detect |
| 查看 profile | conan profile show default |
| 修改 profile | conan profile update settings.compiler.libcxx=libstdc++11 default |
| 安装依赖 | conan install . --build=missing |
| 指定安装目录 | conan install . -if build --build=missing |
| 指定构建类型 | conan install . -s build_type=Debug --build=missing |
| 指定 option | conan install . -o "*:shared=True" --build=missing |
| 构建当前项目 | conan build . -bf build |
| 创建包 | conan create . user/channel |
| 搜索包 | conan search "pkg/*" -r conancenter |
| 添加 remote | conan remote add company https://conan.example.com |
| 登录 remote | conan user -r company -p <password> <username> |
| 上传包 | conan upload "pkg/version@user/channel" -r company --all |
| 删除缓存 | conan remove "pkg/*" -f |
Conan 1.x 和 Conan 2.x 命令差异速查
| 任务 | Conan 1.x | Conan 2.x |
|---|---|---|
| 检测 profile | conan profile new default --detect |
conan profile detect |
| 查看 profile | conan profile show default |
conan profile show |
| 安装输出目录 | conan install . -if build |
conan install . --output-folder=build |
| CMake 旧集成 | cmake generator + conan_basic_setup() |
不推荐,使用 CMakeToolchain 和 CMakeDeps |
| 创建包引用 | conan create . user/channel |
conan create . |
| 上传二进制包 | conan upload ref -r remote --all |
conan upload ref -r=remote --confirm |
| 登录 remote | conan user -r remote user |
conan remote login remote user |
| 清理缓存 | conan remove "pkg/*" -f |
conan remove "pkg/*" -c |
什么时候应该迁移到 Conan 2.x
如果满足以下条件,建议优先规划迁移:
- 项目仍在长期维护,依赖和 CI 会持续演进。
- 需要更清晰的交叉编译模型。
- 新增包希望使用 Conan 2.x 的
layout()、generate()、CMakeToolchain、CMakeDeps。 - 团队希望统一到当前官方主线文档。
迁移时不要直接全量替换。更稳妥的做法是先固定 Conan 1.x 版本和 lockfile,再逐步迁移 generator、profile、recipe API 和 CI 流程。