如何用Conan 2.x分发C++共享库并实现多版本部署?
问题背景与需求
我维护一个包含4个基础库和N个依赖这些库的可执行文件的单仓库(monorepo),目前用Conan 2.x的孵化版workspaces特性管理构建。所有库和应用都已通过Conan打包推送到Artifactory,且希望将这4个库作为共享库交付。
核心需求:
- 能在同一裸机上并存同一共享库的多个版本,同时让不同版本的应用各自依赖对应版本的共享库(主要用于测试场景)
- 避免在CMake中硬编码库版本路径,防止Conan配置和CMake路径不一致导致的错误
- 不依赖系统库路径,也不能使用容器方案
当前已尝试的CMake配置:
set_target_properties(app_one PROPERTIES INSTALL_RPATH "$ORIGIN/../lib" )
该配置仅能应对单版本库的场景,无法满足多版本共存需求。
解决方案
1. Conan打包部署共享库与版本管理
- 打包阶段:在库的
conanfile.py中明确设置shared=True,确保生成共享库。利用Conan的包布局特性,默认会按包名/版本的结构组织库文件,无需手动修改package()方法的目录逻辑,Conan会自动维护版本隔离的基础结构。 - 部署阶段:在目标机器上,通过Conan的
install命令指定版本和独立安装目录,比如:
让不同版本的库完全隔离在各自的目录中。conan install lib/0.0.1@user/channel --install-folder ./deploy/lib/lib_0.0.1 conan install lib/0.0.2@user/channel --install-folder ./deploy/lib/lib_0.0.2 - 动态链接路径配置:不要在CMake中硬编码版本,而是在应用的
conanfile.py中,通过generate()方法注入依赖版本对应的RPATH路径。比如利用Conan的CMakeDeps生成工具,自动将依赖库的路径传递给CMake,最终生成类似$ORIGIN/../lib/lib_0.0.1的RPATH,全程由Conan根据依赖版本动态生成,避免人为错误。
2. 依赖共享库的应用打包
- 应用依赖声明:在应用的
conanfile.py中明确指定依赖库的版本,比如requires = "lib/0.0.1@user/channel",Conan会自动关联对应版本的共享库。 - 打包与目录布局:使用
conan create打包应用时,在package()方法中按版本隔离应用文件,推荐部署目录结构如下:
每个应用版本自带对应版本的依赖库,RPATH设置为deploy/ app_1.0.0/ bin/ app_one lib/ lib_0.0.1/ libfoo.so app_1.1.0/ bin/ app_one lib/ lib_0.0.2/ libfoo.so$ORIGIN/../lib/lib_<version>,运行时直接加载自身目录下的库,完全避免版本冲突。 - 避免硬编码:通过Conan的
CMakeToolchain传递RPATH变量,在CMake中直接使用${CMAKE_INSTALL_RPATH},无需手动写死版本字符串。
3. 环境维护与旧版本清理
- 版本追踪:在部署机器上维护一个
deploy_manifest.json清单文件,记录每个已部署的应用/库版本、安装路径、依赖关系,比如:{ "app_1.0.0": { "path": "./deploy/app_1.0.0", "dependencies": ["lib/0.0.1"] }, "lib_0.0.1": { "path": "./deploy/lib/lib_0.0.1", "used_by": ["app_1.0.0"] } } - 自动化清理:编写脚本定期执行以下操作:
- 扫描部署目录的文件访问时间(
atime),标记超过30天未被访问的版本 - 对照清单文件,清理没有任何应用依赖的库版本
- 提供交互式确认步骤,避免误删正在使用的版本
- 扫描部署目录的文件访问时间(
- Conan缓存清理:使用
conan remove命令清理本地缓存中不再需要的包版本,比如:
执行前需确认该版本未被任何已部署的应用依赖。conan remove "lib/0.0.1@user/channel" --confirm
内容的提问来源于stack exchange,提问作者IvanYanakiev
相关产品推荐
相关产品推荐

