conan install 必须在含 conanfile.txt 或 conanfile.py 的目录执行,否则依赖未安装;需固定版本与通道、显式传入 settings、package() 中用 self.copy 显式复制头文件和库到约定路径,并提交 conan.lock 文件。

conan install 必须在正确目录执行,否则依赖根本没装上
本地能编译通过、CI 报 conan install 找不到 conanfile.txt 或链接失败,十有八九是因为执行路径错了。Conan 不会自动向上查找配置文件,它只认当前目录或显式指定路径下的 conanfile.txt 或 conanfile.py。
常见错误操作:
- 把
conanfile.txt放在src/目录,却在项目根目录运行conan install ..—— Conan 不解析父路径,直接报错No conanfile.py or conanfile.txt found - CI 脚本里写
conan install ./conan/,但实际文件在./下,路径错位导致静默跳过 - 用
conan install .时没先cd到含conanfile的目录,而是从build/目录执行,结果什么都没装
实操建议:CI 脚本开头加一行 ls -l conanfile* 或 find . -name "conanfile.*",确认文件真实位置;然后 cd 进去再跑 conan install . --build=missing。
依赖版本必须锁定,模糊版本号(如 ^1.0.0)在 CI 中不可靠
本地 conan install 成功,CI 却拉到不同二进制、链接失败或头文件不匹配,往往因为 conanfile.txt 里用了不带通道的模糊版本,比如 fmt/^10.2.0 或 openssl/1.1.1w(缺 @)。
Conan 2.x 默认行为是:不带 @channel 的写法会触发远程搜索,而 conancenter 索引可能随时间变化,CI 拉到的预编译包可能对应不同编译器、C++ 标准或 ABI —— 本地缓存里碰巧有兼容包,CI 干净环境就挂。
安全写法只有一条:
- 固定版本 + 显式通道:
fmt/10.2.1@(@表示默认 conancenter)、zlib/1.2.13@ - 私有库必须带完整用户/频道:
mylib/1.0.0@team/stable - 绝对不用
~、^、*—— 它们在 Conan 里不是语义化版本控制,而是远程查询开关
验证方式:本地执行 conan list "fmt/*" --remote conancenter,看是否只返回一个精确版本;CI 日志里检查 conan install 输出的 resolved reference 是否和本地一致。
CI 必须显式传入 settings,不能依赖默认值
本地 DevEco Studio 或 VS Code 插件可能自动注入 compiler=gcc、compiler.version=11 等 settings,但 CI 容器里 conan install 若不显式指定,就会用 Conan 自动探测的值(比如容器里只有 clang,或 gcc 版本是 9),导致生成的 CMakeDeps 和实际构建环境错配。
典型现象:
- CI 报
undefined reference to 'fmt::vX::format'—— 实际是链接了为 GCC 11 编译的 fmt,但构建时用了 GCC 9 -
find_package(fmt CONFIG REQUIRED)找不到 config 文件 —— 因为CMakeDeps生成路径里嵌了gcc-11,而 CMake 没传对应 toolchain
实操建议:CI 脚本中 conan install 命令必须带全 settings:
conan install . --build=missing \ -s compiler=gcc \ -s compiler.version=11 \ -s compiler.libcxx=libstdc++11 \ -s build_type=Release
如果项目支持多平台,settings 应抽成变量或 profile 文件,避免硬编码散落在脚本各处。
conanfile.py 里的 package() 方法必须显式 copy,否则 CI 构建找不到头文件或库
本地能跑通,CI 报 fatal error: fmt/format.h: No such file or directory 或 cannot find -lmylib,大概率是 conanfile.py 的 package() 方法漏了 self.copy() 调用,或者路径写错。
Conan 包结构是强约定的:include/ 下放头文件,lib/ 下放静态库,bin/ 下放动态库 —— 如果 package() 没按这个规则复制,下游 conan install 就拿不到任何东西,CMake 的 find_package() 自然失效。
常见错误写法:
-
self.copy("*.h")没指定dst="include"和src="src",默认复制到包根目录,不被 CMakeDeps 识别 - 用
os.path.join(self.source_folder, "include")但源码里根本没有include/目录,copy 结果为空 - 静态库名是
libmylib.a,但self.copy("*.a")没加keep_path=False,导致路径嵌套过深,CMake 找不到
正确模板:
def package(self):
self.copy("*.h", dst="include", src="include")
self.copy("*.a", dst="lib", keep_path=False)
self.copy("*.so", dst="lib", keep_path=False)
self.copy("*.dll", dst="bin", keep_path=False)
CI 中可加一句 conan inspect . --attribute=cpp_info,检查输出里 includedirs 和 libdirs 是否指向 include 和 lib。
最常被忽略的一点:Conan 2.x 的 lockfile(conan.lock)必须提交进 Git。它记录了完整依赖树和每个包的 exact revision,没有它,哪怕所有 conanfile 写得再精确,CI 仍可能因远程仓库变更而拿到不同二进制。


















