使用 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/。
留爪
这么乱几个工具倒来倒去,一会文本一会命令行,还觉得比vcpkg优雅,到底为什么呢。。。
[...]原文地址[...]