TimothyQiu's Blog

keep it simple stupid

使用 Conan 管理 C++ 依赖

分类:技术

现代 CMake 使用 C++ 依赖项时已经相对方便了。比如 find_package(OpenSSL 1.0 REQUIRED) 就可以自动在本地机器上查找已安装的与 OpenSSL 1.0 兼容的包,然后就可以直接 target_link_libraries(targetName PRIVATE OpenSSL::SSL) 使用,不必再手动写头文件和库文件配置。

要做到「本地机器上已安装」,macOS 和 Linux 系统都非常方便,大多数库都可以直接通过系统级包管理工具安装,而 Windows 上就稍显麻烦。我之前比较喜欢的是,比较复杂的库还是留着在各平台手动安装,简单的则使用 CMake 的 FetchContent 模块下载使用。但这样的缺点是每次重新生成工程时,都需要下载一遍依赖并编译。尤其最近国内的网络状态,HTTPS 连接 GitHub 经常超慢。所以想想还是用现成的包管理工具吧。

目前市面上流行的包管理工具中:vcpkg 虽然很多人用,但是微软那套逻辑我始终表示审美不能;Hunter 虽然是纯 CMake 解决方案,但是官方涵盖的库偶有不足;而 Conan 我一开始是不喜欢的,不但需要使用 Python 安装,而且它的前世 biicode 当年也风光过现在已经挂了。不过现在看来,Conan 似乎是这几个之中比较成熟好用的解决方案,至少,符合我的审美就是了。

安装

官方推荐用 Python 在虚拟环境里用 pip install conan 安装,可以随时保持最新。

我在 macOS 上使用 Homebrew 安装,可以少管理一个虚拟环境。感觉 Arch Linux 这样滚动更新的系统也可以直接使用系统包管理工具安装。

找到想要的库

想要使用 spdlog 时,首先搜索:

$ conan search spdlog -r conan-center
Existing package recipes:

spdlog/0.14.0@bincrafters/stable
spdlog/0.16.3@bincrafters/stable
spdlog/0.17.0@bincrafters/stable
spdlog/1.0.0@bincrafters/stable
spdlog/1.1.0@bincrafters/stable
spdlog/1.2.1@bincrafters/stable
spdlog/1.3.0@bincrafters/stable
spdlog/1.3.1@bincrafters/stable
spdlog/1.4.1@bincrafters/stable
spdlog/1.4.2
spdlog/1.4.2@bincrafters/stable
spdlog/1.5.0

命令行中的 -r conan-center 表示所要搜索的仓库,conan-center 是官方自带的默认仓库,如果你本地添加了多个仓库的话,也可以用 all 表示搜索所有仓库。不带这个选项时则是在本地的缓存中查找。

搜索结果中每一行都是一个可用的包的名称,使用 @user/channel 后缀的是完整的包命名方式。官方 conan-center 仓库中,最近的包都是通过 CI 自动构建二进制文件的,这些包使用name/version 的命名方式。

想要知道某个版本/包的详情,可以使用这样的命令查看:

$ conan inspect spdlog/1.5.0

会列出一些信息和安装时的可选参数。

当然,你也可以直接在网站 https://conan.io/center/ 查找 conan-center 仓库中的包。

依赖的指定、安装、使用

一般使用名为 conanfile.txt 的纯文本文件指定依赖,格式类似 INI 文件。

[requires]
spdlog/1.5.0

[generators]
cmake_find_package

[requires] 部分很简单,列出你所需要依赖的包的名称即可。[generators] 部分指定所需要的「生成器」,可以生成与 CMake、SCons 等工具的对接文件。

使用 conan install /path/to/source-dir 可以安装依赖并生成对接文件,参数为包含 conanfile.txt 的目录。当然,这样做会把「对接文件」生成在当前目录,可以使用 -if 参数指定输出目录,推荐放在 CMake 的构建目录。

这样,Conan 就会把 1.5.0 版本的 spdlog 安装到自己管理的目录(一般是 ~/.conan),然后在输出目录输出一个 Findspdlog.cmake 文件。

CMakeLists.txt 中,要让 find_package 使用 Findspdlog.cmake 文件,把它所在的目录加入到 CMAKE_MODULE_PATH 中即可:

# 因为我们把 Findspdlog.cmake 输出到了构建目录
list(APPEND CMAKE_MODULE_PATH "${CMAKE_BINARY_DIR}")

# 按照正常方式搜索
find_package(spdlog REQUIRED)

# ...

# 这个生成器导出的目标是 package::package
target_link_libraries(targetName PRIVATE spdlog::spdlog)

当然,官方教程中使用的是 cmake 生成器,它不会生成 FindXXX.cmake,而是生成一个 conanbuildinfo.cmake,你需要在 CMakeLists.txt 中手动初始化:

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

# ...

# 这个生成器导出的目标是 CONAN_PKG::package
target_link_libraries(targetName PRIVATE CONAN_PKG::spdlog)

这种方法把 Conan 显式写入了 CMake 配置里,我个人不是很喜欢。(但是 CONAN_PKG::package 的表述确实比 package::package 好一些,因为一些库官方提供的目标并不都是 package::package。)

其它零碎

构建版本

Conan 默认安装/构建的二进制是 Release 版本的。而 CMake 的默认构建方式则是 Debug。

所以,尤其在使用类似 MSVC 的编译器时,你可能需要手动指定安装 Debug 版:

$ conan install . -s build_type=Debug

当然你也可以试试 cmake_multi 或者 cmake_find_package_multi 生成器,可以同时安装 Debug 和 Release 版本。抑或是使用官方提供的CMake 集成,自己写脚本把 CMake 和 Conan 的构建类型同步起来。

包的参数

在使用 conanfile.txt 指定依赖时,还可以同时指定一些可选参数。比如指定使用 spdlog 的动态链接版本:

[options]
spdlog:shared=True

好了,这就是大致的 Conan 使用介绍。

真正上手,还请参阅官方文档 https://docs.conan.io/

C++

仅有一条评论 »

  1. meki meki

    留爪

添加新评论 »