Conan 2 工程手册:从 Profile 到可重建的 C/C++ 二进制图
同一个 conanfile.py,开发机从缓存拿到二进制,CI 却提示缺包;Release 应用误用了 Debug 依赖;交叉编译时 CMake 在宿主机运行,却把代码生成器解析成目标架构。把这些问题统称为“Conan 没装好”没有诊断价值。Conan 2 的真正对象是一张带机器上下文和二进制身份的依赖图:recipe 声明节点与边,profile 提供构建输入,package ID 选择可兼容二进制,lockfile 固定解析结果,cache 与 remote 只是这些对象的存放位置。
Conan 是 C/C++ 包管理器,不替代 CMake、Meson、Ninja、MSBuild 或编译器。它可以生成构建系统所需的 toolchain 与依赖元数据,也可以在 recipe 中调用构建系统,但最终编译规则仍属于对应构建系统。
先建立可审查的客户端身份
安装后先确认客户端与默认 profile:
conan --version
conan profile detect --name=default
conan profile show -pr:h=default -pr:b=default
conan remote listprofile detect 只是在当前机器上猜测编译器与运行库,官方明确提示其输出可能变化。个人首次探索可以使用,团队和 CI 应把审核后的 profile 放进仓库或受控配置包,并通过显式路径引用:
conan install . -pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build不要让隐式 default profile 决定正式构建,也不要把整个个人 Conan home 当作项目配置。CONAN_HOME 中还包含缓存、remote 和认证状态;CI 并行任务应使用彼此隔离的 home,因为 Conan cache 不是面向多个并发进程共享写入设计的。
用消费工程跑通依赖、构建与测试
最小 conanfile.txt 可以先让应用消费 zlib:
[requires]
zlib/1.3.1
[generators]
CMakeDeps
CMakeToolchain
[layout]
cmake_layoutCMakeLists.txt 继续使用原生 CMake 模型:
cmake_minimum_required(VERSION 3.23)
project(compressor LANGUAGES CXX)
find_package(ZLIB REQUIRED)
add_executable(compressor src/main.cpp)
target_link_libraries(compressor PRIVATE ZLIB::ZLIB)
enable_testing()
add_test(NAME compressor_smoke COMMAND compressor)执行顺序是先让 Conan 解析并生成集成文件,再让 CMake 配置、构建与测试:
conan install . --output-folder=build --build=missing \
-pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build
cmake --preset conan-release
cmake --build --preset conan-release
ctest --preset conan-release --output-on-failure--build=missing 只允许缺少匹配二进制时从 recipe 构建,不代表自动接受任意新版本。若不希望客户端构建依赖,省略该参数,让缺失二进制明确失败。团队应分别定义“只取批准二进制”和“受信任构建任务可从源码构建”的权限边界。
Profile 是一组配置输入,不是平台昵称
一个 profile 可以包含:
[settings]
os=Linux
arch=x86_64
compiler=gcc
compiler.version=14
compiler.libcxx=libstdc++11
compiler.cppstd=gnu20
build_type=Release
[options]
*:shared=False
[conf]
tools.build:jobs=8
tools.cmake.cmaketoolchain:generator=Ninja
[buildenv]
CC=gcc
CXX=g++settings 描述影响二进制兼容性的离散维度,例如 OS、架构、编译器、runtime 和 build type;options 是 recipe 暴露的产品变体,例如 shared、fPIC 或 feature;conf 调整工具行为和构建策略,通常不直接参与 package ID;环境区为构建或运行注入受控环境。
这三类输入不能互换。把编译器版本藏进 conf,package ID 可能无法区分 ABI;把并行数建成 option,会无意义地制造二进制变体。官方 Profiles reference 给出了 profile 结构、组合和优先级。
多个 profile 从左到右叠加,右侧优先;命令行 settings/options/conf 又覆盖 profile。CI 应保存最终配置:
conan profile show -pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build
conan graph info . -pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build \
--format=json --out-file=build/conan-graph.json不要仅保存 profile 文件名,因为同名 cache profile 可能遮蔽仓库文件。仓库 profile 使用 ./profiles/name 这类明确路径。
Host 与 Build Context 是两张相连的机器图
Conan 2 即使只传一个 --profile,内部也使用 host 和 build 两个 context。-pr:h 描述最终库与应用运行的环境,-pr:b 描述构建工具运行的环境。
requires 通常进入 host context,例如 zlib、OpenSSL 和业务库。tool_requires 通常为构建提供 CMake、Ninja、代码生成器或交叉编译器。build context 中工具自身的传递依赖也必须能在构建机运行。
本机构建时两份 profile 可能很像,但仍应显式传入。交叉构建时差异成为正确性的核心:
conan install . --build=missing \
-pr:b=profiles/linux-x86_64-build \
-pr:h=profiles/linux-aarch64-host不要把 host 理解为运行 Conan 命令的电脑。在 Conan 术语中,host 是目标二进制运行处;命令实际运行的机器属于 build context。官方 Cross-building tutorial 用双 profile 解释了这条边界。
Recipe 定义依赖、构建、打包与消费契约
应用消费可以从 conanfile.txt 起步;要创建可复用包,通常使用 conanfile.py:
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
class HelloRecipe(ConanFile):
name = "hello"
version = "1.0.0"
package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {"shared": [True, False], "fPIC": [True, False]}
default_options = {"shared": False, "fPIC": True}
exports_sources = "CMakeLists.txt", "include/*", "src/*"
def config_options(self):
if self.settings.os == "Windows":
self.options.rm_safe("fPIC")
def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
def layout(self):
cmake_layout(self)
def generate(self):
CMakeDeps(self).generate()
CMakeToolchain(self).generate()
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def package(self):
CMake(self).install()
def package_info(self):
self.cpp_info.libs = ["hello"]requirements() 建图,source() 取得源码,generate() 生成构建集成,build() 编译,package() 只收集交付文件,package_info() 告诉消费者如何使用。职责混在一起时,recipe 很难复用和测试。
创建包时运行:
conan create . --build=missing \
-pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build生产级 recipe 还应提供 test_package,从包缓存之外按消费者方式链接和运行。只检查 package 目录里“有 .a 文件”,无法证明头文件、组件名、传递依赖和运行环境正确。
Graph 先决定节点,再为每个节点找二进制
conan graph info 可以在不直接驱动应用构建的情况下展示解析结果:
conan graph info . -pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build
conan graph info . --format=json --out-file=build/graph.json \
-pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build先看 version range、override、recipe revision 和 context 是否正确,再看 binary 状态是 Cache、Download、Build 还是 Missing。若节点已经解析错了,清缓存不会让图自动变正确;应修 requirement、lock、profile 或 remote 顺序。
依赖冲突不能简单靠“选最高版本”处理。C/C++ 库可能把依赖类型、内联代码和运行库暴露进 ABI。override 应有兼容证据,版本范围应由 lockfile 固化,图变更应在评审中可见。
Package ID 是二进制身份,不是源码版本号
Conan 根据 settings、options 和依赖信息计算每个包的 package_id。相同 recipe version 可以有 Debug/Release、不同编译器、不同架构、shared/static 等多个二进制。官方 Binary model 与 package ID computation 展开了默认规则。
可以把默认关系理解为:
package ID = hash(settings + options + relevant dependency identities)recipe 的 package_id() 可以删除或调整维度,例如 header-only 包常清除无关 settings。但这不是减少缓存体积的随意开关。错误地宣称两个 ABI 不兼容产物“兼容”,会让 Conan 复用错误二进制,问题可能直到链接或运行时才暴露。
组织级 core.package_id:default_* 策略应稳定一致。修改默认兼容模式会改变大量二进制身份,必须与 recipe、构建支持组合和消费者一起迁移,不能由个人 global.conf 悄悄覆盖。
诊断缺失二进制时,比较 graph 中节点的 settings、options、recipe revision、package ID 和可用 remote,不要只对比包名版本。需要定位本地对象时使用:
conan list "zlib/1.3.1:*"
conan cache path "zlib/1.3.1:<package-id>"cache 路径是内部存储位置,不应被业务构建脚本硬编码。
Lockfile 固定解析图,不冻结整台构建机
创建 lockfile:
conan lock create . --lockfile-out=conan.lock \
-pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build之后安装显式使用:
conan install . --lockfile=conan.lock --build=missing \
-pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-buildConan 2 lockfile 记录依赖引用与 recipe revision,用于让版本范围和图更新可控;它不替代 profile,也不直接携带编译器、操作系统镜像或所有 package binary。相同 lock 配不同 profile,仍可能需要不同 package ID。
更新依赖时创建可评审的新 lock,比较 graph,再构建测试。严格 lock 遇到未锁定 requirement 会失败,这正是防止图悄悄漂移的价值。--lockfile-partial 适合明确的增量场景,不应成为绕过缺失锁项的默认参数。命令细节以 conan lock reference 为准。
Remote 顺序、包过滤与认证共同决定来源
客户端只需要知道 remote 的名字、顺序、允许访问的包和认证方式:
conan remote list
conan remote add approved https://packages.example.invalid/api/conan/cpp
conan remote auth approved --strict示例域名不可直接使用。正式 remote 通过受控 bootstrap 或 conan config install 下发,不让开发者手工维护不同顺序。Conan 支持 --allowed-packages 限制某 remote 可解析的引用范围,可减少同名包从错误来源进入图的机会。
CI 使用 secret 注入 CONAN_LOGIN_USERNAME_<REMOTE> 与 CONAN_PASSWORD_<REMOTE>,再执行 conan remote auth ... --strict。--strict 很重要,因为默认 auth 对部分 remote 失败仍可能返回成功。开发机更适合交互登录或组织批准的凭证助手,不把密码写进 profile、命令历史和 remote URL。官方 conan remote 说明了顺序、认证和严格退出码。
不要用 --insecure 或关闭 TLS 校验解决企业证书问题。应把企业 CA 注入系统或批准的 Python/客户端信任链,并在日志中隐藏用户名、授权头、内部 URL 参数和完整环境变量。
Cache 是可再生状态,不是共享文件仓库
Conan 2 cache 保存 recipe、revision、binary package、source、build 和临时状态。常用诊断与维护入口:
conan list "*"
conan cache path "pkg/1.0"
conan cache check-integrity "pkg/1.0:*"
conan cache clean "pkg/1.0:*" --build --source --temp清理前先用 graph 记录实际节点和来源,按包模式删除可疑对象;不要把删除整个 Conan home 当作首选排障。cache 中的认证、profiles 和 global.conf 与包数据不是同一责任,粗暴删除会抹掉证据并改变环境。
CI 每个并行 job 使用隔离 CONAN_HOME,需要加速时通过批准的 remote、cache save/restore 或流水线缓存策略传递材料。直接让多个 job 并发写同一个 home 可能引发锁与一致性问题。官方 conan cache 提供 path、clean、integrity、save 和 restore 等受支持入口。
CMakeToolchain 与 CMakeDeps 分别解决配置和发现
CMakeToolchain 把 Conan settings/options/conf 转成 conan_toolchain.cmake 与 CMake presets,帮助 CMake选择架构、runtime、标准和生成器。CMakeDeps 为依赖生成 find_package() 可消费的 config/module 文件与 imported targets。
两者职责不同:
Profile -> CMakeToolchain -> compiler/platform/build configuration
Dependency graph -> CMakeDeps -> find_package/imported targets应用的 CMakeLists.txt 应继续显式 find_package() 和 target_link_libraries(),不要 include 一大包全局变量绕过 target。官方 CMake integration、CMakeToolchain 与 CMakeDeps 给出了生成文件和 preset 行为。
Conan 2 的官方文档已经提供更新的实验性 CMakeConfigDeps 路线,但实验接口可能变化。现有工程以稳定的 CMakeDeps + CMakeToolchain 为基线,试迁移时用独立分支和消费测试验证 target 名称、组件、配置映射与 IDE 行为,不能把预览能力直接当组织默认。
交叉构建要同时验证工具链与依赖上下文
host profile 可以描述 AArch64 目标:
[settings]
os=Linux
arch=armv8
compiler=gcc
compiler.version=14
compiler.libcxx=libstdc++11
build_type=Release
[conf]
tools.cmake.cmaketoolchain:system_name=Linux
tools.build:sysroot=/opt/sdk/sysroot
[buildenv]
CC=aarch64-linux-gnu-gcc
CXX=aarch64-linux-gnu-g++build profile 仍描述运行 Conan、CMake、Ninja 和代码生成器的 x86_64 Linux。执行 graph 后检查 tool requirement 在 build context,目标库在 host context;再检查生成的 CMake toolchain 是否使用正确 sysroot、编译器和查找根路径。
交叉构建“编译成功”不代表目标可运行。至少扫描目标产物架构,验证动态依赖与 sysroot 来源,并在目标机、模拟器或等价环境执行代表性测试。把 build 工具误放到 host context,常见表现是配置阶段下载成功、执行时却报 Exec format error。
Vendor 与 Offline 要区分源码、Recipe 和 Binary
离线恢复需要回答三种材料是否齐全:解析图所需的 recipe/revision、recipe 下载的上游源码、每个 profile 所需的 binary package。只复制 conan.lock 不够,只复制已安装 DLL 也不够。
Conan cache 可以保存和恢复指定 package list,deployer 可以把运行或构建所需文件复制到受控目录。对源码 vendor,优先让 recipe 使用固定 revision、校验和和批准的本地镜像;某些 Conan 版本还提供 graph vendor 等孵化能力,采用前必须检查当前版本稳定性,不能把实验命令写成长期唯一入口。
一个可信离线演练遵循这条链:
在联网受信任任务中按 lock 与 profile 解析完整 graph。下载或构建所需 recipe、源码与 binary,并记录 package list、revision 和校验结果。把材料转移到全新隔离 CONAN_HOME。
禁用 remote 或使用 --no-remote,按同一 lock 与双 profile 安装。完成 configure、build、test 与运行时部署验证。
conan install . --no-remote --lockfile=conan.lock \
-pr:h=profiles/linux-gcc-release -pr:b=profiles/linux-build--no-remote 成功只证明当前 cache 足够,不能证明材料包可在另一台机器恢复;所以必须从空 home 导入并验证。vendor 材料也要接受许可证、补丁、来源和漏洞审查,不能因为“已经进内网”就跳过供应链责任。
CI 同时验证冷图、热缓存与只读消费
日常 PR 可以使用只读 remote 凭证,按 lock 与显式 profiles 执行 graph、install、configure、build、test;受保护的包构建任务才允许创建并上传二进制。普通分支若能覆盖共享二进制,等于能向后续构建注入可执行内容。
CI 至少保存这些证据:Conan 版本、双 profile 最终值、lockfile 哈希、graph JSON、recipe 与 package revision、binary 状态、remote 名称、CMake preset/toolchain、测试和空白消费结果。日志不保存密码或带签名的下载 URL。
同时保留两条验证:
热路径验证批准二进制能被正确命中,监控下载量、缺失率和构建时长。冷路径从隔离 home 恢复,暴露未锁定范围、漏传 recipe、隐式个人配置和离线材料缺口。
缓存键不能只有 conan.lock 哈希。Conan 自身按 package ID 区分二进制;流水线若把整个 home 塞进一个过粗键,会把 remote、profile、配置和错误二进制一起覆盖回来。
常见失败按图、身份、来源和消费层定位
Missing binary
先看 graph 节点所需 package ID,再比较可用 remote 中的 recipe revision 与 binary。若策略允许源码构建,使用精确的 --build=missing 或 pattern;若不允许,补齐受信任构建组合。不要用宽泛 --build=* 隐藏正式仓库漏包。
本机命中,CI 不命中
比较双 profile、命令行覆盖、global.conf、lock、recipe revision 和 remote 顺序。个人 cache 可能保存了从未上传的本地产物;以全新 CONAN_HOME 复现才能判断可恢复性。
CMake 找不到已安装依赖
确认 conan install 的 output folder、生成的 preset/toolchain、CMake configure 使用的 preset,以及 CMakeDeps target 名。不要手工补 CMAKE_PREFIX_PATH 掩盖生成目录错位。
链接或运行时 ABI 错误
对比 package ID 输入中的 compiler、runtime、build_type、shared、cppstd 与依赖身份。若 recipe 自定义了 package_id() 或组织改了 compatibility policy,先恢复默认严格匹配验证,不能只清 cache 重试。
Remote 认证偶发成功
使用 conan remote auth <name> --strict,检查匿名访问、remote 顺序、凭证过期与 CI secret 范围。不要把 token 放到 URL 或打开 insecure 模式。
从 Conan 1 迁移时保留双轨与回滚能力
Conan 2 不是只换 CLI 版本。命令、Python API、generator、环境模型、cache 布局、revisions 与 package ID 行为都有变化。迁移先让 Conan 1 recipe 采用尽可能接近 Conan 2 的新式工具与布局,再在独立环境运行 Conan 2。
重点替换包括:
旧 cmake/cmake_find_package* generator 迁移到 CMakeToolchain + CMakeDeps 与 target 消费。conan user 迁移到 conan remote login/auth。--json=file 类命令输出迁移到 --format=json --out-file=file。
旧环境生成器与 tools.* API 迁移到 conan.tools.* 和新的 environment 模型。Conan 1 cache 与 Conan 2 cache 分开,不在文件层直接复制或共用。
迁移覆盖至少包含每个受支持 OS、编译器、runtime、架构、shared/static 和关键 option。对同一源码分别生成 Conan 1 与 Conan 2 包,比较头文件、库、符号、组件 metadata、运行时依赖和 test_package,而不是只看构建退出码。
回滚时保留 Conan 1 客户端环境、旧 profile、旧 lock/版本约束、旧 remote 命名和旧二进制命名空间。Conan 2 新包不要覆盖唯一的 Conan 1 可用二进制;切换消费者前先让服务端或 remote 路由能并存。迁移细节可从官方 What’s new in Conan 2 与 Conan 1 的 migration guide 对照确认。
二进制兼容策略是架构决策。过严会造成构建爆炸,过松会复用不兼容 ABI。调整 package ID 规则前,先按库的头文件暴露、模板/内联、链接方式、runtime 和传递依赖分类,再用消费者测试证明兼容。
Recipe 和 binary 的信任边界不同。recipe 能下载源码、执行构建和调用系统工具;binary 会直接进入链接或运行。remote 的只读权限、上传权限、允许包模式、签名/校验、许可证与漏洞审查都要与构建身份关联。
Profiles 是组织支持组合的代码。编译器升级、runtime 切换、cppstd、sysroot 与 package ID policy 应在独立变更中推进,并观察缺失二进制数量、缓存体积、构建耗时和回滚可用性。
离线与 vendor 方案的成本会随 profile 组合成倍增长。不要宣称支持所有平台后只保存一套 Release x86_64 包;应明确支持组合、材料 owner、刷新频率、漏洞响应和淘汰策略。
Conan 版本、双 profile 与 lockfile 显式进入权威构建入口。settings、options、conf 各自承担二进制身份、产品变体和工具行为,不相互冒充。graph JSON 能解释 host/build context、依赖版本、revision、package ID 与 binary 状态。
recipe 有清晰的 source/generate/build/package/package_info 职责和 test_package 消费验证。remote 顺序、allowed packages、TLS 与认证受控,PR 默认无共享二进制写权限。cache 通过受支持命令维护,并行 CI 使用隔离 CONAN_HOME。
CMakeToolchain 与 CMakeDeps 分工清楚,应用继续使用 CMake target 模型。交叉构建验证构建工具和目标库的 context、sysroot、架构与目标运行测试。vendor/offline 从空 home、禁用 remote 后重建,recipe、源码与 binary 材料都可追踪。
Conan 1 迁移使用双轨覆盖组合,旧客户端、配置和二进制命名空间可独立回滚。
命令或模型发生变化时,从 Conan 2 commands、Profiles、Binary model 和 CMake integration 进入对应对象。先确认当前客户端版本,再采用文档中的新 generator 或孵化能力。
