conan 的 settings 是构建上下文的刚性描述,必须与 cmake 构建类型严格对齐以确保 package id 正确;options 是可选编译开关,需在 package_id() 中显式声明才影响二进制唯一性。

settings 决定 package ID,不是“可选”,而是“必须对齐”
Conan 的 settings(如 os、arch、compiler、build_type)不是运行时开关,而是构建上下文的刚性描述。它们直接参与计算 package_id —— 换句话说,build_type=Debug 和 build_type=Release 是两个完全不同的包,哪怕源码一模一样。
常见错误现象:conan install 成功,但链接时报 undefined reference;或 Debug 版本加载了 Release 的依赖库。
- 根本原因:host profile 中的
build_type与 CMake 的-DCMAKE_BUILD_TYPE不一致(Linux/Clang/GCC 场景下尤其高频) - 多配置生成器(如 MSVC)不适用
-DCMAKE_BUILD_TYPE,必须靠conan install --config Debug+ host profile 显式设为build_type=Debug -
settings无法在requires里“传给依赖”——它天然全局共享;你改不了依赖的os,只能换一个已为该os构建好的二进制
options 是包内部的布尔/枚举开关,影响编译行为但不强制改变 package ID
options(如 shared=True、with_ssl=False)是配方作者定义的、供消费者控制的编译期分支。它不参与默认 package_id 计算 —— 除非你在 package_id() 方法里显式把它加进去。
使用场景:你想让 openssl 静态链接,但又不想因此拉取一整套全新二进制(即复用已有的 build_type=Debug 包),这时就靠 options 控制。
- 默认值由
default_options定义,但会被下游通过self.options["xxx"].xxx = ...覆盖 - 在
configure()方法中可做条件判断:if self.settings.build_type == "Debug": self.options["zlib"].shared = False - 跨层级传递要小心:A → B → C,若 B 没把 A 的 option 显式透传,C 就拿不到;Conan 不自动级联
profile 文件里怎么写 settings 和 options 才不冲突
profile 是 settings + options 的固化快照,但它只作用于当前命令的 host 上下文。容易被忽略的是:profile 里的 options 只影响“直接依赖”,不自动广播到整个依赖图。
正确做法是用模式匹配语法,在 profile 里声明目标包的选项:
#[options] zlib/*:shared=True boost/*:without_python=True mylib/1.2.3:libs_only=True
而 settings 必须全量写在 [settings] 下,例如:
#[settings] os=Linux arch=x86_64 compiler=gcc compiler.version=12 compiler.libcxx=libstdc++11 build_type=Debug
- 不要在 profile 里写
options时不带包名前缀(如shared=True),这会报错或静默失效 - profile 中的
build_type必须和你最终要生成的二进制类型严格一致;否则 Conan 会去找错的 package ID,远端没有就失败,不会“自动 fallback” - 双 profile 场景(
-pr:h+-pr:b)下,只有-pr:h的settings影响最终产物的package_id
为什么改了 options 却没重新构建?
因为 Conan 默认只根据 settings 和 options 是否进入 package_id() 来决定是否复用缓存。如果配方没重写 package_id(),那 shared=True/False 的变化根本不会触发新构建 —— 它们被当成同一个包。
典型表现:改了 shared=True,conan install 直接复用旧二进制,结果链接时报 undefined reference to dlopen。
- 解决办法一:在
conanfile.py中显式声明def package_id(self): self.info.options.shared = self.options.shared - 解决办法二:用
conan create --build=missing强制从源码构建(适合调试阶段) - 更稳妥的做法:在 CI 流水线中固定 profile + 显式
package_id(),避免本地开发和构建机行为不一致
真正难的不是写对 syntax,而是意识到:settings 是坐标轴,options 是坐标轴上的点;你得先确认自己站在哪根轴上,再决定要不要挪那个点。











