C++包管理工具:conan2使用教程
本节是一个实践性的动手教程,包含示例和真实代码,旨在按顺序从头到尾学习,并在你自己的计算机上运行练习。本节有一个“叙述性”结构,练习可能依赖于前面的解释和代码——建立在前一个示例的基础上。这是学习 Conan 的推荐方法。
重要提示:Conan 2 兼容性
本教程是为 Conan 2 编写的。虽然 Conan 1.X 的许多概念仍然适用,但具体的命令、工具名称和流程在 Conan 2 中可能有所不同。建议使用 Conan 2 来学习本教程。
1.1 使用包 (Consuming packages)
本节展示如何使用 Conan 管理依赖项来构建你的项目。我们将从一个使用 CMake 并依赖 zlib 库的 C 项目的基本示例开始。
我们还将介绍如何:
- 使用
tool_requires
管理构建工具(如 CMake)。 - 为不同的配置(如 Debug/Release、静态/动态链接)构建你的项目。
- 理解设置 (Settings) 和选项 (Options) 之间的区别。
- 使用
conanfile.py
替代conanfile.txt
以获得更大的灵活性。 - 使用两个配置文件(构建配置文件和主机配置文件)进行交叉编译。
最后,我们将介绍版本控制概念,包括使用版本范围、修订版本 (Revisions) 和锁文件 (Lockfiles) 以实现可重现性。
1.1.1 使用 CMake 构建一个简单项目
目标: 构建一个使用 zlib 库压缩字符串的应用程序。
步骤:
-
克隆示例:
$ git clone https://github.com/conan-io/examples2.git $ cd examples2/tutorial/consuming_packages/simple_cmake_project
-
检查项目结构:
CMakeLists.txt
: 项目构建脚本,包含对 zlib 的依赖。src/main.c
: 应用程序源代码。conanfile.txt
: Conan 依赖声明文件。
-
创建默认配置文件 (Profile):
Conan 使用配置文件定义构建配置(如编译器、架构、构建类型)。运行以下命令让 Conan 检测你的系统并创建默认配置文件:$ conan profile detect --force
这会生成一个名为
default
的配置文件,存储在 Conan 用户主目录 (~/.conan2/profiles/
) 下。 -
安装依赖项 (zlib):
运行 Conan 安装命令来获取 zlib 并生成 CMake 所需的文件:$ conan install . --output-folder=build --build=missing
--output-folder=build
: 指定生成文件输出到build
文件夹。--build=missing
: 如果本地缓存和远程仓库中没有预编译的 zlib 二进制包,则从源代码构建。
-
构建项目:
切换到build
文件夹,使用 CMake 配置和构建项目。注意需要传递 Conan 生成的工具链文件 (conan_toolchain.cmake
)。- Windows (示例使用 Visual Studio 2017):
$ cd build $ cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake $ cmake --build . --config Release $ Release\compressor.exe
- Linux/macOS:
$ cd build $ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release $ cmake --build . $ ./compressor
- Windows (示例使用 Visual Studio 2017):
-
验证输出:
如果成功,你应该看到类似以下的输出,显示压缩前后的字符串大小和使用的 zlib 版本:Uncompressed size is: 233 Compressed size is: 147 ZLIB VERSION: 1.2.11
关键点:
conanfile.txt
的[requires]
部分声明了项目依赖的库 (zlib)。[generators]
部分告诉 Conan 生成必要的文件(CMakeDeps
用于查找库,CMakeToolchain
用于传递构建信息)。conan install
处理依赖项的下载/构建和生成器的运行。- CMake 构建时需要使用
conan_toolchain.cmake
文件来集成 Conan 的设置。
1.1.2 使用 Conan 包作为构建工具 (tool_requires
)
目标: 使用 Conan 管理的特定版本 CMake 来构建项目,而不是系统安装的 CMake。
步骤:
-
克隆示例:
$ git clone https://github.com/conan-io/examples2.git $ cd examples2/tutorial/consuming_packages/tool_requires
-
修改
conanfile.txt
:
注意conanfile.txt
现在包含一个[tool_requires]
部分,指定了 CMake 版本:[requires] zlib/1.2.11 [tool_requires] # 声明构建工具依赖 cmake/3.22.6 [generators] CMakeDeps CMakeToolchain
-
安装依赖项 (zlib 和 CMake):
$ conan install . --output-folder=build --build=missing
Conan 会安装 zlib 和指定版本的 CMake。
-
激活构建环境:
Conan 自动生成了一个环境设置脚本 (conanbuild.bat
或conanbuild.sh
),用于将 Conan 安装的 CMake 路径添加到PATH
。- Windows:
$ cd build $ conanbuild.bat # 或者 .\conanbuild.ps1 (PowerShell)
- Linux/macOS:
$ cd build $ source conanbuild.sh
- Windows:
-
验证 CMake 版本:
$ cmake --version cmake version 3.22.6 ...
应该显示 Conan 安装的 CMake 版本 (3.22.6),而不是系统版本。
-
构建项目:
使用与之前相同的 CMake 命令构建项目。现在使用的是 Conan 提供的 CMake。 -
停用环境 (可选):
运行后生成的deactivate_conanbuild.bat
或source deactivate_conanbuild.sh
可以恢复原始环境。
关键点:
[tool_requires]
用于声明项目构建过程中需要的工具(如 CMake、Ninja)。VirtualBuildEnv
生成器会自动创建环境脚本 (conanbuild
),用于设置这些工具的路径。- 这确保了构建过程使用特定版本的工具,与系统环境隔离。
1.1.3 为不同配置构建:Release、Debug、静态库和共享库
目标: 学习如何为不同的构建类型 (Debug/Release) 和链接方式(静态库/共享库)配置和构建项目。
步骤:
-
克隆示例:
$ git clone https://github.com/conan-io/examples2.git $ cd examples2/tutorial/consuming_packages/different_configurations
-
理解配置文件 (Profile):
- 配置文件 (
~/.conan2/profiles/default
) 定义了全局设置,如os
,arch
,compiler
,build_type
。 - 运行
conan profile show default
查看内容。 - 可以创建不同的配置文件(如
debug
)来定义不同的配置。
- 配置文件 (
-
构建 Debug 版本:
- 通过
--settings
覆盖默认的build_type
:$ conan install . --output-folder=build --build=missing --settings=build_type=Debug
- 构建时指定
Debug
配置:- Windows:
$ cd build $ cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake $ cmake --build . --config Debug $ Debug\compressor.exe # 注意输出显示 "Debug configuration!"
- Linux/macOS:
$ cd build $ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug $ cmake --build . $ ./compressor # 注意输出显示 "Debug configuration!"
- Windows:
- 通过
-
构建共享库版本的 Zlib:
- 通过
--options
设置 zlib 的shared
选项为True
:$ conan install . --output-folder=build --build=missing --options=zlib/1.2.11:shared=True
- 构建项目(使用 Release 或 Debug 配置)。
- 运行问题: 尝试运行程序可能会失败,因为找不到 zlib 的共享库 (
.dll
,.so
,.dylib
)。
- 通过
-
解决共享库运行时依赖 (
VirtualRunEnv
):- Conan 为使用共享库的配置自动生成了
VirtualRunEnv
生成器,输出conanrun
脚本。 - 激活运行时环境以设置库搜索路径 (
PATH
,LD_LIBRARY_PATH
,DYLD_LIBRARY_PATH
):- Windows:
$ cd build $ conanrun.bat $ Release\compressor.exe # 现在应该可以运行了 $ deactivate_conanrun.bat
- Linux/macOS:
$ cd build $ source conanrun.sh $ ./compressor # 现在应该可以运行了 $ source deactivate_conanrun.sh
- Windows:
- Conan 为使用共享库的配置自动生成了
关键点:
- Settings vs Options:
Settings
(如build_type
,os
,compiler
): 通常是项目范围的配置,由客户端机器定义,不能在配方中设置默认值。它们影响二进制兼容性。Options
(如shared
,fPIC
): 是包特定的配置,可以在配方中设置默认值 (如default_options = {"shared": False}
)。它们通常不影响其他包的二进制兼容性。
- Package ID: Conan 使用
package_id
唯一标识一个包的特定二进制变体(基于设置、选项和依赖关系计算出的哈希值)。不同的配置会产生不同的package_id
。 - 共享库运行时: 使用共享库 (
shared=True
) 时,可执行文件在运行时需要能够找到这些库。VirtualRunEnv
生成器帮助设置必要的环境变量。
1.1.4 理解 conanfile.py
与 conanfile.txt
的灵活性
目标: 从 conanfile.txt
过渡到更强大的 conanfile.py
,利用 Python 代码的灵活性。
步骤:
-
克隆示例:
$ git clone https://github.com/conan-io/examples2.git $ cd examples2/tutorial/consuming_packages/conanfile_py
-
查看
conanfile.py
:from conan import ConanFile from conan.tools.cmake import cmake_layoutclass CompressorRecipe(ConanFile):settings = "os", "compiler", "build_type", "arch"generators = "CMakeToolchain", "CMakeDeps"def requirements(self):self.requires("zlib/1.2.11")def build_requirements(self):self.tool_requires("cmake/3.22.6")def layout(self):cmake_layout(self) # 使用内置的 CMake 布局
- 继承
ConanFile
类。 settings
: 定义影响二进制兼容性的设置。generators
: 指定使用的生成器。requirements()
: 定义库依赖项。build_requirements()
: 定义构建工具依赖项。layout()
: 定义项目的目录结构(源文件位置、构建目录、生成器输出目录)。cmake_layout()
提供了预定义的 CMake 项目布局。
- 继承
-
使用
conanfile.py
:
命令与使用conanfile.txt
类似,但不再需要--output-folder
:$ conan install . --build=missing $ cd build # 或者 cmake_layout 定义的构建目录 (如 build/Release) # ... 激活环境、运行 CMake 和构建命令 ...
关键点:
conanfile.py
提供了比conanfile.txt
更大的灵活性:- 使用 Python 代码动态定义依赖项(例如,基于设置添加条件依赖)。
- 覆盖或扩展 Conan 方法(如
configure()
,validate()
,generate()
,build()
)。 - 使用
layout()
方法明确定义项目结构。 - 更容易集成到复杂的构建系统或工作流中。
cmake_layout()
是一个辅助函数,简化了标准 CMake 项目的布局定义。
1.1.5 如何交叉编译你的应用程序:主机和构建上下文
目标: 学习如何在一种平台(构建平台,如 Ubuntu)上构建应用程序,使其在另一种平台(主机平台,如 Raspberry Pi)上运行。
概念:
- 构建上下文 (
profile:build
): 定义构建机器本身的平台(操作系统、架构、编译器)。构建工具(如 CMake)在此上下文中运行。 - 主机上下文 (
profile:host
): 定义最终二进制文件将运行的平台。你的应用程序及其库依赖项(如 zlib)在此上下文中构建。 - 两个配置文件: 交叉编译时需要两个配置文件:一个描述构建机器 (
--profile:build
),一个描述目标机器 (--profile:host
)。
步骤:
-
克隆示例:
$ git clone https://github.com/conan-io/examples2.git $ cd examples2/tutorial/consuming_packages/cross_building
-
准备配置文件:
- 构建配置文件 (
default
): 通常使用conan profile detect
创建的默认配置文件即可(描述你的 Ubuntu 机器)。 - 主机配置文件 (
raspberry
): 创建一个描述 Raspberry Pi (armv7hf, Linux) 的配置文件。示例内容 (profiles/raspberry
):[settings] os=Linux arch=armv7hf compiler=gcc compiler.version=9 build_type=Release compiler.cppstd=gnu14 compiler.libcxx=libstdc++11 [buildenv] CC=arm-linux-gnueabihf-gcc-9 CXX=arm-linux-gnueabihf-g++-9 LD=arm-linux-gnueabihf-ld
[buildenv]
部分设置交叉编译工具链的环境变量。
- 构建配置文件 (
-
安装依赖项并生成工具链:
使用两个配置文件运行conan install
:$ conan install . --build missing -pr:b=default -pr:h=./profiles/raspberry
-pr:b=default
: 指定构建配置文件。-pr:h=./profiles/raspberry
: 指定主机配置文件。
-
激活构建环境并构建:
$ cd build/Release # 根据 cmake_layout 或你的布局 $ source conanbuild.sh # 设置交叉编译工具链的环境变量 $ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release $ cmake --build .
-
验证目标架构:
使用file
命令检查生成的二进制文件:$ file compressor compressor: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, ... for GNU/Linux 3.2.0, not stripped
输出应显示为 ARM 架构。
关键点:
--profile:build
和--profile:host
明确区分了构建平台和目标平台。- 构建上下文 (
build
) 用于构建工具 (tool_requires
如 CMake)。 - 主机上下文 (
host
) 用于应用程序及其库依赖项 (requires
如 zlib)。 - 环境变量 (
[buildenv]
) 或特定的tool_requires
(如交叉编译器包) 用于设置交叉编译工具链。 - Conan 的生成器 (
CMakeToolchain
) 会根据主机配置文件生成正确的交叉编译 CMake 工具链文件。
1.1.6 版本控制介绍
目标: 了解 Conan 如何管理依赖项版本,包括固定版本、版本范围和锁文件。
概念:
- 固定版本 (
zlib/1.2.11
): 明确指定依赖的确切版本。 - 版本范围 (
zlib/[~1.2]
): 定义允许的版本范围(如~1.2
表示“大约 1.2”,接受 1.2.11, 1.2.12 但不接受 1.3.0)。范围解析总是选择范围内最新的版本。 - 修订版本 (Revisions): 当配方或源代码改变但版本号未提升时,Conan 使用修订版本(配方修订和包修订)来唯一标识这些变化。配方修订是配方和源代码内容的哈希值。包修订是包二进制内容的哈希值。
- 锁文件 (Lockfiles): 捕获整个依赖关系图在某个时间点的确切状态(包括版本、修订版本)。用于确保后续构建使用完全相同的依赖项,实现可重现性。
使用版本范围:
-
克隆示例:
$ git clone https://github.com/conan-io/examples2.git $ cd examples2/tutorial/consuming_packages/versioning
-
查看
conanfile.py
:def requirements(self):self.requires("zlib/[~1.2]") # 使用版本范围
-
安装依赖项:
$ conan install .
Conan 会解析范围
[~1.2]
并安装该范围内最新的 zlib 版本(例如 zlib/1.2.12)。
使用锁文件:
-
创建锁文件: 在依赖关系解析后捕获当前状态。
$ conan lock create .
生成
conan.lock
文件。 -
使用锁文件进行后续安装: 确保使用锁定的版本,即使有新版本可用。
$ conan install . # 自动使用 conan.lock 如果存在 # 或明确指定 $ conan install . --lockfile=conan.lock
关键点:
- 版本范围: 方便自动获取依赖项更新(补丁、次要版本),但可能引入不确定性。
- 修订版本: 确保即使版本号不变,配方或二进制内容的任何更改都能被跟踪和区分。对可重现性至关重要。
- 锁文件: 是保证依赖关系图完全可重现的推荐方法,特别是在 CI/CD 和生产环境中。它们锁定确切的版本和修订版本。