根本原因是--build=missing依赖运行时settings匹配远程二进制,而CI环境编译器版本、libcxx、runtime等微小差异即导致匹配失败并触发本地构建;必须用conan lock create生成确定性锁文件,并配合--lockfile --build=never及预装精准工具链与完整镜像仓库才能保障多平台CI稳定。

为什么 conan install --build=missing 在多平台 CI 上容易失败
根本原因不是 Conan 本身不稳,而是 --build=missing 会动态决定哪些包需要源码编译——而这个决策依赖于当前环境的 settings(如 os, compiler, arch, build_type)是否与远程仓库中已存在的二进制完全匹配。CI 环境千差万别:Linux runner 可能用 GCC 11/12/13,macOS runner 默认 Clang 版本随 Xcode 升级而变,Windows runner 的 MSVC 工具链版本又受 VS 安装影响。只要 settings 有一项微小差异(比如 compiler.version=12.0 vs 12),Conan 就认为“无匹配二进制”,触发本地构建,进而暴露编译器缺失、依赖链断裂、超时等问题。
必须用 conan lock create + conan install --lockfile
锁定文件(conan.lock)是跨平台 CI 稳定性的唯一事实来源。它把整个依赖图、每个包的 exact revision、binary ID、settings 和 requires 全部固化下来,和你本地开发机或某台成功构建的 runner 完全一致。
-
conan lock create . -s os=Linux -s compiler=gcc -s compiler.version=11 -s compiler.libcxx=libstdc++11 -s build_type=Release:在 CI 配置对应环境下生成锁文件(建议按平台分别生成多个 lock 文件) -
conan install . --lockfile=conan-linux-gcc11-release.lock --build=never:CI 构建时强制只使用锁文件里指定的二进制,禁用任何源码构建 - 把 lock 文件纳入 Git:确保所有团队成员和 CI runner 拿到的是同一份确定性依赖快照
注意:--build=never 是关键。它让 Conan 在找不到匹配二进制时直接报错,而不是尝试编译——这反而帮你提前暴露镜像仓库同步不全或平台支持遗漏的问题,而不是等到构建中途崩溃。
CI runner 必须预装匹配的编译器,不能靠 Conan 装
Conan 不负责安装系统级工具链,它只管理 C++ 库包。很多团队误以为 conan install 能自动搞定 GCC 或 Clang,结果 CI 报错 Compiler 'gcc' not found 或 Unable to find 'cmake'。
- Linux CI runner:用
apt-get install gcc-11 g++-11 cmake ninja-build python3显式安装,再通过update-alternatives或环境变量固定CC/CXX - macOS CI runner:用
brew install cmake ninja,并确保 Xcode Command Line Tools 版本与 lock 文件中compiler.version匹配(例如 Xcode 14.3 对应 Clang 14.0.3) - Windows CI runner:安装 Visual Studio Build Tools(非完整 VS IDE),并用
-s compiler=msvc -s compiler.version=193 -s compiler.update=11精确对齐
不这么做,conan install 可能因检测不到 compiler 而 fallback 到错误版本,导致 binary ID 偏移,锁文件失效。
镜像仓库必须覆盖全部 target platform 的二进制
即使你用了 lock 文件,如果私有镜像仓库没同步好对应平台的二进制,--build=never 就会失败。常见盲区:
- 只同步了
linux_x86_64,但 CI 还跑linux_aarch64(ARM64 服务器)或linux_i686(32 位兼容) - 只同步了
Release,但 CI 测试流程需要Debug构建(build_type=Debug会生成不同 binary ID) - 镜像同步脚本漏掉了
compiler.runtime(Windows 下的dynamic/static)或compiler.libcxx(Linux 下的libstdc++vslibstdc++11)
验证方式很简单:在 CI runner 上手动执行 conan search "zlib/*" -r your-mirror,确认返回结果包含你 lock 文件里列出的所有 package_id 对应的条目。缺一个,CI 就可能卡住。
真正难的不是写对那几行 conan 命令,而是让 lock 文件、镜像仓库、runner 环境三者 settings 的每一个字段都严丝合缝——少一个 compiler.runtime,或多一个空格在 compiler.version,都会让看似稳定的 CI 突然开始随机失败。


















