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 模型。
  • 更推荐 CMakeDepsCMakeToolchain
  • 更严格的 recipe API。
  • 更适合可复现构建和 CI 集成。

如果阅读旧资料,需要注意 cmake_find_packageconan_basic_setup() 等 Conan 1.x 用法已经不是 Conan 2.x 的推荐路径。

包管理、构建系统、依赖管理的关系

Conan 负责依赖解析、下载、构建和包管理;CMake 负责生成项目构建系统;编译器和链接器负责真正生成目标产物。

常见流程是:

1
2
3
conan install . --output-folder=build --build=missing
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
cmake --build build

Conan 的核心概念

  • recipe:描述如何获取源码、配置、构建、打包和导出信息的脚本,通常是 conanfile.py
  • package:由 recipe 生成的二进制包,和平台、架构、编译器、构建类型、选项等有关。
  • profile:描述当前构建环境和目标环境的配置文件。
  • remote:远程包仓库,例如 ConanCenter 或公司私有仓库。
  • cache:本地 Conan 缓存,保存 recipe、源码、构建结果和二进制包。

环境准备

安装 Conan

Conan 是 Python 工具,可以通过 pipxpipuv 等方式安装。下面使用 uv 安装:

1
2
3
4
5
6
apt update && apt install curl -y
curl -LsSf https://astral.sh/uv/install.sh | sh
uv python install cpython-3.14.3-linux-x86_64-gnu
uv tool install pip
uv tool install conan
conan --version

Conan 需要 Python 环境支持。使用 uv tool install conan 可以把 Conan 作为独立命令行工具安装。

初始化默认 profile

首次使用 Conan 时,先生成默认 profile:

1
2
conan profile detect
conan profile show

conan profile detect 会根据本机环境推断默认编译器、系统、架构和构建类型。

检查本机编译环境

重点确认:

  • 编译器名称和版本是否符合预期。
  • compiler.cppstd 是否需要显式指定。
  • build_typeDebug 还是 Release
  • CMake 使用的是 Makefile、Ninja 还是 IDE 生成器。

Conan 本地缓存目录说明

Conan 会把 recipe、源码、构建目录、二进制包等内容存放在本地缓存中。常用命令:

1
2
3
conan cache path
conan list "*"
conan remove "pkg/*" -c

第一个 Conan 项目

创建一个最小 C++ 项目

假设项目结构如下:

1
2
3
4
5
hello-conan/
├── CMakeLists.txt
├── conanfile.txt
└── src/
└── main.cpp

编写 conanfile.txt

conanfile.txt 适合简单消费第三方依赖:

1
2
3
4
5
6
7
[requires]
nlohmann_json/3.11.3
sqlite3/3.48.0

[generators]
CMakeDeps
CMakeToolchain

其中:

  • [requires] 声明项目需要的第三方库。
  • [generators] 声明 Conan 需要生成哪些构建系统辅助文件。

使用 conan install 安装依赖

1
conan install . --output-folder=build --build=missing

常用参数:

  • --output-folder=build:指定 Conan 生成文件输出目录。
  • --build=missing:本地和远程没有匹配二进制包时,允许从源码构建。

使用 CMake 构建项目

1
2
cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
cmake --build build

如果使用 Ninja:

1
2
cmake -S . -B build -G Ninja -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
cmake --build build

运行程序并验证依赖是否生效

构建完成后运行目标程序,确认链接和运行时依赖都正常。如果使用动态库,还需要注意运行时库路径是否正确。

Conan 与 CMake 集成

CMakeToolchain 的作用

CMakeToolchain 会生成 conan_toolchain.cmake,用于把 Conan profile 中的编译器、架构、构建类型、C++ 标准等信息传递给 CMake。

CMakeDeps 的作用

CMakeDeps 会为依赖生成 CMake 查找文件,让项目可以使用:

1
2
find_package(nlohmann_json REQUIRED)
target_link_libraries(app PRIVATE nlohmann_json::nlohmann_json)

find_package() 与 Conan 生成文件

Conan 并不替代 CMake 的 find_package()。它负责生成 CMake 能理解的包配置文件,CMake 再通过 find_package() 找到这些依赖。

CMake Presets 集成

Conan 可以生成或配合 CMake Presets 使用。使用 presets 后,构建命令可以简化为:

1
2
cmake --preset conan-release
cmake --build --preset conan-release

Profile 详解

Profile 是什么

Profile 是 Conan 构建配置的核心,用来描述当前项目要在什么环境下构建,以及构建出来的包面向什么目标环境。

settings:系统、架构、编译器、构建类型

典型 settings:

1
2
3
4
5
6
7
8
[settings]
os=Linux
arch=x86_64
compiler=gcc
compiler.version=13
compiler.libcxx=libstdc++11
compiler.cppstd=20
build_type=Release

options:控制依赖构建选项

Options 用来控制包的可变行为,例如是否构建动态库:

1
2
3
[options]
*:shared=False
sqlite3/*:shared=True

conf:工具链和构建配置

conf 用于配置 Conan 工具链和辅助工具行为,例如指定 CMake 生成器:

1
2
[conf]
tools.cmake.cmaketoolchain:generator=Ninja

Host Profile 与 Build Profile

Conan 2.x 区分:

  • build profile:构建工具运行所在环境。
  • host profile:最终产物运行所在环境。

普通本机构建时二者通常一致;交叉编译时二者不同。

Debug / Release 多配置管理

建议为不同构建类型准备独立 profile 或明确传参:

1
2
conan install . -s build_type=Debug --output-folder=build-debug --build=missing
conan install . -s build_type=Release --output-folder=build-release --build=missing

交叉编译 Profile 示例

交叉编译时需要分别指定 build 和 host:

1
conan install . -pr:b=default -pr:h=linux-armv8 --build=missing

依赖管理

添加第三方依赖

conanfile.txt 中添加:

1
2
3
[requires]
fmt/11.0.2
spdlog/1.14.1

conanfile.py 中添加:

1
2
3
def requirements(self):
self.requires("fmt/11.0.2")
self.requires("spdlog/1.14.1")

固定版本与版本范围

生产项目建议优先固定版本,避免上游变化影响构建。版本范围适合内部库快速迭代,但需要配合 lockfile。

传递依赖

如果 A 依赖 B,项目依赖 A 时,Conan 会自动解析 B。遇到版本冲突时,需要显式 override 或调整依赖版本。

依赖冲突与版本覆盖

当多个依赖要求同一个库的不同版本时,Conan 会尝试解析依赖图。必要时可以在上层项目强制指定版本。

requirestool_requires

  • requires:目标程序链接或运行所需依赖。
  • tool_requires:构建过程中使用的工具,例如 protobuf 编译器、代码生成器、CMake、Ninja。

静态库与动态库切换

常见方式是在 profile 或命令行中设置:

1
2
conan install . -o "*:shared=True" --build=missing
conan install . -o "*:shared=False" --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 通常会影响二进制兼容性:

  • os
  • arch
  • compiler
  • compiler.version
  • compiler.libcxx
  • build_type

options 如何影响二进制包

例如 shared=Trueshared=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
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
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout


class MyProjectConan(ConanFile):
name = "mytestproj"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
options = {"shared": [True, False], "fPIC": [True, False]}
default_options = {"shared": False, "fPIC": True}

def requirements(self):
self.requires("nlohmann_json/3.11.3")
self.requires("sqlite3/3.48.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()

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
2
3
4
5
6
from conan.tools.files import copy
import os

def package(self):
copy(self, "*.h", src=os.path.join(self.source_folder, "include"), dst=os.path.join(self.package_folder, "include"))
copy(self, "*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)

Remote 与私有仓库

ConanCenter 的作用

ConanCenter 是官方公共包仓库,提供大量开源 C/C++ 库的 recipe 和二进制包。

添加和管理 remote

1
2
3
conan remote list
conan remote add company https://conan.example.com
conan remote remove company

登录私有仓库

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
2
conan lock create conanfile.py --lockfile-out=conan.lock
conan install . --lockfile=conan.lock --build=missing

固定依赖版本

生产项目建议在主干或发布分支固定依赖版本,减少隐式升级风险。

团队共享 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 中可以使用 pipxpipuv 安装 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::filesystemboost::system。自定义包也可以在 package_info() 中定义组件。

editable 开发模式

editable 模式适合本地同时开发多个库,让消费者直接使用源码目录中的库,而不是缓存中的包。

1
2
3
conan editable add . mylib/0.1
conan editable list
conan editable remove 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-debugbuild-release 两个目录。

静态库和动态库链接问题

检查 *:shared、目标库导出的链接依赖、运行时库路径,以及 Windows 下的 .dll 复制问题。

ABI 不兼容问题

重点检查编译器版本、C++ 标准库 ABI、compiler.libcxx、运行时库和编译选项。

编译器版本不匹配问题

Conan profile 中的编译器版本必须和实际使用的编译器一致,否则可能找不到二进制包或产生 ABI 风险。

本地缓存清理与重建

常用命令:

1
2
3
conan remove "pkg/*" -c
conan remove "*" -c
conan cache clean

清理缓存前要确认是否有未上传的内部包。

实战项目

使用 Conan 管理一个 CLI 工具项目

适合练习 conanfile.txtCMakeDepsCMakeToolchain 和基础 CMake 集成。

使用 Conan 管理一个 CMake 库项目

适合练习 conanfile.pylayout()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 newconan profile update 创建、修改 profile。
  • 使用 cmakecmake_find_packagecmake_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
2
python3 -m pip install "conan<2"
conan --version

如果本机同时维护 Conan 1.x 和 Conan 2.x 项目,建议使用虚拟环境、pipx 或容器隔离不同版本。

初始化 profile

Conan 1.x 中常用 profile new 生成默认 profile:

1
2
conan profile new default --detect
conan profile show default

修改 profile 中的配置:

1
2
3
conan profile update settings.compiler.libcxx=libstdc++11 default
conan profile update settings.compiler.cppstd=17 default
conan profile update settings.build_type=Release default

也可以直接编辑 profile 文件:

1
conan profile path default

消费第三方依赖的常用流程

最小 conanfile.txt 示例:

1
2
3
4
5
[requires]
fmt/8.1.1

[generators]
cmake

安装依赖:

1
2
3
4
5
mkdir build
cd build
conan install .. --build=missing
cmake ..
cmake --build .

Conan 1.x 的 cmake generator 会生成 conanbuildinfo.cmake,CMakeLists.txt 中通常这样使用:

1
2
3
4
5
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()

add_executable(app src/main.cpp)
target_link_libraries(app ${CONAN_LIBS})

使用 cmake_find_package 集成 CMake

如果希望使用 CMake 原生的 find_package(),Conan 1.x 常用 cmake_find_package

1
2
3
4
5
[requires]
fmt/8.1.1

[generators]
cmake_find_package

安装和构建:

1
2
3
conan install . -if build --build=missing
cmake -S . -B build -DCMAKE_MODULE_PATH=build
cmake --build build

CMakeLists.txt 中使用:

1
2
3
4
find_package(fmt REQUIRED)

add_executable(app src/main.cpp)
target_link_libraries(app fmt::fmt)

多配置生成器,例如 Visual Studio,常用 cmake_find_package_multi

1
2
[generators]
cmake_find_package_multi

使用 conanfile.py 管理依赖

Conan 1.x 的 conanfile.py 示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from conans import ConanFile, CMake


class AppConan(ConanFile):
name = "app"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
generators = "cmake"

def requirements(self):
self.requires("fmt/8.1.1")

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

执行:

1
2
conan install . -if build --build=missing
conan build . -bf build

创建自己的 Conan 1.x 包

典型流程:

1
2
3
conan new hello/0.1 -t
conan create . demo/testing
conan search hello/0.1@demo/testing

Conan 1.x 常见包引用格式:

1
hello/0.1@demo/testing

其中:

  • hello 是包名。
  • 0.1 是版本。
  • demo 是 user。
  • testing 是 channel。

上传和下载私有包

管理 remote:

1
2
3
conan remote list
conan remote add company https://conan.example.com
conan user -r company -p <password> <username>

上传包:

1
conan upload hello/0.1@demo/testing -r company --all

下载或安装依赖时指定 remote:

1
conan install . -r company --build=missing

搜索、查看和清理本地缓存

搜索本地或远程包:

1
2
3
conan search
conan search "fmt/*"
conan search "fmt/*" -r conancenter

查看包信息:

1
2
conan inspect fmt/8.1.1
conan info .

清理缓存:

1
2
conan remove "fmt/*" -f
conan remove "*" -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() 不推荐,使用 CMakeToolchainCMakeDeps
创建包引用 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()CMakeToolchainCMakeDeps
  • 团队希望统一到当前官方主线文档。

迁移时不要直接全量替换。更稳妥的做法是先固定 Conan 1.x 版本和 lockfile,再逐步迁移 generator、profile、recipe API 和 CI 流程。

参考