conan 通过 conan.lock 文件锁定依赖的具体版本、revision 和二进制配置,而非 conanfile 中的版本声明;它由 conan install 自动生成或更新,必须提交至 git 并在 ci/cd 中强制使用 --lockfile 参数以确保构建可重现。

Conan 锁定依赖版本的核心手段是生成并使用 conan.lock 文件,而不是靠 conanfile.txt 里写死版本号——后者只是声明意图,conan.lock 才是实际生效的“契约”。
conan.lock 文件怎么生成和更新
它不是手动创建的,而是在执行 conan install 时自动生成或更新。关键在于是否带 --lockfile 参数以及是否允许解析新版本。
- 首次运行
conan install . --build=missing(在含conanfile.py或conanfile.txt的目录),Conan 会解析依赖图、选择具体包 ID 和修订号(revision),然后生成conan.lock - 后续想更新依赖(比如加了新 require 或升级了某个版本),必须显式触发重解析:
conan install . --lockfile-out=conan.lock --build=missing,否则 Conna 默认复用旧锁文件 - 如果只想更新某一个依赖(如
fmt/10.2.1 → fmt/11.0.0),改完conanfile后仍需重新运行 install 命令,不能只改conan.lock—— 它是只读快照,手改极易破坏哈希一致性
为什么只写 fmt/10.2.1 不等于锁定
在 conanfile.py 或 conanfile.txt 中写 fmt/10.2.1 只表示“我想要这个版本”,但 Conan 实际可能拉取不同 revision、不同二进制配置(如 compiler.libcxx=libstdc++11 vs libc++)的包,只要它们都满足该版本约束。真正锁定的是 conan.lock 里记录的完整坐标:
-
ref:包引用,含版本、用户、频道(如fmt/10.2.1@) -
rev:该引用对应的仓库提交哈希(revision) -
package_id:由 settings + options 计算出的唯一 ID,决定二进制是否可复用 -
rrev和prev字段(Conan 2.x):分别标识 recipe 和 package 的精确版本
没有 conan.lock,同一行 fmt/10.2.1 在不同机器上可能解析出 ABI 不兼容的二进制。
CI/CD 中必须用 --lockfile 参数
本地开发时漏掉 --lockfile 可能“碰巧”成功,但 CI 流水线必须严格遵循锁定文件,否则构建不可重现。常见错误配置:
-
conan install . --build=missing—— 没指定锁文件,Conan 自己找或新建,结果不可控 -
conan install . --lockfile=conan.lock—— 正确,强制使用现有锁文件 -
conan install . --lockfile=conan.lock --lockfile-out=conan.lock—— 更新锁文件的标准写法(尤其在 PR 构建后自动提交新锁) - 忘记把
conan.lock提交到 Git:这是最常被忽略的一环,没它,协作就退化成“在我机器上能运行”
conan.lock 不是银弹:它锁得越死,越要小心过期风险
conan.lock 确保构建可重复,但也意味着你主动放弃了自动获取安全补丁(比如 zlib/1.2.11 的某个 revision 有已知漏洞,但锁文件卡在旧 revision 就不会升级)。所以:
- 生产发布分支适合用完整锁定;开发分支建议定期运行
conan install . --lockfile-out=conan.lock --build=missing主动刷新 - 不要把
conan.lock和conanfile的语义混淆:前者是结果,后者是输入;改conanfile必须触发重生成锁,否则变更不生效 - 跨平台项目要特别注意
settings差异——Windows 上生成的conan.lock默认不含 Linux 的package_id,直接拿过去用会报错Missing prebuilt package











