conan找不到二进制包的根本原因是package_id不匹配,而非未上传;它依据settings、options、requires版本解析结果等自动计算id,任一变化即导致id变更,从而无法复用缓存或远程二进制。

Conan 找不到匹配的二进制包,根本原因不是“没上传”,而是它算出来的 package_id 和远程/本地缓存里已有的不一致。你看到的 ERROR: Binary for xxx not found 或 Missing prebuilt package,背后全是 ID 对不上。
package_id 计算逻辑决定一切
Conan 不靠包名和版本号找二进制,而是靠 package_id —— 一个由当前配置“哈希”出来的字符串。只要以下任一变化,ID 就变:
-
settings:比如compiler.version="12"vs"13"、build_type="Debug"vs"Release"、os="Linux"vs"Windows" -
options:比如shared=TruevsFalse、fPIC=True -
requires的版本解析结果(尤其在非full_version_mode下,只认 major 版本) -
self.info.requires被显式修改过(比如在package_id()中调用self.info.requires["zlib"].full_package_mode())
常见现象:
- 你在命令行指定
-s compiler.version=12,但依赖项的conanfile.py里写了requires = "openssl/1.1.1w@",而该 openssl 包的 recipe 又依赖zlib/1.2.13—— 如果 zlib 在远程只有1.2.12的预编译包,且你没开--build=missing,就会卡住 - 项目 A 引用了
opencv/4.9.0,项目 B 引用了opencv/2.4.13,两者共用一个依赖库 C;C 的requires默认是 override 模式,导致最终 opencv 被“升版”到 4.9.0,但 C 自己只测试过 2.4.x,于是package_id变了,原有二进制失效
requires 写法直接影响 ID 兼容性
requires 不只是声明依赖,它参与 package_id 计算。默认模式下,zlib/1.2.13 和 zlib/1.2.14 被视为等价(只看 major),但如果你启用了 full_version_mode,它们就完全不兼容。
更隐蔽的问题是依赖覆盖:
错误写法:
requires = ["opencv/2.4.13", "dlib/19.24"]
→ 如果 dlib 内部也 requiresopencv/4.5.0,它会把你的 2.4.13 “覆盖”掉,最终整个图里 opencv 是 4.5.0,ID 改变正确写法(锁定子依赖不被覆盖):
requires = [("opencv/2.4.13", "private"), "dlib/19.24"]
→private模式让 opencv 不参与当前包的package_id计算,也不透传给下游
其他风险点:
- 漏写
@:写成"zlib/1.2.13"而非"zlib/1.2.13@",Conan 会尝试从远程搜索,可能命中不兼容的社区包 - 用模糊版本:
"fmt/[~10.0.0]"或"^10.0.0"—— CI 环境下不同时间拉到的版本可能不同,ID 飘移 - 没指定
user/channel却依赖私有包:比如"mylib/1.0@"实际想找mylib/1.0@team/stable,但没写全,Conan 默认去conancenter查,当然找不到
conan install 命令参数必须和 profile 严格对齐
conan install 不是“自动适配”,它完全按你给的 settings 和 profile 构造上下文,然后去查 ID。
典型错配:
- 你用 Ninja(单配置)构建,却在命令行硬塞
-s build_type=Debug -s build_type=Release→ Conan 只认最后一个,ID 变成 Release,但你实际要 Debug - Windows 上用 MSVC,没加
--config Debug,又没在 profile 里设build_type=Debug→ 默认取Release,ID 不匹配 - profile 里写的是
compiler.libcxx=libstdc++11,但你本地 GCC 实际用的是libstdc++(无 11 后缀)→ ID 不同,找不到二进制
验证方式很简单:
conan install . -s build_type=Debug --dry-run | grep "package_id"
看看输出的 ID 是什么,再查缓存:conan search "pkgname/*" -r remote_name,比对是否存在对应 ID 的二进制。
package_id 是隐式维度,看不见摸不着,但它是 Conan 二进制复用的唯一依据。很多人改来改去发现还是不匹配,问题往往出在某个依赖的 recipe 里悄悄调用了 self.info.clear(),或者 profile 覆盖了 os_build 这类 host-only 设置 —— 这些细节不报错,但会让 ID 偏离预期。











