package() 必须与 package_id()、构建逻辑及消费者使用方式对齐,否则导致文件缺失、头文件找不到、链接失败或缓存污染;默认不自动拷贝文件,需显式调用 self.copy(),且要注意 pattern/src/dst 参数含义及 keep_path=false 的使用。

package() 方法不是“写出来就行”,而是必须和 package_id()、构建逻辑、消费者使用方式对齐。写错会导致包内容缺失、头文件找不到、链接失败,甚至不同配置下缓存污染。
什么时候必须重写 package()
Conan 默认不自动拷贝任何文件——除非你显式调用 self.copy()。常见场景包括:
- 源码编译后生成的
.lib/.a/.so在build()后落在self.build_folder下,不手动copy就不会进包 - 头文件在
source_folder里(比如include/目录),但没调用self.copy("*.h", dst="include"),消费者就看不到include路径 - 第三方预编译二进制(如 Windows SDK 的
foo.dll)放在项目根目录,需用self.copy("*.dll", src="prebuilt", dst="bin")拉进来
self.copy() 的路径参数容易错在哪
三个关键参数:pattern、dst、src,顺序和含义常被颠倒:
-
src是相对于self.source_folder或self.build_folder的起始路径,不是绝对路径 —— 写成src="/home/user/include"会静默失败 -
dst是包内最终路径,比如dst="include"表示消费者通过cpp_info.includedirs能拿到include/目录 -
keep_path=False很关键:不加它,self.copy("*.h", src="src/core", dst="include")会把文件放进include/src/core/xxx.h,而不是扁平的include/xxx.h
header-only 包的 package() 必须配合 package_id()
纯头文件库(如 common_source_cpp)不需要编译,但 package() 仍要负责把头文件放对位置;否则 package_info() 设置的 includedirs 就指向空目录。
- 必须写
self.copy("*.h", dst="include")、self.copy("*.hpp", dst="include")等,覆盖所有头文件类型 - 必须在
package_id()中调用self.info.header_only(),否则 Conan 会按默认逻辑(含os/compiler等)生成多个 package ID,浪费缓存 - 如果漏掉
self.info.header_only(),即使package()拷对了文件,conan install时也可能因 ID 不匹配而拉错包或报MISSING
打包预编译二进制时别用 build()
当你只有 .dll、.so、.a 文件,没有源码,就不该走 conan create 流程——它会强制执行 source() → build() → package(),而 build() 是空操作或报错。
- 改用
conan export-pkg . -r=remote-name -s os=Windows -s arch=x86_64直接导出本地文件 - 此时
package()依然要写,但只负责self.copy();build()可以完全删掉或留空 - 注意:
export-pkg不校验settings是否匹配,所以必须手动指定-s参数,否则包 ID 会默认为os=Linux类型,跨平台消费时出问题
最常被忽略的是 package_id() 和 package() 的联动关系:前者定义“什么变化会导致新包”,后者决定“这个包里实际有什么”。两者脱节,轻则包不可用,重则整个依赖树失效。











