原文: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

发生了什么:

  1. Conan 从远程仓库 ConanCenter 下载了 zlib 的 recipe(配方文件)
  2. 下载了与你的平台/配置匹配的预编译二进制包
  3. build/ 目录生成了 CMake 工具链和依赖配置文件

常见错误:

  • ERROR: 'zlib/1.3.1' not found in remotes — 网络问题,检查能否访问 center2.conan.io
  • ERROR: 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

如果忘记激活环境,会报错:

  • WindowsThe code execution cannot proceed because zlib1.dll was not found
  • Linuxerror while loading shared libraries: libz.so.1: cannot open shared object file
  • macOSLibrary 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
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐