Conan必须将静态库和动态库分包,因为shared选项直接影响构建过程、包结构和package_info行为,且包ID由settings与options共同决定,shared不同则生成独立二进制包。

会,Conan 默认把静态库和动态库视为不同二进制包,哪怕源码完全一样,只要 shared=True 和 shared=False 不同,就生成独立的包 ID,对应不同的缓存路径和二进制文件。
为什么静态库和动态库必须分包
Conan 的包 ID 是由 settings(如 os、arch、compiler)和 options(如 shared)共同决定的。而 shared 是一个关键 option,直接影响:
- 构建过程:是否传
-fPIC、是否用SHARED类型 target、是否链接.so/.dll而非.a/.lib - 包结构:动态库需额外提供
bin/目录或 runtime 依赖(如.dll拷贝),静态库则只放lib/和include/ -
package_info()行为:例如self.cpp_info.libs可能因shared值不同而变化(如动态库需导出符号名,静态库可能含多个子模块.a)
conanfile.py 中如何控制共享行为
在配方中显式声明 options 并在 build() / package() 中响应:
class MyLibConan(ConanFile):
name = "mylib"
options = {"shared": [True, False]}
default_options = {"shared": False}
<pre class="brush:php;toolbar:false;">def build(self):
cmake = CMake(self)
# 关键:把 shared 选项透传给 CMake
cmake.definitions["BUILD_SHARED_LIBS"] = self.options.shared
cmake.configure()
cmake.build()
def package_info(self):
# 静态库通常直接 link libmylib.a;动态库可能需额外 runtime path 或 import lib
if self.options.shared:
self.cpp_info.libs = ["mylib"]
self.cpp_info.defines.append("MYLIB_SHARED")
else:
self.cpp_info.libs = ["mylib"]
注意:self.cpp_info.libs 名字可以一样,但实际链接的文件类型(.a vs .so)和符号可见性完全不同,Conan 不会帮你自动切换——它只按当前配置打包和暴露。
常见踩坑点
以下问题几乎都源于混淆了静态/动态包的隔离性:
- 本地改了
conanfile.txt里[options] mylib:shared=True,但没删~/.conan/data/mylib/...下旧的shared=False包缓存,CMake 仍 link 到静态版,报undefined reference - 用
conan create打包时没加-o mylib:shared=True,结果上传的是静态包,下游却想用动态链接,根本找不到.so - CMakeLists.txt 里硬编码了
target_link_libraries(myapp mylib),但 Conan 提供的${CONAN_LIBS}实际是mylib(名字相同),链接器却因运行时找不到libmylib.so而失败——这时得检查LD_LIBRARY_PATH或RPATH是否包含conan install输出的lib路径
最易被忽略的一点:Conan 的「包」本质是二进制产物 + 元信息的绑定体,不是源码快照。哪怕你只改了一个 shared 选项,它就不再是“同一个包”,也不能靠清缓存以外的方式复用旧二进制。

















