requirements()仅声明直接依赖并由cmakedeps为其生成xxx-config.cmake,不处理传递依赖;generators指定cmaketoolchain和cmakedeps组合,禁用已弃用的cmake_find_package;conan_toolchain.cmake须在project()前引入,conan_deps.cmake须在project()后、find_package()前引入。

conanfile.py 里 requirements() 和 generators 要分清职责
很多人把所有依赖写进 requirements(),再一股脑配 CMakeDeps,结果 CMake 找不到某些库——问题常出在「依赖是否真正被生成了配置」。CMakeDeps 只为 requires() 声明的包生成 xxx-config.cmake,但不会处理 transitive(传递)依赖里的非直接 requirement。比如你 requires("opencv/4.9.0"),它内部依赖 zlib 和 libjpeg,这些不会自动暴露给你的 CMakeLists.txt。
解决办法是:明确哪些库你代码里 #include 并 target_link_libraries(),就只在 requires() 里写哪些;其余靠 opencv 自身链接的,不用管。若真要单独控制 zlib 版本或选项,才显式加一行 self.requires("zlib/1.3")。
另外,generators = "CMakeDeps", "CMakeToolchain" 是最简组合,别加 cmake_find_package(Conan 2.x 已弃用),否则会和 CMakeDeps 冲突,导致 find_package() 找到重复定义。
CMakeLists.txt 中 include() 顺序不能错
Conan 生成的两个关键文件:conan_toolchain.cmake(含编译器、标准、架构等设置)和 conan_deps.cmake(含 find_package(fmt CONFIG) 等逻辑),必须按顺序引入:
-
include(${CMAKE_BINARY_DIR}/conan_toolchain.cmake)必须放在project()之前,否则 CMake 不会按 Conan 指定的compiler.cppstd解析标准库 -
include(${CMAKE_BINARY_DIR}/conan_deps.cmake)必须放在project()之后、find_package()之前,否则变量作用域不对
常见错误是把两者都塞在 project() 后面,结果 set(CMAKE_CXX_STANDARD 17) 被覆盖,或者 find_package(fmt REQUIRED CONFIG) 报 “Could not find a package configuration file”。
多依赖时 settings 和 options 容易混在一起
当你同时用 fmt/10.2.1、boost/1.85.0、openssl/3.3.2,它们对 shared、fPIC、with_zlib 等选项的默认值可能冲突。Conan 不会帮你“协调”,而是按每个包自己的 options 构建独立二进制,只要最终 ABI 兼容就行。
CMake 4.3.2 Windows x86_64 历史版本安装包,适合旧项目兼容、构建环境回退、CMakeLists.txt 迁移验证、Visual Studio/Ninja/Makefile 生成器测试和 C/C++ 项目维护。
但实际中容易踩坑的地方有:
-
conan install . --build=missing -o fmt:shared=True -o boost:shared=False:混合动静态链接,在 Windows 上大概率报 LNK2005 或 CRT 冲突 -
-s compiler.libcxx=libstdc++11和-s compiler.libcxx=libc++混用:C++ 标准库不一致,std::string传参直接崩溃 - 没指定
-s build_type=Release却在 CMake 里用RelWithDebInfo:Conan 缓存里找不到匹配二进制,强制源码构建,耗时且易失败
建议统一用 profile 文件管理这些设置,比如 conan profile update settings.build_type=Release default,避免每次命令行敲一长串。
依赖版本冲突时不要硬删 ~/.conan2
当 conan install 报 “Conflict in zlib/1.2.11 vs zlib/1.3” 时,有人习惯直接清空本地缓存目录。这看似干净,实则破坏复现性——你刚构建好的 fmt 二进制也丢了,下次 --build=missing 又得重编。
更稳妥的做法是:
- 用
conan list "*"查当前缓存里有哪些 zlib 版本 - 用
conan remove "zlib/*"精准删掉冲突包,保留其他 - 检查
conanfile.py里是否写了self.requires("zlib/1.2.11")和self.requires("openssl/3.3.2")(后者自带 zlib 依赖),这时应显式固定 openssl 的 zlib 子依赖:self.requires("openssl/3.3.2", options={"with_zlib": False})
Conan 的二进制 ID 是 settings + options 的哈希,哪怕只差一个 fPIC=True,就是另一个缓存条目——组织清楚的关键,其实是让每个依赖的构建上下文可追溯、可复现,而不是追求“看起来干净”。










