TDengine 将所有 conanfile.py 统一放在 conan/ 子目录下,与主 CMakeLists.txt 分离,以明确区分“包构建”与“代码编译”职责;header-only 库需设 no_copy_source=True,conan install 必须在 build/ 目录执行并严格对齐 profile 与生成器。

conanfile.py 该放项目根目录还是单独建 conan/ 子目录
必须和源码仓库的构建逻辑对齐,不是凭感觉放。TDengine 的实践是把所有 conanfile.py 统一放在 conan/ 子目录下,和主 CMakeLists.txt 分离——因为它们服务对象不同:conan/ 下的配方只管「包怎么建」,主项目只管「代码怎么编」。
常见错误是把 conanfile.py 直接丢进项目根目录,结果导致:conan create 时误读项目源码为包源、profile 覆盖被污染、CI 中多版本并行构建失败。
- header-only 库(如
cppstub)的conanfile.py必须显式声明no_copy_source = True,否则 Conan 会试图复制空源目录,报source() method not defined - 用
ExternalProject_Add迁移过来的旧项目,conanfile.py的source()方法要指向原始第三方 repo 的url和commit,不能写相对路径 - 如果项目本身要发布为 Conan 包(比如你写的 SDK),才把
conanfile.py放在根目录,且需重写package()逻辑,把头文件和库文件按self.copy()规则导出
profile 文件怎么随 Git 提交又不锁死环境
profile 是「用哪把刀编」的声明,它必须进 Git,但不能硬编码绝对路径或用户名。TDengine 的 profiles/linux_gcc11 示例里,toolchain 指向的是相对路径 ../toolchains/gcc11.cmake,而非 /home/user/toolchains/...。
直接运行 conan profile detect 生成的 profile 不建议提交:它会塞入本地 compiler.version、compiler.libcxx 等不可复现字段,CI 构建时大概率报 Cannot find a valid package。
- profile 中的
[env]段只写必要变量,比如CC=/opt/gcc-11/bin/gcc,别写PATH全量覆盖 - 交叉编译 profile 必须显式设
target_host和sysroot,例如嵌入式场景下漏掉sysroot=/opt/arm64-sysroot,链接阶段会找不到libc.a - 用
conan profile update settings.compiler.version=11手动调参,比编辑文本更安全;改完立刻跑conan profile show linux_gcc11核对
CMakeLists.txt 怎么无侵入接入 Conan 生成的配置
关键不是改 CMake 逻辑,而是让 Conan 的输出「自动注入」。TDengine 使用 CMakeToolchain + CMakeDeps 两个生成器,对应 CMake 中两行:
include(${CMAKE_BINARY_DIR}/conan_toolchain.cmake)
find_package(fast-lzma2 CONFIG REQUIRED)
注意:conan_toolchain.cmake 必须在 project() 之前 include,否则编译器标志(如 -march=armv8-a)不会生效;而 find_package 必须在 project() 之后,否则 CONFIG 模式找不到 fast-lzma2Config.cmake。
- 不要手动写
link_directories()或include_directories()——CMakeDeps已通过fast-lzma2Targets.cmake注入全部路径 - 若依赖是 header-only(如
cppstub),find_package(cppstub)后无需target_link_libraries(),但必须确保target_include_directories(your_target PRIVATE ${cppstub_INCLUDE_DIRS}),因为CMakeDeps不自动生成 target 接口 - 使用
DEP_ext_*宏兼容旧构建逻辑时,宏定义必须在conan install生成的conanbuildinfo.cmake加载之后,否则变量为空
conan install 命令该在哪个目录执行、带什么参数
必须在构建目录(build/)里执行,且参数要和 profile、生成器、锁定文件三者严格对齐。典型命令是:
conan install .. -pr:h=conan/profiles/linux_gcc11 -pr:b=default -g=CMakeToolchain -g=CMakeDeps -b=missing
这里 -pr:h 是 host profile(目标平台),-pr:b 是 build profile(构建机平台),两者不同时(比如 x86_64 编译 arm64 包),漏掉 -pr:b 就会用 host profile 反向构建工具链,报 Cannot build compiler wrapper for profile。
-
-b=missing表示缺二进制就现场编译,CI 中应换为-b=cache防止意外触发源码编译拖慢流水线 - 首次运行后生成
conan.lock,这个文件必须提交 Git —— 它锁定了所有传递依赖的 exact 版本,比如zlib/1.3.1#7f5a0e... → openssl/3.2.1#9a1b2c... - 如果
conan install报Conflict in xxx: requirement yyy conflicts with zzz,不是删 lock 文件重来,而是用conan list "xxx/*" --graph=deps.html查依赖图,定位冲突源头
最易忽略的一点:profile 里写的 compiler.version=11 和你实际 gcc --version 输出的 11.4.0 并不等价;Conan 只认主版本号,但如果你 profile 写了 compiler.version=11.4,它就会去匹配不存在的 gcc-11.4 工具链,整个构建静默失败。


















