最直接的方式是在项目根目录统一配置conanfile.py,各子模块共享依赖和构建设置;通过conan install --output-folder生成一次工具链,所有CMakeLists.txt统一include;必须使用conan.lock保证二进制一致性,避免因settings差异导致package ID分裂。

多个子模块共用同一套 conanfile.py 配置
如果你的项目是多模块结构(比如 core/、network/、ui/),但所有模块都依赖相同的库(如 fmt/10.2.1、spdlog/1.13.0)和构建设置(build_type=Release、compiler.libcxx=libstdc++11),最直接的方式不是每个模块写一个 conanfile.py,而是把配置统一放在项目根目录,让各模块共享。
关键点在于:Conan 的 conan install 命令支持 --install-folder 或指定输出路径,而 CMake 的 find_package() 只关心生成的 *Config.cmake 文件位置,不关心它从哪来。
- 在项目根目录放一个
conanfile.py,声明全部公共依赖和settings - 所有子模块的
CMakeLists.txt都通过include(${CMAKE_CURRENT_LIST_DIR}/../build/generators/conan_toolchain.cmake)引入统一工具链 - 构建任一模块时,先在根目录运行
conan install . --output-folder=build --build=missing,生成一次配置即可 - 避免在子模块内重复执行
conan install—— 否则可能因settings微小差异(如路径、缓存时间戳)导致 package ID 不一致,引发链接失败
conan lock 是跨模块一致性的事实来源
仅靠共享 conanfile.py 不足以保证所有模块使用完全相同的二进制版本。例如,core 模块可能拉取了 zlib/1.2.13 的某次构建,而 ui 模块在另一天执行 conan install 时,若远程仓库更新了该包的 recipe,就可能拿到不同 binary。
解决办法是生成并提交 conan.lock 文件:
- 首次完整安装后立即运行
conan lock create . --lockfile-out=conan.lock - 把
conan.lock提交到 Git —— 它记录了每个依赖的 exact revision、package ID 和远程源 - 后续所有模块构建都加
--lockfile=conan.lock参数:conan install . --lockfile=conan.lock --output-folder=build - CI 流水线也必须强制使用 lock 文件,否则“本地能编,CI 报错”就是典型症状
子模块需要差异化配置?用 requires + override 而非复制 conanfile
某些模块确实需要额外依赖或不同选项(比如 ui 模块要加 qt/6.7.2,且要求 shared=True),但又不想破坏整体一致性。这时候不该为它单独建一套 conanfile.py,而应在根 conanfile.py 中用条件逻辑控制:
- 保持主
requires列表不变,用self.requires("qt/6.7.2", override=True)在特定子模块的构建上下文中覆盖 - 或者用
self.options["qt"].shared = True显式设置选项,而非依赖 profile 默认值 - 更稳妥的做法是:把模块特有依赖声明在各自
CMakeLists.txt的find_package()中,并确保其Config.cmake已由根 conanfile 一并生成(即提前requires进去,只是不默认启用) - 避免在子模块里调用
conan install --profile单独安装 —— profile 冲突会直接导致package ID错配,出现 “找不到 target” 或 “undefined reference”
为什么不用 conanfile.txt 管理多模块?
conanfile.txt 看似简单,但在多模块场景下很快失控:
- 它不支持 Python 逻辑,无法做
if self.settings.os == "Windows"这类判断 - 没有
default_options或configure()方法,差异化选项只能靠外部--options传入,极易遗漏或拼错 - 无法复用已有
conanfile.py中定义的generate()行为(如自动生成 PCH、注入编译宏) - Conan 2.x 已明确将
conanfile.py作为推荐方式,conanfile.txt仅用于极简原型
真正容易被忽略的是:多模块项目中,build_type 和 compiler.version 这些 settings 必须全局对齐。哪怕一个子模块用了 -s build_type=Debug 而其余都是 Release,整个依赖图就会分裂成两套 package ID —— 最终链接时报错时,你看到的往往只是 “fmt::fmt not found”,而不是 “build_type mismatch”。


















