用conan export-pkg而非conan create,当ci已完成编译并产出二进制和头文件时;需指定唯一profile、显式声明settings、验证包结构与package_info()完整性,并启用revision机制避免重复上传。

CI中用conan create还是conan export-pkg?
取决于你的构建产物来源。如果CI里已经完成了完整编译(比如CMake build完,输出了libfoo.a、include/等),就别再让Conan重复跑一遍build()——直接用conan export-pkg把本地产物打包进缓存,快且可复现。只有当你要从源码在CI上“边编译边打包”,才用conan create。
常见错误是:CI脚本里写了conan create . user/channel,但conanfile.py里还留着build()逻辑,结果Conan又拉源码、又调CMake,白耗资源还可能因环境不一致失败。
- 用
conan export-pkg的前提:二进制和头文件已存在,路径明确(如build/install/include、build/install/lib) - 必须指定
--profile,否则Conan无法记录该包对应的平台/编译器信息,后续conan install时会找不到匹配项 -
conan export-pkg不运行source()或build(),所以conanfile.py里这两块可以删掉或留空
怎么保证不同平台的包不混在一起?
Conan靠settings区分二进制,比如os=Linux、arch=x86_64、compiler=gcc、compiler.version=12、compiler.libcxx=libstdc++11。CI里每条构建流水线必须用唯一profile,不能所有平台共用一个default。
典型坑:Linux CI用了GCC 12,但profile里漏写compiler.libcxx,导致生成的包被标记为libstdc++(旧ABI),而下游项目用libstdc++11去查,根本匹配不上。
- 推荐做法:按平台+工具链建profile文件,例如
profiles/linux-gcc12-release,内容显式声明全部关键settings - CI脚本中传参要严格对应:
conan export-pkg . mypkg/1.2.0@user/stable --profile=profiles/linux-gcc12-release - 跨平台CI(如GitHub Actions矩阵)里,
conan upload前务必校验conan list输出,确认包名含正确os和arch字段
上传前怎么验证包结构是否合法?
Conan不会自动检查package()拷进去的文件是否完整,比如漏了.so的.so.X版本链接,或include/下少了某个头文件——这些都会导致下游find_package()失败,但错误信息往往很模糊(如target not found)。
最轻量的验证方式是本地模拟CI流程:在干净容器里执行conan export-pkg后,立刻用conan install试装一次,并检查生成的CMakeDeps内容是否包含预期的target。
- 关键检查点:
conan info . --graph=file.html能生成依赖图,确认包是否被识别为二进制而非源码包 - 用
conan list "mypkg/*" --graph看包元数据里settings是否齐全 - 上传前加一步
conan download mypkg/1.2.0@user/stable -r=my-remote再conan install,确保远程下载后行为一致
CI里如何避免重复上传同一二进制?
Conan默认不校验文件内容,只看recipe和settings。如果两次CI用相同参数但源码有微小变更(比如改了注释),生成的.so其实不同,但Conan仍认为是“同一个包”,上传会覆盖或报错。
真正可靠的去重靠revision机制,但前提是启用revisions_enabled = 1并在CI中显式使用--revision或配合conan lock。
- 简单方案:在
conan export-pkg命令末尾加--revision=auto(Conan 2.x支持),它会基于conanfile.py和实际打包文件内容计算哈希 - 更稳的做法:CI第一阶段先跑
conan lock生成conan.lock,上传时用conan upload --lockfile=conan.lock,这样连依赖树都锁死了 - 注意:私有Nexus/Artifactory需开启
checksum deploy策略,否则服务器端不校验SHA256,上传覆盖风险仍在
最常被忽略的一点:CI生成的包必须带完整的package_info(),尤其是self.cpp_info.libs和self.cpp_info.includedirs。很多团队只顾打包二进制,忘了在conanfile.py里声明链接名,结果下游CMake里find_package(mypkg)成功,但target_link_libraries(myapp PRIVATE mypkg::mypkg)报错——因为Conan没告诉CMake该链接哪个.a。











