# conan使用指南
# 使用conan 包
下载示例工程
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/consuming_packages/simple_cmake_project
上述工程会依赖zlib
, 在使用conan
管理包的时候,会从ConanCente
中拉取需要的包,上述工程中包含conanfile.txt
就是为了说明需要获取的conan包的版本信息。
[requires]
zlib/1.2.11
[generators]
CMakeDeps
CMakeToolchain
上面文件中,[generators]
这一部分定义了 Conan
应该使用的生成器。生成器是 Conan 的一个组件,它负责生成构建系统所需的文件。CMakeDeps:这是一个生成器,它会生成一个
conan_cmake_find_package.cmake
文件,这个文件可以用来在 CMake 项目中查找 Conan
管理的包。CMakeToolchain:
这是另一个生成器,它会生成一个 conan_toolchain.cmake
文件,这个文件包含了构建项目所需的工具链配置,比如编译器设置、CMake 版本等。
conan profile detect --force
上面的命令用来创建或更新一个 Conan
用户配置文件(profile)
,这个文件包含了构建环境的设置,如编译器、架构、操作系统等信息。
detect_api: Found cc=gcc- 13.2.0
detect_api: gcc>=5, using the major as version
detect_api: gcc C++ standard library: libstdc++11
Detected profile:
[settings]
arch=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=13
os=Linux
WARN: This profile is a guess of your environment, please check it.
WARN: The output of this command is not guaranteed to be stable and can change in future Conan versions.
WARN: Use your own profile files for stability.
Saving detected profile to /home/lx/.conan2/profiles/default
可以使用如下命令获取conan
的配置文件默认的路径,
conan config home
# /home/lx/.conan2
profile
文件中包含不同的部分,[settings]
包含了操作系统、体系结构、编译器和构建的配置,当使用conan
指令带--profile
参数时,相关的配置将都会从profile
文件中读取,当不指定这个参数的时候,默认的会从--profile=default
中读取。可以使用不同的profile
文件来配置不同的构建设置。在conan
命令中使用--settings
参数可以覆盖掉profile
中的setting
设置。可以使用如下代码来确认setting
参数有没有生效,
#include <cstdio>
int main() {
#ifdef NDEBUG
printf("Not debug\n");
#else
prinf("debug\n");
#endif
return 0;
}
编译的时候使用的参数如下:
conan install . --output-folder=build --build=missing --settings=build_type=Debug
接下来将使用 Conan
安装 Zlib
并生成 CMake
所需的文件来查找该库并构建我们的项目。我们将在文件夹 build
中生成这些文件。为此,请运行:
conan install . --output-folder=build --build=missing
构建仓库:
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
cmake
中的CMAKE_TOOLCHAIN_FILE
变量非常有用,它允许用户指定一个工具链文件,这个文件定义了构建系统的环境和编译器设置。工具链文件通常用于跨平台构建,或者当你需要自定义编译器、编译选项、链接器等设置时。
# 将构建工具也作为conan包进行管理
上面的示例中使用的是系统中已经安装的cmake,有时候需要使用conan包来指定要使用的cmake版本,本节就来介绍如何使用conan来安装指定版本的cmake来进行编译系统的构建。
以上操作其实非常简单,只需要在conanfile.txt
中进行指定即可,如下:
[requires]
zlib/1.2.11
[tool_requires]
cmake/3.22.6
[generators]
CMakeDeps
CMakeToolchain
在指定cmake‵版本之前,还是需要系统先有一个
cmake,因为
conanfile中指定的
cmake`版本只是指定在当前的工程中。
在cmake
文件中添加一行打印使用cmake
的版本信息:
message("Building with CMake version: ${CMAKE_VERSION}")
执行上述命令后,在build文件夹下将有如下文件conanbuild.sh
,这个脚本自动调用VirtualBuildEnv
生成器,这个脚本会设置一些环境变量如$PATH
来指定我们的软件路径,如新安装的cmake
。
source conanbuild.sh # 激活当前环境
cmake --version
# cmake version 3.22.6
同样在build
文件夹中还有deactivate_conanbuild.sh
文件用来恢复系统环境变量的设置,
source deactivate_conanbuild.sh # 恢复环境变量设置
# 应用依赖设置
默认情况下,conan
生成目标文件使用的是静态链接的方式,通过设置conan
的--options
参数可以设置目标文件是静态链接还是动态链接的方式,
conan install . --output-folder=build --build=missing --options=zlib/1.2.11:shared=True
使用上述命令的时候会在build
目录下生成‵conanrun.sh脚本设置
VirtualRunEnv环境相关的变量,如
LD_LIBRARY_PATH和
PATH`,供执行可执行文件的时候使用,如执行共享库的路径。
conan中settings
和options
的区别:
settings
是项目范围的配置,会影响正在构建的整个项目。例如,操作系统(os)、架构(arch)和编译器(compiler)等设置,对于依赖关系图中的所有包来说,这些设置通常是相同的。options
是特定于包的配置。例如,静态或共享库不是适用于所有包的设置。有些包可能只包含头文件,而其他包可能包含数据或可执行文件。shared
是一个常见的选项,但包可以定义和使用任何它们需要的选项。
# 使用conanfile.py
简单场景使用conanfile.txt
就足够了,但想更灵活的使用conan
就需要使用conanfile.py
了,可以在其中使用 Python
代码来执行诸如动态添加需求、根据其他选项更改选项或根据需求设置选项等操作。
将以下conanfile.txt
改造成conanfile.py
文件:
# conanfile.txt
[requires]
zlib/1.2.11
[tool_requires]
cmake/3.22.6
[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.2.11")
def build_requirements(self):
self.tool_requires("cmake/3.22.6")
这个类CompressorRecipe
继承自ConanFile
类,这个类有不同的settings/gennerators
配置,
requirements()
方法中调用self.requires
方法来指定zlib
依赖build_requirements()
方法中使用self.tool_requires()
来指定编译工具等的使用
其他的conan build/install
指令的使用方式和使用conanfile.txt
时一样不要变更。
在前面的示例中,每次执行 conan install
命令时,我们都必须使用 –output-folder
参数来定义要创建 Conan
生成的文件的位置。有一种更简洁的方法来决定我们希望 Conan
在哪里为构建系统生成文件,例如如果我们想要根据我们使用的 CMake 生成器的类型来设置不同的输出文件夹, 可以直接在conanfile.py layout()
方法中定义它,并使其适用于每个平台,而无需添加更多更改。
# 使用layout方法
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
,layout()
方法中可以通过设置这个属性来指定Conan
生成的所有辅助文件(CMake 工具链和 cmake 依赖文件)放置的文件夹
# 使用validate
方法
当conan
加载conanfile.py
文件时,还会自动执行validate
函数,可以进行一些配置的校验。
def validate(self):
if self.settings.os == "Macos" and self.settings.arch == "armv8":
raise ConanInvalidConfiguration("ARM v8 not supported in Macos")
# 使用generate()
方法从pkg
中复制资源
在某些场景中,conan pkg
中包含有对使用pkg
的人来说十分重要的文件,像配置文件/assert等,使用generate()
方法可以将这些文件从conan cache
中拷贝到工程文件夹中,确保所有的资源可以被正确的使用。
如下的示例代码功能是将pkg resdirs
目录下的资源文件拷贝到工程asserts
文件夹下,
import os
from conan import ConanFile
from conan.tools.files import copy
class MyProject(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
命令后,所有的资源文件将会被拷贝到本地,如此就可以在本地工程中使用配置文件来构建了。
# 交叉编译
譬如在x86 64
的ubuntu
上编译,在Raspberry Pi
上运行。conan
使用两个编译配置文件高的profile
,即便对于本地编译运行的conan
构建,也可以看做其使用了两套profile
,如下:
conan install . --build=missing --profile:host=someprofile --profile:build=default
profile:host
:这是定义构建的二进制文件将运行的平台的配置文件。对于我们的字符串压缩器应用程序,此配置文件将应用于将在Raspberry Pi
中运行的Zlib
库。profile:build
:这是定义将构建二进制文件的平台的配置文件。对于我们的字符串压缩器应用程序,CMake 工具将使用此配置文件,该工具将在Ubuntu Linux
计算机上对其进行编译。
仅设置--profile
参数时,等价于设置profile:host
,--profile:build
将使用默认配置。
# build.profile
[settings]
os=Linux
arch=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=gnu14
compiler.libcxx=libstdc++11
compiler.version=9
# host.profile
[settings]
os=Linux
arch=armv7hf
compiler=gcc
build_type=Release
compiler.cppstd=gnu14
compiler.libcxx=libstdc++11
compiler.version=9
[buildenv]
CC=arm-linux-gnueabihf-gcc-9
CXX=arm-linux-gnueabihf-g++-9
LD=arm-linux-gnueabihf-ld
对应的conanfile.py
文件内容基本上不变:
from conan import ConanFile
from conan.tools.cmake import cmake_layout
class 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)
编译使用的命令为:
conan install . --build missing -pr:b=default -pr:h=./profiles/raspberry
使用file
命令可以查看编译生成的可执行文件的目标架构是aarch64
。