conan创建包时默认只生成静态库,要支持动态库必须显式声明shared选项、透传至cmake、条件拷贝产物,并由消费者显式指定shared=true。

Conan 创建包时默认只生成静态库,要同时支持静态库和动态库,必须显式声明 shared 选项并正确处理构建逻辑。
conanfile.py 中必须定义 shared option
不加这行,Conan 就不知道你打算支持动态链接 —— 它不会自动生成 .dll、.so 或 .dylib,也不会把 shared=True 传给底层 CMake 构建系统。
-
options = {"shared": [True, False]}是必需的,不能省略 -
default_options = {"shared": False}建议设为False,符合多数包默认静态链接的习惯 - 如果源码项目本身不支持
BUILD_SHARED_LIBS或等效开关,光加 option 没用,得同步改build()逻辑
CMake 构建时要透传 shared 设置
Conan 不会自动把 shared=True 转成 CMake 的 -DBUILD_SHARED_LIBS=ON,必须手动做映射,否则无论你传什么 option,CMake 都按自己默认方式构建。
- 在
build(self)里用cmake.definitions["BUILD_SHARED_LIBS"] = "ON" if self.options.shared else "OFF" - 或者更稳妥地:直接拼进
cmake.configure(..., defs={...})参数里 - 注意 MSVC 下还要考虑运行时库(
/MDvs/MT),shared=True通常要求/MD,否则链接会失败
package() 方法里要区分拷贝静态/动态产物
Conan 的 self.copy() 不会根据 shared 值自动过滤文件,你得自己写条件逻辑,否则容易把 .lib 和 .dll 全塞进同一个包,导致消费者混淆。
- 静态库:
self.copy("*.lib", dst="lib", keep_path=False)(Windows)、self.copy("*.a", dst="lib", keep_path=False)(Linux/macOS) - 动态库:
self.copy("*.dll", dst="bin", keep_path=False)(Windows)、self.copy("*.so", dst="lib", keep_path=False)(Linux)、self.copy("*.dylib", dst="lib", keep_path=False)(macOS) - 头文件照常拷贝,不依赖
shared选项:self.copy("*.h", dst="include", src="src")
消费者使用时必须指定 shared=True 才能拿到动态库
即使你打包时支持了 shared,用户不显式声明,Conan 默认仍拉取静态版本 —— 这是 Conan 的行为惯性,不是 bug。
- 在
conanfile.txt中写:[options] yourpkg:shared=True
- 命令行安装时加:
conan install . -o yourpkg:shared=True - 若没指定,
conan search yourpkg/1.0@查到的二进制 ID 里会带shared=False,对应的就是静态版 - 混合使用(部分库动态、部分静态)需确保 ABI 兼容,尤其在 Windows 上
/MD和/MT混用会崩溃
真正麻烦的不是怎么写这几行代码,而是每个依赖项的 CMakeLists.txt 是否尊重 BUILD_SHARED_LIBS、是否导出正确的 INTERFACE 属性、以及 Windows 下 DLL 导出宏(如 __declspec(dllexport))有没有被正确启用 —— 这些细节不验证,包看起来能 build,但下游一链接就报 LNK2019 或运行时报 missing symbol。











