Conan 实战:从零开始使用第三方包
原文:Conan Documentation — Release 2.29.0
第一步:环境准备
安装 Conan
# 推荐使用 pip 安装
$ pip install conan
# 检查是否安装成功
$ conan --version
Conan version 2.29.0
新手常见错误:
如果提示
conan: command not found,说明 Python 脚本目录不在 PATH 中。
- Linux/macOS 尝试:
source ~/.profile- Windows 尝试:重启终端,或手动将 Python Scripts 目录加入 PATH
创建默认 profile
Conan 需要一个配置文件来知道你的编译器信息:
$ conan profile detect --force
输出示例(macOS):
Found apple-clang 14.0
apple-clang>=13, using the major as version
Detected profile:
[settings]
arch=x86_64
build_type=Release
compiler=apple-clang
compiler.cppstd=gnu17
compiler.libcxx=libc++
compiler.version=14
os=Macos
输出示例(Windows):
Found msvc 19.38
Detected profile:
[settings]
arch=x86_64
build_type=Release
compiler=msvc
compiler.cppstd=gnu17
compiler.runtime=dynamic
compiler.version=193
os=Windows
查看生成的 profile 文件:
$ conan profile path default
/Users/user/.conan2/profiles/default # Linux/macOS
C:\Users\user\.conan2\profiles\default # Windows
注意:如果系统有多个编译器(如 GCC 和 Clang),
conan profile detect会选一个。你可以手动编辑 profile 文件来切换编译器。
第二步:第一个 Conan 项目 — 字符串压缩器
我们创建一个使用 zlib 库进行字符串压缩的 C 语言程序。
获取示例代码
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/consuming_packages/simple_cmake_project
项目结构:
.
├── CMakeLists.txt
├── src
│ └── main.c
查看项目文件
src/main.c — 使用 zlib 压缩字符串:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <zlib.h>
int main(void) {
char buffer_in[256] = {
"Conan is a MIT-licensed, Open Source package manager "
"for C and C++ development..."
};
char buffer_out[256] = {0};
z_stream defstream;
defstream.zalloc = Z_NULL;
defstream.zfree = Z_NULL;
defstream.opaque = Z_NULL;
defstream.avail_in = (uInt) strlen(buffer_in);
defstream.next_in = (Bytef *) buffer_in;
defstream.avail_out = (uInt) sizeof(buffer_out);
defstream.next_out = (Bytef *) buffer_out;
deflateInit(&defstream, Z_BEST_COMPRESSION);
deflate(&defstream, Z_FINISH);
deflateEnd(&defstream);
printf("Uncompressed size is: %lu\n", strlen(buffer_in));
printf("Compressed size is: %lu\n", strlen(buffer_out));
printf("ZLIB VERSION: %s\n", zlibVersion());
return EXIT_SUCCESS;
}
CMakeLists.txt — 构建配置:
cmake_minimum_required(VERSION 3.15)
project(compressor C)
find_package(ZLIB REQUIRED)
add_executable(${PROJECT_NAME} src/main.c)
target_link_libraries(${PROJECT_NAME} ZLIB::ZLIB)
创建 conanfile.txt
在项目根目录创建 conanfile.txt:
[requires]
zlib/1.3.1
[generators]
CMakeDeps
CMakeToolchain
字段说明:
[requires]:声明项目需要的依赖包,格式为包名/版本号[generators]:告诉 Conan 生成哪些辅助文件CMakeDeps:生成 CMake 的find_package()配置文件CMakeToolchain:生成 CMake 工具链文件,传递编译设置
安装依赖
$ conan install . --output-folder=build --build=missing
参数说明:
.:使用当前目录下的conanfile.txt--output-folder=build:生成的辅助文件放到build目录--build=missing:如果本地没有缓存的二进制包,则从源码构建
完整输出:
-------- Computing dependency graph ----------
zlib/1.3.1: Not found in local cache, looking in remotes...
zlib/1.3.1: Checking remote: conancenter
zlib/1.3.1: Trying with 'conancenter'...
Downloading conanmanifest.txt
Downloading conanfile.py
Downloading conan_export.tgz
Decompressing conan_export.tgz
zlib/1.3.1: Downloaded recipe revision f1fadf0d3b196dc0332750354ad8ab7b
Graph root
conanfile.txt: .../simple_cmake_project/conanfile.txt
Requirements
zlib/1.3.1#f1fadf0d3b196dc0332750354ad8ab7b - Downloaded (conancenter)
-------- Computing necessary packages ----------
Requirements
zlib/1.3.1#f1fadf0d3b196dc0332750354ad8ab7b:cdc9a35e010a17fc90bb845108cf86cfcbce64bf
#dd7bf2a1ab4eb5d1943598c09b616121 - Download (conancenter)
-------- Installing packages ----------
Installing (downloading, building) binaries...
zlib/1.3.1: Retrieving package cdc9a35e0... from remote 'conancenter'
Downloading conanmanifest.txt
Downloading conaninfo.txt
Downloading conan_package.tgz
Decompressing conan_package.tgz
zlib/1.3.1: Package installed cdc9a35e0...
zlib/1.3.1: Downloaded package revision dd7bf2a1ab4eb5d1943598c09b616121
-------- Finalizing install (deploy, generators) ----------
conanfile.txt: Generator 'CMakeToolchain' calling 'generate()'
conanfile.txt: Generator 'CMakeDeps' calling 'generate()'
conanfile.txt: Generating aggregated env files
发生了什么:
- Conan 从远程仓库 ConanCenter 下载了 zlib 的 recipe(配方文件)
- 下载了与你的平台/配置匹配的预编译二进制包
- 在
build/目录生成了 CMake 工具链和依赖配置文件
常见错误:
ERROR: 'zlib/1.3.1' not found in remotes— 网络问题,检查能否访问center2.conan.ioERROR: Package binary could not be found— 你的平台没有预编译包,尝试加上--build=missing
构建项目
Windows(Visual Studio):
$ cd build
$ cmake .. -G "Visual Studio 17 2022" -DCMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"
$ cmake --build . --config Release
...
[100%] Built target compressor
$ Release\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.3.1
Linux/macOS:
$ cd build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .
...
[100%] Built target compressor
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.3.1
成功了! 你刚刚用 Conan 管理了第一个 C 项目的外部依赖。
使用 CMake Presets(可选,CMake >= 3.23)
Conan 的 CMakeToolchain 生成器还会生成 CMake presets 文件。如果使用较新版本的 CMake,可以更简洁地构建:
# 查看可用的 presets
$ cmake --list-presets
# 直接使用 preset 构建
$ cmake --preset default
$ cmake --build --preset default
第三步:使用构建工具作为 Conan 包
有时你需要使用特定版本的工具(如 CMake)来构建项目。Conan 可以通过 tool_requires 管理构建工具。
切换到示例目录
$ cd examples2/tutorial/consuming_packages/tool_requires
conanfile.txt
[requires]
zlib/1.3.1
[tool_requires]
cmake/3.27.9
[generators]
CMakeDeps
CMakeToolchain
注意:
[tool_requires]中的工具只用于当前项目的构建。如果 zlib 需要从源码构建,Conan 不会用这个 CMake 版本来构建 zlib——它会用系统 CMake。
CMakeLists.txt(新增版本显示)
cmake_minimum_required(VERSION 3.15)
project(compressor C)
find_package(ZLIB REQUIRED)
message("Building with CMake version: ${CMAKE_VERSION}")
add_executable(${PROJECT_NAME} src/main.c)
target_link_libraries(${PROJECT_NAME} ZLIB::ZLIB)
安装依赖
$ conan install . --output-folder=build --build=missing
输出:
-------- Computing dependency graph ----------
cmake/3.27.9: Not found in local cache, looking in remotes...
cmake/3.27.9: Checking remote: conancenter
cmake/3.27.9: Trying with 'conancenter'...
Downloading conanmanifest.txt
Downloading conanfile.py
cmake/3.27.9: Downloaded recipe revision 3e3d8f3a848b2a60afafbe7a0955085a
Graph root
conanfile.txt: .../tool_requires/conanfile.txt
Requirements
zlib/1.3.1#f1fadf0d3b196dc0332750354ad8ab7b - Cache
Build requirements
cmake/3.27.9#3e3d8f3a848b2a60afafbe7a0955085a - Downloaded (conancenter)
-------- Installing packages ----------
cmake/3.27.9: ... - Download (conancenter)
...
zlib/1.3.1: Already installed!
-------- Finalizing install ----------
conanfile.txt: Generator 'CMakeToolchain' calling 'generate()'
conanfile.txt: Generator 'CMakeDeps' calling 'generate()'
可以看到 Conan 自动生成了一个 conanbuild.{sh,bat} 环境激活脚本。
激活环境并使用指定的 CMake 版本
Windows:
$ cd build
$ conanbuild.bat
# 或者 if using Powershell: conanbuild.ps1
Linux/macOS:
$ cd build
$ source conanbuild.sh
Capturing current environment in deactivate_conanbuildenv-release-x86_64.sh
Configuring environment variables
验证 CMake 版本:
$ cmake --version
cmake version 3.27.9
构建项目
Windows:
$ cmake .. -G "Visual Studio 17 2022" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake
$ cmake --build . --config Release
...
Building with CMake version: 3.27.9
...
[100%] Built target compressor
$ Release\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.3.1
Linux/macOS:
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .
...
Building with CMake version: 3.27.9
...
[100%] Built target compressor
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.3.1
还原环境
# Windows
$ deactivate_conanbuild.bat
# Linux/macOS
$ source deactivate_conanbuild.sh
Restoring environment
$ cmake --version
cmake version 3.22.0
第四步:多配置构建 — Debug / Release / 静态 / 共享
查看默认 profile
$ conan config home
Current Conan home: /Users/user/.conan2
$ cat /Users/user/.conan2/profiles/default
[settings]
os=Macos
arch=x86_64
compiler=apple-clang
compiler.version=14.0
compiler.libcxx=libc++
compiler.cppstd=gnu11
build_type=Release
创建 Debug profile
创建文件 <conan home>/profiles/debug:
[settings]
os=Macos
arch=x86_64
compiler=apple-clang
compiler.version=14.0
compiler.libcxx=libc++
compiler.cppstd=gnu11
build_type=Debug
使用命令行设置构建配置(不创建 profile)
切换目录:
$ cd examples2/tutorial/consuming_packages/different_configurations
安装 Debug 配置:
$ conan install . --output-folder=build --build=missing --settings=build_type=Debug
安装 Release 配置:
$ conan install . --output-folder=build --build=missing --settings=build_type=Release
使用共享库(shared libraries)
$ conan install . --output-folder=build --build=missing --options="zlib/*:shared=True"
运行共享库版本时注意:
共享库在运行时需要能找到 .dll / .dylib / .so 文件。Conan 会自动生成 conanrun.{sh,bat} 脚本来设置环境变量:
# Linux/macOS
$ source conanrun.sh
$ ./compressor
# Windows
$ conanrun.bat
$ Release\compressor.exe
如果忘记激活环境,会报错:
- Windows:
The code execution cannot proceed because zlib1.dll was not found - Linux:
error while loading shared libraries: libz.so.1: cannot open shared object file - macOS:
Library not loaded: @rpath/libz.1.dylib
Settings vs Options — 关键区别
| Settings | Options | |
|---|---|---|
| 范围 | 项目全局,由客户端机器定义 | 包级别,可在 recipe 中设置默认值 |
| 示例 | 操作系统、架构、编译器、构建类型 | shared(共享/静态)、fPIC |
| 能否在 recipe 中设默认值 | 不能(由消费者决定) | 能(比如默认静态链接) |
Package ID 是如何工作的?
Conan 根据 settings、options 和依赖计算出一个哈希值作为 package_id:
不同配置 → 不同的 package_id → 不同的二进制包
build_type=Release → package_id = abc123...
build_type=Debug → package_id = def456...
shared=True → package_id = ghi789...
这就是为什么 zlib 的 Release 和 Debug 版本是不同的二进制包。
第五步:从 conanfile.txt 升级到 conanfile.py
conanfile.txt 简单但功能有限,conanfile.py 可以用 Python 代码实现条件依赖、动态配置等高级功能。
切换到示例目录
$ cd examples2/tutorial/consuming_packages/conanfile_py
对比:conanfile.txt vs conanfile.py
conanfile.txt:
[requires]
zlib/1.3.1
[tool_requires]
cmake/3.27.9
[generators]
CMakeDeps
CMakeToolchain
等效的 conanfile.py:
from conan import ConanFile
class CompressorRecipe(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "CMakeToolchain", "CMakeDeps"
def requirements(self):
self.requires("zlib/1.3.1")
def build_requirements(self):
self.tool_requires("cmake/3.27.9")
conanfile.py 的优势 — 条件依赖
from conan import ConanFile
class CompressorRecipe(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "CMakeToolchain", "CMakeDeps"
def requirements(self):
self.requires("zlib/1.3.1")
if self.settings.os == "Windows":
self.requires("base64/0.4.0")
def build_requirements(self):
if self.settings.os != "Windows":
self.tool_requires("cmake/3.27.9")
第六步:交叉编译
交叉编译就是在一个平台上构建另一个平台能运行的程序。Conan 使用两个 profile 来实现:
--profile:build:当前构建机器的 profile--profile:host:目标运行平台的 profile
例如,从 x86_64 Linux 为 ARMv7 交叉编译:
$ conan profile detect --force --profile=profile_armv7
$ conan install . --profile:build=default --profile:host=profile_armv7
完整示例:从 x86_64 Linux 编译到 ARM Raspberry Pi
build profile (default):
[settings]
os=Linux
arch=x86_64
compiler=gcc
compiler.version=12
compiler.libcxx=libstdc++11
compiler.cppstd=gnu17
build_type=Release
host profile (raspberry):
[settings]
os=Linux
arch=armv7hf
compiler=gcc
compiler.version=12
compiler.libcxx=libstdc++11
compiler.cppstd=gnu17
build_type=Release
[buildenv]
CC=arm-linux-gnueabihf-gcc-12
CXX=arm-linux-gnueabihf-g++-12
LD=arm-linux-gnueabihf-ld
安装依赖:
$ conan install . --build missing -pr:b=default -pr:h=./profiles/raspberry
构建:
$ cd build
$ source Release/generators/conanbuild.sh
Capturing current environment in deactivate_conanbuildenv-release-armv7hf.sh
Configuring environment variables
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=Release/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .
...
-- The C compiler identification is GNU 12.4.0
-- Check for working C compiler: /usr/bin/arm-linux-gnueabihf-gcc-12 - skipped
...
[100%] Built target compressor
验证:
$ file compressor
compressor: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, ...
第七步:版本管理介绍
版本范围
def requirements(self):
self.requires("zlib/[~1.2]")
范围解析示例:
$ conan install .
Graph root
conanfile.py: .../conanfile.py
Requirements
zlib/1.2.12#87a7211557b6690ef5bf7fc599dd8349 - Downloaded
Resolved version ranges
zlib/[~1.2]: zlib/1.2.12
常用范围表达式:
| 表达式 | 含义 | 匹配示例 |
|---|---|---|
[>=1.0 <2.0] |
在范围内 | 1.0, 1.5, 1.9 |
[~1.2] |
近似 1.2.x | 1.2.8, 1.2.12 |
[~1] |
近似 1.x | 1.3, 1.8 |
[^2.5] |
>=2.5 ❤️.0 | 2.5.0, 2.9 |
[>3.10] |
大于 3.10 | 3.11, 3.27.9 |
Revisions(修订版本)
$ conan list "zlib/1.2.12#*" -r=conancenter
conancenter
zlib
zlib/1.2.12
revisions
82202701ea360c0863f1db5008067122 (2022-03-29 15:47:45 UTC)
bd533fb124387a214816ab72c8d1df28 (2022-05-09 06:59:58 UTC)
...
Lockfiles(锁定文件)
# 生成 lockfile
$ conan lock create .
-------- Computing dependency graph ----------
Graph root
conanfile.py: .../conanfile.py
Requirements
zlib/1.2.11#4524fcdd41f33e8df88ece6e755a5dcc - Cache
Generated lockfile: .../conan.lock
# conan.lock 内容:
{
"version": "0.5",
"requires": [
"zlib/1.2.11#4524fcdd41f33e8df88ece6e755a5dcc%1650538915.154"
],
"build_requires": [],
"python_requires": []
}
即使 recipe 改为 zlib/[~1.2] 版本范围,lockfile 会强制使用 zlib/1.2.11:
$ conan install .
Graph root
Requirements
zlib/1.2.11#4524fcdd41f33e8df88ece6e755a5dcc - Cache
常见错误排查
| 错误信息 | 原因 | 解决 |
|---|---|---|
conan: command not found |
Conan 未在 PATH 中 | source ~/.profile 或重启终端 |
Package binary could not be found |
没有对应平台的预编译包 | 加 --build=missing 从源码构建 |
Library not loaded: @rpath/libz.1.dylib |
共享库未找到 | source conanrun.sh 激活运行环境 |
ERROR: Version conflict |
依赖版本冲突 | 使用 lockfile 或版本范围解决 |
error: externally-managed-environment |
Linux 系统禁止 pip 全局安装 | 使用 pipx 或虚拟环境 |
ERROR: 'profile' not found |
没有创建 profile | 运行 conan profile detect |
更多推荐
所有评论(0)