第91章:使用Conan:集成Conan包管理器

说实话,C++的包管理一直是个让人头疼的问题。Python有pip,JavaScript有npm,Java有maven,而我们C++开发者呢?要么手动下载源码编译,要么写一堆find_package脚本。直到Conan出现,这个局面才真正改观。

我个人是从Conan 1.x时代就开始用了。那时候功能还没现在这么完善,但已经能解决我80%的依赖管理问题。到了Conan 2.x,嗯,可以说真正成熟了。今天我们就来聊聊,怎么在CMake项目中集成Conan。

Conan是什么?

Conan是一个去中心化的C/C++包管理器。说白了,它帮你做三件事:

  • 下载依赖:从远程仓库拉取第三方库
  • 编译依赖:根据你的编译器、架构、配置(Debug/Release)自动编译
  • 集成到CMake:生成CMake可用的配置文件,让你直接用find_package

我在项目中遇到过最典型的场景:团队里有人用VS2022,有人用Clang,还有人用GCC。每个库都要各自编译一遍,版本还经常对不上。用了Conan之后,一个conanfile.txt就搞定了所有。

核心概念速览

先看一张图,帮你快速理解Conan的工作流程:

Conan 包管理流程 1. 定义依赖 conanfile.txt 声明库名和版本 2. conan install 下载+编译依赖 生成 conanbuildinfo.cmake 3. CMake集成 find_package target_link_libraries conanfile.txt 示例: [requires] fmt/10.1.1 spdlog/1.12.0 [generators] CMakeDeps CMakeToolchain CMakeLists.txt 集成: # 使用预设的 toolchain find_package(fmt REQUIRED) find_package(spdlog REQUIRED) target_link_libraries(myapp fmt::fmt spdlog::spdlog) 💡 Conan 2.x 推荐使用 CMakeDeps + CMakeToolchain 组合

实战:从零开始集成Conan

我们用一个真实项目来演示。假设你要写一个日志工具,依赖fmt和spdlog。传统做法是手动下载源码,然后add_subdirectory。用Conan呢?三步走。

第一步:写conanfile.txt

在项目根目录创建这个文件:

[requires]
fmt/10.1.1
spdlog/1.12.0

[generators]
CMakeDeps
CMakeToolchain

[layout]
cmake_layout

这里我解释一下:

  • requires:声明你要用哪些库,版本号要写清楚。Conan会去远程仓库找对应的包。
  • generators:告诉Conan生成什么类型的CMake集成文件。CMakeDeps生成find_package需要的配置文件,CMakeToolchain生成编译器设置。
  • layout:指定项目目录结构。cmake_layout是Conan 2.x推荐的布局方式。
小技巧: 如果你不确定某个库在Conan里的名字,可以用 conan search 库名 来查。我个人习惯先在ConanCenter(conan.io/center)上搜一下,确认版本号再写。

第二步:编写CMakeLists.txt

这是集成后的CMake文件:

cmake_minimum_required(VERSION 3.24)
project(MyLogger VERSION 1.0.0 LANGUAGES CXX)

# 设置C++标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 查找Conan生成的依赖
find_package(fmt REQUIRED)
find_package(spdlog REQUIRED)

# 添加可执行文件
add_executable(my_logger main.cpp)

# 链接库
target_link_libraries(my_logger
    PRIVATE
        fmt::fmt
        spdlog::spdlog
)

注意这里没有add_subdirectory,也没有手动设置include目录。Conan生成的CMakeDeps文件已经帮你做好了所有路径配置。

第三步:构建项目

构建命令和传统方式略有不同:

# 1. 安装依赖(只需要执行一次)
conan install . --build=missing

# 2. 配置CMake(使用Conan生成的toolchain)
cmake --preset conan-default

# 3. 编译
cmake --build --preset conan-release

为什么会多一个conan install步骤?因为Conan要先下载并编译依赖,生成CMake能用的配置文件。--build=missing的意思是:如果本地没有预编译好的二进制包,就自动从源码编译。

注意: 如果你换了编译器或者改了构建配置(比如从Debug切到Release),记得重新执行 conan install。我曾经因为这个踩过坑——换了编译器没重新install,结果链接了一堆不兼容的库,编译报错找了半天。

Conan 2.x vs 1.x:关键变化

如果你之前用过Conan 1.x,下面这个表格能帮你快速了解2.x的变化:

特性 Conan 1.x Conan 2.x
生成器 cmake(生成conanbuildinfo.cmake) CMakeDeps + CMakeToolchain
配置文件 conaninfo.txt conaninfo.txt + CMake presets
构建方式 手动指定toolchain文件 cmake --preset 自动加载
包格式 旧格式(兼容性差) 新格式(更小更快)
推荐度 不再推荐新项目使用 强烈推荐

我个人建议:新项目直接上Conan 2.x。如果你在维护老项目,可以逐步迁移,但别拖太久——Conan 1.x已经进入维护模式了。

避坑指南

用Conan这几年,我踩过不少坑。挑几个典型的说说:

  • 版本冲突:两个库依赖了同一个库的不同版本。比如库A要fmt 9.x,库B要fmt 10.x。Conan会报错。解决办法是升级或降级其中一个库,让它们统一版本。
  • 二进制兼容性:用MSVC编译的库,不能链接到MinGW的项目里。Conan会按settings区分,但如果你手动改了settings,就可能出问题。
  • 缓存问题:有时候改了conanfile.txt,但Conan用了缓存里的旧包。加个--update参数可以强制刷新。

核心要点:

  • Conan解决的是C++依赖管理的痛点——自动下载、编译、集成
  • conanfile.txt声明依赖,CMakeDeps生成CMake集成文件
  • 构建流程:conan install → cmake --preset → cmake --build
  • 新项目用Conan 2.x,老项目逐步迁移

好了,关于Conan集成就聊这么多。说白了,它就是给C++项目装了个包管理器,让依赖管理变得像Python一样简单。你想想看,以前手动编译第三方库要花多少时间?现在一个conan install就搞定了,省下来的时间干点啥不好?

公众号:蓝海资料掘金营,微信 deep3321