Conan C/C++ 包管理器介绍

发布时间: 更新时间: 总字数:3810 阅读时间:8m 作者:IP:上海 网址

Conan 2 是 Conan C/C++ 包管理器 的最新主要版本(于 2023 年初正式发布)。Conan 是目前 C 和 C++ 生态中最流行、最强大的开源和去中心化包管理工具,而 Conan 2.0 是对其进行的一次大规模架构重构和升级,旨在解决 Conan 1.x 遗留的痛点,提供更现代、更快速、更一致的依赖管理体验。本文是关于 Conan 2 的详细介绍及其核心亮点。

什么是 Conan?

C/C++ 语言长期以来缺乏像 Python 的 pip、Node.js 的 npm 或 Rust 的 cargo 那样统一的包管理器。Conan 的出现填补了这一空白。

  • 跨平台:支持 Windows、Linux、macOS,甚至嵌入式系统和交叉编译。
  • 二进制管理:不仅仅是下载源码编译,Conan 原生支持管理预编译的二进制文件(按不同的编译器、架构、操作系统、Release/Debug 组合)。
  • 去中心化:你可以使用官方的中央仓库(ConanCenter),也可以在企业内部轻松搭建私有仓库(如基于 JFrog Artifactory)。

Conan 2.0 的核心改进与新特性

Conan 1.x 在多年发展中积累了大量的“技术债”。Conan 2 移除了所有过时的特性,进行了全面的现代化升级:

  • 全新的图解析器 (Graph Model): 重新设计了依赖图的解析方式,能够更精确、更智能地处理复杂的依赖关系(如菱形依赖冲突)。它严格区分了构建时依赖(tool_requires,如 CMake、Ninja)和运行时/链接时依赖(requires,如 fmt, zlib)。
  • 无缝且透明的构建系统集成: Conan 2 放弃了老旧的生成器(Generators),全面拥抱“透明集成”。例如,在 CMake 中,它通过 CMakeToolchain 和 CMakeDeps 生成标准的 CMake 工具链文件和 Config 文件。这意味着你的 CMake 代码不需要为了适配 Conan 写任何特定的“Conan 魔法代码”,只要标准的 find_package() 即可。
  • 全新的 Lockfile(锁文件)系统: 锁文件机制被彻底重写。Conan 2 的 lockfiles 更加灵活且稳定,能够完美保障在不同的 CI/CD 环境、不同的开发者电脑上拉取到完全一致的依赖版本和图结构,实现真正的可重现构建 (Reproducible Builds)。
  • 自定义命令 (Custom Commands): Conan 2 提供了全新的、清晰的 Python Public API。开发者可以极其方便地编写自己的 Conan CLI 插件和自定义命令,以适应复杂的企业级内部工作流。
  • 配置和 Profile 改进: 对 profile(用于定义编译器版本、架构等环境信息)进行了增强,支持 Jinja2 模板渲染,配置起来更加动态和灵活。

Conan2 服务端搭建

  • JFrog Artifactory
  • GitLab / Gitea 内置 Package Registry
  • Sonatype Nexus Repository

Conan 核心概念总结表

核心概念 英文术语 描述与含义 作用 / 应用场景
配方 Recipe
(conanfile.py / conanfile.txt)
定义如何获取源码、构建、打包和消费某个库的 Python 脚本或文本文件。 它是包的“图纸”。conanfile.txt 常用于消费包的项目;conanfile.py 常用于创建包的项目。
包引用 Reference
(e.g., pkg/1.0)
包在全局的唯一名称和版本号。完整格式为 name/version[@user/channel]。 用于在依赖树或命令行中精确指定要寻找的包(如 conan install --requires="zlib/1.2.13")。
包标识符 Package ID (核心) 一个基于 Settings、Options 和 依赖项 计算出的哈希值字符串(如 2a4b...)。 用于区分同一配方下不同的二进制产物。例如 zlib/1.2.13 会针对 Windows/Linux 或 Debug/Release 生成不同的二进制包,它们拥有同一个 Reference,但拥有不同的 Package ID。
环境设置 Settings 全局范围生效的构建环境配置,如 os, compiler, build_type (Debug/Release), arch。 决定生成的二进制架构和平台兼容性。它是决定 Package ID 的最主要因素。通常不写死在代码里,而是由外部环境决定。
包选项 Options 特定于某个特定包的编译开关,如 shared=True/False, with_openssl=True。 控制包内部的特性。比如你可以选择静态链接还是动态链接该库。它同样会影响生成的 Package ID。
配置文件 Profile 一个纯文本文件,里面预先写好了特定的一套 Settings、Options 和环境变量配置。 方便开发者在不同的编译环境间一键切换。如 conan install . -pr default(默认配置)或 -pr cross_arm(交叉编译配置)。
生成器 Generators Conan 插件模块,负责将依赖树的库路径、包含路径等信息翻译成特定构建系统能懂的文件。 桥接 Conan 和构建系统(如 CMake)。Conan 2.x 中最常用的是 CMakeDeps(生成 .cmake 依赖文件)和 CMakeToolchain(生成工具链文件)。
依赖项 Requirements /
Tool Requires
声明项目所依赖的其他包。
分为普通依赖(运行时需要)和工具依赖(仅构建时需要,如 CMake, Ninja)。
构建项目的依赖图(Dependency Graph)。修改依赖库的版本也会改变当前包的 Package ID。
本地缓存 Local Cache 开发者本机上的隐藏目录(通常为 ~/.conan2),用于集中存储所有下载的 Recipe 和二进制包。 本机统一的依赖池。不同项目依赖同一个库的相同版本时,直接从缓存读取,避免重复下载或编译。
远程仓库 Remote 存储并分发 Conan 包的远端服务器(如官方的 ConanCenter,或企业内部的 Artifactory)。 团队协作的核心。开发者可以将编译好的带有特定 Package ID 的二进制包上传,其他人直接下载即可,无需重编。
版本修订 Revisions
(RREV / PREV)
记录同一版本号下,配方代码(RREV)或二进制内容(PREV)变更的哈希记录。 用于实现绝对可复现的构建。防止远程仓库中某个人偷偷覆盖了 pkg/1.0 的内容导致构建意外破坏。

核心逻辑串联:它们是如何协同工作的?

为了更好理解,可以把 Conan 想象成一个工厂,以上概念的关系如下:

  1. Recipe(配方) 告诉 Conan 某本书(库)应该怎么印。
  2. 开发者在 Profile(配置文件) 中定义了当前的 Settings(操作系统/编译器)。
  3. 结合用户指定的 Options(比如是否加精装 shared=True) 和 Requirements(前置依赖)。
  4. Conan 将上述三者(Settings + Options + Requirements)做一次哈希计算,得出一个唯一的 Package ID。
  5. Conan 拿着这个 Package ID 去 Local Cache(本地缓存) 里找。
  6. 如果缓存没有,再去 Remote(远程仓库) 找这个特定的二进制包。
  7. 如果依然没有,Conan 就会根据 Recipe 当场从源码编译出一个产物,并打上这个 Package ID 存入缓存。
  8. 最后,Generators(生成器) 把这些库在缓存中的绝对路径提取出来,写成 CMakeLists.txt 能读懂的文件,完成与项目的对接。

其他

  • 每个 Conan 包内部都有一个 conanmanifest.txt 文件,记录了所有文件的 MD5 哈希值

Conan 命令行工具

以下是 Conan 2 常用的客户端命令表格总结,按照使用场景进行了分类:

核心依赖消费与包构建 (Dependencies & Building)

这是日常开发项目时最常用的基础命令组合。

命令 常用参数/示例 功能描述
conan install conan install . --build=missing 安装依赖:根据 conanfile.py/.txt 解析并安装所需包。同时生成所选构建系统的工具链文件(如 CMakeDeps 和 CMakeToolchain)。
conan build conan build . 本地构建:在本地执行构建操作,这会直接触发并调用 conanfile.py 中定义的 build() 方法。
conan create conan create . -pr default 创建包:完整的从源码拉取、构建二进制到导出的流程,将其打包为正式的 Conan 包并存入本地缓存中,供其他模块引用。
conan export conan export . 导出配方:仅将当前的 conanfile.py(Recipe 配方)导出并复制到本地缓存,不执行源码下载或编译构建。
conan export-pkg conan export-pkg . 导出预编译包:利用本地已经编译好的二进制文件与 Recipe,直接生成一个 Conan 包,跳过代码构建过程。
conan source conan source . 获取源码:仅触发 conanfile.py 中的 source() 方法(例如执行 Git clone 或是下载提取压缩包)。
conan new conan new cmake_lib -d name=foo -d version=1.0 生成项目模板:根据内置模板快速生成新包的基础骨架文件,包括 conanfile.py 和对应的构建脚本(如 CMakeLists.txt)。

包查询、信息展示与图分析 (Query, Info & Graph)

用于查询库状态及管理复杂的依赖拓扑图。

命令 常用参数/示例 功能描述
conan list conan list "zlib/*" [2.x 核心命令] 在本地缓存或远程仓库中详细列出配方(Recipes)、修订版本(Revisions)以及具体的二进制包(Package ID)。
conan search conan search "zlib*" 搜索包:在远程仓库中按通配符模式搜索可用的包名(不包含具体的版本修订细节)。
conan graph conan graph info .
conan graph build-order .
依赖图分析:计算并输出项目的完整依赖树信息,帮助排查版本冲突,或者分析大型项目的并行构建拓扑顺序。
conan remove conan remove "zlib/*" -c 删除包:从本地缓存或远程仓库中删除指定的依赖包及其对应的二进制文件。

远程仓库交互 (Remote & Upload)

用于和 JFrog Artifactory、ConanCenter 等远程服务器进行上下行交互。

命令 常用参数/示例 功能描述
conan remote list, list-users, add, remove, login, auth 远程仓库管理:管理目标远程仓库(Remote)列表,并处理账户身份认证(注:2.x 中用 conan remote login 替代了 1.x 的 conan user)。
conan upload conan upload "zlib/*" -r myremote -c 上传包:将本地缓存中的依赖库配方和对应的二进制产物推送到配置好的远程仓库中。
conan download conan download "zlib/1.2.13" -r myremote 下载包:直接从远程服务器拉取 Recipe 和预编译二进制文件并放到本地缓存,但不触发当前工程的依赖安装流程。

环境配置与高级工具 (Config, Profiles & Advanced)

用于跨平台编译配置的切换及大规模工程的自动化管理。

命令 常用参数/示例 功能描述
conan profile detect, list, path, show Profile 管理:管理不同的构建环境配置(包含 OS、架构、编译器及版本号等)。conan profile detect 能够自动侦测当前环境并生成默认配置。
conan config install, list, show 客户端配置:配置管理。如配置 global.conf;2.29.0 新增了针对局部覆盖的 global_user.conf 支持。
conan cache path, clean, check-integrity 缓存管理:管理本地 Conan 数据目录。可以获取具体的缓存文件路径、执行冗余清理,或验证本地数据的哈希完整性。
conan lock create, add, update 锁文件机制:生成并管理 conan.lock 文件。通过锁定完整的依赖图版本及 Revision,来确保 CI/CD 流程中构建的绝对一致性和可重复性。
conan pkglist merge, find_remote 包列表处理:管理序列化的包列表 JSON 数据,方便流水线在多个构建节点间合并状态并进行批量下发处理。
conan workspace init, add, update, install 工作区协同:允许在一个父级 Workspace 下,同时在本地拉取和编辑多个关联的 Conan 项目并自动处理它们之间的依赖注入(2.29.0 对此项功能有增强,如新增对 python_requires 的支持)。