shared=false不保证静态链接成功,因实际构建依赖cmakelists.txt是否支持build_shared_libs=off等开关,且需匹配compiler.runtime、build_type等settings,否则链接失败。

conanfile.py 里 shared=False 不等于静态链接成功
很多人以为在 options 中设 "shared": [True, False] 并把 default_options = {"shared": False} 就能打包出静态库,但实际编译结果还取决于底层 CMakeLists.txt 是否真正启用静态构建逻辑。比如某些项目(如 mongo-cxx-driver)默认只生成动态库,即使 Conan 指定 shared=False,CMake 仍可能忽略或报错。
实操建议:
- 检查上游项目的构建文档,确认它是否原生支持静态构建(例如是否提供
BUILD_SHARED_LIBS=OFF或类似开关) - 在
configure()阶段显式传参:cmake.configure(..., defs={"BUILD_SHARED_LIBS": "OFF"}) - 若项目用 Autotools,改用
self.run("./configure --enable-static --disable-shared") - Windows 下注意 CRT 链接:
/MT(静态 CRT)和/MD(动态 CRT)必须与主项目一致,否则链接失败;Conan 的compiler.runtimesetting 就是用来控制这个的
profile 中 compiler.runtime 和 build_type 必须匹配静态库预期
Conan 的二进制 ID 是由 settings 全局决定的,其中 compiler.runtime(仅 Windows)和 build_type 直接影响静态库能否被正确选中和链接。
常见错误现象:
- Linux/macOS 上没 runtime 概念,但
build_type=Debug编译的静态库无法链接到build_type=Release的主项目(符号名、调试信息、优化宏都不同) - Windows 上 profile 里写的是
compiler.runtime=MD,但你手动编译的静态库是/MT,链接时会报LNK2038: mismatch detected for 'RuntimeLibrary' - ConanCenter 的包大多只提供
compiler.runtime=MD(动态 CRT),如果你需要/MT,必须自己--build=missing并确保 profile 明确指定compiler.runtime=MT
CMake 项目链接静态库时要主动禁用 find_package 的动态优先行为
Conan 生成的 CMakeDeps 默认会让 find_package(fmt) 找到动态库(哪怕你安装的是 shared=False 版本),因为 CMake 的 find_package 机制本身倾向动态库。
解决方法不是改 Conan 配置,而是调整 CMakeLists.txt:
- 用
find_package(fmt CONFIG REQUIRED)+target_link_libraries(myapp PRIVATE fmt::fmt)是安全的,它走的是 Conan 生成的fmt-config.cmake,会自动选对静态/动态目标 - 避免直接写
target_link_libraries(myapp PRIVATE fmt),这会触发 CMake 原生查找,可能绕过 Conan 提供的静态版本 - 如果必须强制静态,可在 target 上加属性:
set_target_properties(fmt::fmt PROPERTIES INTERFACE_LINK_LIBRARIES "$<fmt::fmt_static>")</fmt::fmt_static>(需确认该别名存在)
跨平台静态库路径和命名差异容易导致 Linux/macOS 链接失败
Conan 约定静态库放在 lib/ 下,但不同平台命名规则不同:libfoo.a(Linux/macOS)、foo.lib(Windows)。而有些项目(尤其用 Meson 或自定义脚本打包的)会把静态库放进 lib/static/ 或漏放 .a 文件——这时 CMakeDeps 生成的 xxx-config.cmake 仍会尝试链接 libfoo.so,报 cannot find -lfoo。
排查步骤:
- 执行
conan install后,进build/目录看生成的conanfile.txt对应的xxx-config.cmake,搜索set_and_check(_IMPORT_PREFIX,定位真实库路径 - 手动
ls -la ~/.conan/data/foo/...查看package/子目录下是否有lib/libfoo.a(Linux/macOS)或lib/foo.lib(Windows) - 若缺失,说明包作者没按 Conan 约定布局;此时要么提 PR 修复,要么 fork 后在
package()方法里手动self.copy("*.a", dst="lib", src="build/lib")
最易被忽略的一点:Conan 的 package_id() 不校验静态库文件是否存在,只校验 settings/options —— 所以一个“声称支持 static”的包,可能根本没打包静态库,直到链接时报错才暴露。











