package_id变化由settings、options和requires的实际取值决定,非源码哈希;default_mode下仅major版本影响id,full_version_mode则minor/patch也参与计算,且package_id()方法可手动调整兼容性边界。

conan package_id 变化是因为 settings/options/requires 的实际取值变了
package_id 不是哈希源码或时间戳,而是由当前 conanfile 中 settings、options 和 requires 三类输入共同决定的逻辑 ID。只要其中任一维度的值在构建上下文里不同,ID 就会变——哪怕只改了一个 build_type 或升级了某个依赖的 minor 版本(取决于 mode)。
常见诱因包括:
-
conan install时用了不同的 profile(比如从gcc@12切到clang@16),compiler.version变了 → ID 变 - 在
conanfile.py里显式设置了options = {"shared": True},但调用时加了--options shared=False→ ID 变 - 依赖链中某个包的
requires从"zlib/1.2.13"升级为"zlib/1.2.14",且当前使用的是full_version_mode→ ID 变 - 没写
validate(),但os="Windows"实际被传入,而 recipe 内部逻辑又根据os修改了package_info()→ ID 也会变(因为package_info()影响兼容性判定)
default_mode 下 requires 的 minor/patch 版本不参与计算
Conan 默认采用 semver_direct_mode(旧称 default_mode),它只取 requires 中每个依赖的 major 版本号参与 package_id 计算。例如 "zlib/1.2.13" 和 "zlib/1.2.14" 在该模式下被视为等价,不会触发 ID 变更。
但要注意:这只是“默认行为”,不是“安全行为”。如果你的库对 zlib 的 patch 补丁有强依赖(比如修复了某个内存越界),那这个默认策略反而会让缓存复用出错。
验证是否启用默认模式:
conan config get general.default_package_id_mode
输出 semver_direct 即为默认模式。若需严格区分所有版本,请设为:
conan config set general.default_package_id_mode=full_version_mode
package_id() 方法手动修改会导致 ID 偏离预期
当你在 package_id() 里调用 self.info.include_build_settings()、self.info.requires["xxx"].full_package_mode(),或像下面这样添加 compatible_packages,就等于主动重定义了兼容边界:
def package_id(self):
if self.settings.compiler == "gcc" and self.settings.compiler.version == "4.9":
compatible_pkg = self.info.clone()
compatible_pkg.settings.compiler.version = "4.8"
self.compatible_packages.append(compatible_pkg)
这种写法会让 Conan 认为 “gcc 4.9 构建的包可以兼容 gcc 4.8 的二进制”,从而改变实际匹配逻辑。容易踩的坑有:
- 忘记在
package_id()中排除不支持的平台(如os="Windows"),导致 fallback 包仍尝试匹配 Windows 配置,浪费下载和检查资源 - clone 后没 clean 掉无关字段(比如保留了
build_type="Debug"但目标包只有 Release 二进制),结果 fallback 失败又没报明确错误 - 多个
compatible_packages条目之间产生冲突(比如同时声明兼容 4.7 和 4.8,但远端只有 4.7 的二进制),Conan 不会自动选最优,而是按顺序尝试
Conan 2.x 的 package_id 更动态,但也更隐蔽
Conan 2.x 引入了基于“包类型”(header_only / static / shared)和“依赖关系类型”(private / interface / implementation)的自动策略。这意味着:
- 一个
header_only包的package_id可能完全忽略compiler和build_type,因为它不产出二进制 - 标记为
private的依赖(如requires = [("opencv/2.4.13", "private")])不再向上透传其 settings 到父包 ID,从而避免被“覆盖”导致 ID 意外变更 - 但这也意味着你不能单靠看
conanfile.py的settings字段来推断最终 ID —— 必须结合包类型和依赖传递规则一起判断
最常被忽略的一点:Conan 2.x 中 package_id() 方法的执行时机和上下文比 1.x 更复杂,尤其在多级依赖嵌套时,self.info 可能已被上游修改过,直接 clone 并改 setting 容易引入不可见偏差。











