conan 2.0 Getting Started

系列文章目录


文章目录


前言

C++包管理工具conan简介。

conan实际上是用python编写的一个python module,用于C/C++的包管理,基于C/S模式,client向server端请求二进制包。

构建工具栈:

复制代码
+-------------------------+
| conan                   |
+-------------------------+
| cmake(or others)        |
+-------------------------+
| make(or others)         |
+-------------------------+
| gcc(or others)          |
+-------------------------+

0、安装

复制代码
# 安装python虚拟环境管理模块
pip install venv
# 创建虚拟环境
# 这里会在当前目录下创建一个.venv目录,
python3 -m venv ./.venv
# 激活虚拟环境。 激活虚拟环境后所有通过pip安装的模块都会在该目录下,不会与全局环境冲突
source .venv/bin/activate
# 在虚拟环境中安装conan
pip install conan

分享依赖给他人

sh 复制代码
# 导出当前依赖
pip freeze > requirements.txt
# 安装所有需要的模块
pip install -r requirements.txt

一、使用conan管理项目依赖

使用conan构建一个简单的CMake项目

sh 复制代码
├── CMakeLists.txt
├── conanfile.txt
└── src
    └── main.c

CMakeLists.txt

cmake 复制代码
find_package(ZLIB REQUIRED)

conanfile.txt
[requires] 段用于声明项目中需要用到的库
[generators] 段告诉 Conan 生成一个文件,该文件将用于编译器或构建系统查找依赖项和构建项目。在本例中,由于我们的项目基于 CMake,我们将使用 CMakeDeps 来生成有关 Zlib 库文件安装位置的信息,并使用 CMakeToolchain 通过 CMake 工具链文件将构建信息传递给 CMake。

conan 复制代码
[requires]
zlib/1.3.1

[generators]
CMakeDeps
CMakeToolchain

Conan profile 允许用户定义配置,如,指定编译器、构建选项、架构、共享或静态库等。Conan默认不自动检测profile

sh 复制代码
# 该指令
conan profile detect --force

这将根据环境检测操作系统、构建架构和编译器设置。它还会默认将构建配置设置为"Release"。生成的配置文件将以"default"的名称存储在Conan的主文件夹中,除非通过命令行指定了其他配置文件,否则Conan在所有命令中都会默认使用该配置文件。

sh 复制代码
conan install . --output-folder=build --build=missing
  • Conan从远程服务器安装了Zlib库,如果该库可用,默认情况下该服务器应为Conan Center服务器。此服务器既存储Conan配方(定义如何构建库的文件),也存储可重用的二进制文件,这样我们就不必每次都从源代码构建。
  • Conan在build文件夹下生成了几个文件。这些文件是由我们在conanfile.txt中设置的CMakeToolchain和CMakeDeps生成器生成的。CMakeDeps生成文件,以便CMake能够找到我们刚刚下载的Zlib库。另一方面,CMakeToolchain为CMake生成一个工具链文件,这样我们就可以使用为默认配置文件检测到的相同设置,通过CMake透明地构建我们的项目。
  • --build=missing:当预编译包缺失时自动从源码构建
  • --install-folder:指定生成文件的输出目录
  • --settings、--options:指定构建配置(如编译器版本、架构等)

conan install的核心作用:准备cmake环境

  • 依赖解析与获取
    • 读取项目根目录下的 conanfile.txt或 conanfile.py
    • 解析依赖图(包括传递依赖)
    • 从配置的远程仓库(如 conancenter)下载预编译的二进制包
    • 如果预编译包不可用,则根据 settings和 options在本地从源码构建
  • 环境配置与集成文件生成
    • 为每个依赖包生成对应的 .cmake或 .pc文件
    • 创建 conanbuildinfo.cmake(旧版本)或 conan_toolchain.cmake(新版本)
    • 设置编译器和链接器所需的路径、定义、库文件、脚本等信息
sh 复制代码
$ cd build
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .

Conan 命令行

sh 复制代码
$ conan config home

$ conan install . --build=missing --profile=default

$ conan install . --output-folder=build --build=missing --settings=build_type=Debug

$ conan install . --output-folder=build --build=missing --options=zlib/1.3.1:shared=True

conan编译会自动生成程序的运行环境:

sh 复制代码
source conanrun.sh

source deactivate_conanrun.sh

conanfile.py文件

conanfile.txt

sh 复制代码
[requires]
zlib/1.3.1

[tool_requires]
cmake/3.27.9

[generators]
CMakeDeps
CMakeToolchain

conanfile.py

python 复制代码
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")
  • settings: 类属性,定义项目维度的变量,如编译器、它的版本、OS
  • generators: 类属性,说明调用conan install命令时,哪个Conan生成器会运行
  • requirements() 方法,使用self.requires()方法声明 zlib/1.3.1 依赖
  • build_requirements() 方法,使用self.tool_requires() 方法声明 cmake/3.27.9 依赖
sh 复制代码
$ conan install . --output-folder build --build=missing
$ cd build
$ source conanbuild.sh
Capturing current environment in deactivate_conanbuildenv-release-x86_64.sh
Configuring environment variables
$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .

layout() 方法

如:通过layout()方法,可以直接根据CMake generator的类型指定输出目录名

python 复制代码
    def layout(self):
        # We make the assumption that if the compiler is msvc the
        # CMake generator is multi-config
        multi = True if self.settings.get_safe("compiler") == "msvc" else False
        if multi:
            self.folders.generators = os.path.join("build", "generators")
            self.folders.build = "build"
        else:
            self.folders.generators = os.path.join("build", str(self.settings.build_type), "generators")
            self.folders.build = os.path.join("build", str(self.settings.build_type))

self.folders.generators=指定生成目录

self.folders.build=Makefile所在目录

这里有一些预定义的layouts以供import和直接使用,如,cmake_layout()

python 复制代码
from conan.tools.cmake import cmake_layout

	def layout(self):
	  cmake_layout(self)

使用 validate() 方法对不支持的配置抛出错误

python 复制代码
from conan.errors import ConanInvalidConfiguration
class CompressorRecipe(ConanFile):
  ...
  def validate(self):
    if self.settings.os == "Macos" and self.settings.arch == "armv8":
      raise ConanInvalidConfiguration("ARM v8 not supported in Macos")

条件requirements

向requirements()方法中添加或移除requirements

python 复制代码
from conan import ConanFile
class CompressorRecipe(ConanFile):
  # binary configuration
  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")

使用 generate() 方法从packages中拷贝资源

python 复制代码
import os
from conan import ConanFile
from conan.tools.files import copy
class Recipe(ConanFile):
  ...
  def generate(self):
    # Copy all resources from the dependency's resource directory
    # to the "assets" folder in the source directory of your project
    dep = self.dependencies["dep_name"]
    copy(self, "*", dep.cpp_info.resdirs[0], os.path.join(self.source_folder, "assets"))

conan install 就会拷贝资源文件

** 使用build() 方法和conan build命令 **

如果Conan配方里实现了build()方法,那么一条conan build命令就可以实现conan install + cmake <configure> + cmake <build>

python 复制代码
from conan import ConanFile
from conan.tools.cmake import CMake
class CompressorRecipe(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    generators = "CMakeToolchain", "CMakeDeps"
    ...
    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

交叉编译

build profile: 编译主机

host profile: 运行编译产物的主机

sh 复制代码
conan install . --build=missing --profile=someprofile
# 等价于
conan install . --build=missing --profile:host=someprofile --profile:build=default
conan install . --build missing -pr:b=default -pr:h=./profiles/raspberry

<local folder>/profiles/raspberry

txt 复制代码
[settings]
os=Linux
arch=armv7hf
compiler=gcc
build_type=Release
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=12
[buildenv]
CC=arm-linux-gnueabihf-gcc-12
CXX=arm-linux-gnueabihf-g++-12
LD=arm-linux-gnueabihf-ld

buildenv\] 用于设置环境变量。将该段添加到profile文件后,执行 conan install 将会调用*VirtualBuildEnv* 生成器,该生成器将会把环境信息添加到 *conanbuild.sh* 脚本中,该脚本会在CMake之前source一下以使用交叉构建工具链。 **host context** 是编译产物时用到的,通过self.requires()添加 **build context** 包含\[tool requirements\],在build machine中使用 两个context互不影响 ### versioning ```python def requirements(self): self.requires("zlib/[~1.2]") # 1.2.X的最新版 "zlib/[<1.2.12]" # zlib版本小于1.2.12的最新版 def build_requirements(self): self.tool_requires("cmake/[>3.10]") # 至少是cmake3.11的版本 pkgname/version#recipe_reversion or pkgname/version#user/channel#recipe_revision # 查看修订的版本 conan list "zlib/1.2.12#*" -r=conancenter self.requires("zlib/1.2.12#87a7211557b6690ef5bf7fc599dd8349") ``` **Lockfiles** 是指包含固定依赖的列表,该列表指明了依赖的固定版本 lockfile可以被认为是某个时间点的依赖图的快照 ```sh conan lock create . # then conan install . 等价于 conan install . --lockfile=conan.lock 此时会强制使用conan.lock中的配置 ``` *** ** * ** ***

相关推荐
zew10409945883 小时前
PyCharm【2023.2.5下】中命令行【Terminal】不见了如何解决?
ide·python·pycharm·快捷键·terminal·命令行消失
MarkHD3 小时前
智能体在车联网中的应用:第12天 CARLA实战:编写Python客户端生成与控制车辆,迈向联合仿真
开发语言·python
Generalzy3 小时前
应该是跨时代的更新——langgraph v1.0
python
xqqxqxxq3 小时前
Java 集合框架核心用法与实战技术笔记
java·笔记·python
有味道的男人3 小时前
Python 爬虫框架设计:类封装与工程化实践
开发语言·爬虫·python
Daily Mirror3 小时前
Day40 简单 CNN
python
程序猿追3 小时前
在昇腾NPU上实战部署LongCat-Video:从环境配置到长视频生成的完整指南
python·大模型·华为云·音视频
l1t3 小时前
豆包解读论文:将具有分支和循环控制流的命令式程序转换为标准SQL1999的公共表表达式
开发语言·数据库·人工智能·python·sql·postgresql·duckdb
————A3 小时前
强化学习基础概念----状态、动作、策略、奖励
人工智能·python