conan 基本使用

发布时间 2023-12-18 13:20:50作者: 料峭春风吹酒醒

原文:https://docs.conan.io/2/tutorial/consuming_packages.html

Basic

安装conan

pip install conan

打印conan依赖安装路径

conan config home

查看profile

conan profile show

install时指定profile

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

Profile

首次安装好conan2后,需要编辑profile文件,或者使用命令生成默认配置

conan profile detect --force     

查看默认配置

conan profile path default    

配置文件内容

[settings]
arch=armv8
build_type=Release
compiler=apple-clang
compiler.cppstd=gnu17
compiler.libcxx=libc++
compiler.version=15
os=Macos

手动创建一个debug的配置

使用conan config home找到conan的目录,在conna的profile目录下新建一个配置debugfile

[settings]
arch=armv8
build_type=Debug
compiler=apple-clang
compiler.cppstd=gnu17
compiler.libcxx=libc++
compiler.version=15
os=Macos

安装时指定debugfile

conan install . --output-folder=build --build=missing --profile=debugfile

其他方式构建debug版本

指定settings

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

Install zlib in conan

https://docs.conan.io/2/tutorial/consuming_packages/build_simple_cmake_project.html

创建一个Cmake项目

项目结构

.
├── CMakeLists.txt
└── src
    └── main.c

main.c

#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 "
                            "for C and C++ development, allowing development teams to easily and efficiently"
                            "manage their packages and dependencies across platforms and build systems."};
  
    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

项目结构

.
├── CMakeLists.txt
├── conanfile.txt
└── src
    └── main.c

conanfile.txt

[requires]
zlib/1.2.11

[generators]
CMakeDeps
CMakeToolchain

构建项目

安装依赖

conan install . --output-folder=build --build=missing

Windows

$ cd build
# assuming Visual Studio 15 2017 is your VS version and that it matches your default profile
$ cmake .. -G "Visual Studio 15 2017" -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.2.11

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.2.11

Read more

Specify your cmake

conanfile.txt

[requires]
zlib/1.2.11

[tool_requires]
cmake/3.22.6

[generators]
CMakeDeps
CMakeToolchain

安装依赖

conan install . --output-folder=build --build=missing

激活环境变量以切换指定的cmake

Windows

$ cd build
$ conanbuild.bat
# conanbuild.ps1 if using Powershell

Linux, macOS

$ cd build
$ source conanbuild.sh
Capturing current environment in deactivate_conanbuildenv-release-x86_64.sh
Configuring environment variables

构建项目

Windows

# assuming Visual Studio 15 2017 is your VS version and that it matches your default profile
$ cmake .. -G "Visual Studio 15 2017" -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake
$ cmake --build . --config Release
...
Building with CMake version: 3.22.6
...
[100%] Built target compressor
$ Release\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.2.11

Linux, macOS

$ cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
$ cmake --build .
...
Building with CMake version: 3.22.6
...
[100%] Built target compressor
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
ZLIB VERSION: 1.2.11

恢复环境

当使用脚本激活环境后,会生成一个deactivate_conanbuild.sh/bat文件用来恢复环境。

Windows

$ deactivate_conanbuild.bat

Linux, macOS

$ source deactivate_conanbuild.sh
Restoring environment

tool_requires and tool packages are intended for executable applications, like cmake or ninja. Do not use tool_requires to depend on library or library-like dependencies.

Build Release or Debug

在Release模式下会自动生成一个NDEBUG宏,在代码中可以通过这个宏来判断是Debug模式还是Release模式。

#ifdef NDEBUG
    printf("Release configuration!\n");
#else
    printf("Debug configuration!\n");
#endif

install

conan install . --output-folder=build --build=missing --settings=build_type=Debug
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug
cmake --build . --config=Debug       

修改option,使用shared方式链接外部库

通过命令行指定

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

通过conanfile.txt指定

[options]
zlib/1.2.11:shared=True

cmake中指定set(CMAKE_SKIP_RPATH TRUE)后,构建后运行会出现如下错误

Windows

$ Release\compressor.exe
(on a pop-up window) The code execution cannot proceed because zlib1.dll was not found. Reinstalling the program may fix this problem.
# This error depends on the console being used and may not always pop up.
# It could run correctly if the console gets the zlib dll from a different path.

Linux, Macos

$ ./compressor
./compressor: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory

这是因为动态库文件无法加载,在Windows连接器会先找同目录下,然后是PATH里的目录; 在OSX会搜索在DYLD_LIBRARY_PATH中的路径,linux下使用的是LD_LIBRARY_PATH。

conan提供了脚本来设置运行时的环境变量。

Windows

$ conanrun.bat
$ Release\compressor.exe
Uncompressed size is: 233
Compressed size is: 147
...

Linux, macOS

$ source conanrun.sh
$ ./compressor
Uncompressed size is: 233
Compressed size is: 147
...

Conanfile

一般小型项目使用conanfile.txt就足够了,而conanfile.py会更加灵活。

conanfile.txt

[requires]
zlib/1.2.11

[tool_requires]
cmake/3.22.6

[generators]
CMakeDeps
CMakeToolchain

根据上述conanfile.txt改写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")

使用python来创建conan配方,首先需要创建一个继承自 ConanFile 的类,这个类有以下属性和方法:

  • settings 该类属性定义了项目范围的变量,如编译器、其版本或操作系统本身,这些变量在我们构建项目时可能会发生变化。
  • generators 该类属性指定当我们调用conan install命令时,将运行哪些Conan生成器。在上面的例子中,我们在conanfile.txt中添加了CMakeToolchain和CMakeDeps。
  • requirements() 这个方法中使用了 self.requires() 声明项目对 zlib/1.2.11的依赖。
  • build_requirements() 这个方法中使用了self.tool_requires() 声明了对 cmake/3.22.6 的依赖。

Cross-complie

省略,详情见:https://docs.conan.io/2/tutorial/consuming_packages/cross_building_with_conan.html

Versioning

Version ranges

通过conanfile.txt方式能够指定一个具体版本的依赖,如果需要升级依赖库,需要手动修改conanfile。如果使用conanfile.py,则可以更好的配置版本而不需要每次升级时手动更新。

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]")

zlib/[~1.2]表示依赖的版本为1.2 ,它可能是zlib/1.2.8, zlib/1.2.11 或者 zlib/1.2.12,而不可能时zlib/1.3.0之类。在这个指定的版本范围之中,往往是最新的一个版本会被使用。

如果使用 zlib/[<1.2.12], 表明使用1.2.12之前的最后一个版本,即使用zlib/1.2.11

Lockfiles

在conanfile.py中指定了zlib依赖版本为zlib/1.2.11

def requirements(self):
    self.requires("zlib/1.2.11")

创建一个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": []
}

尝试修改conanfile.py中 requires

def requirements(self):
    self.requires("zlib/[~1.2]")

运行 conan install .,conan会自动找到 conan.lock,这个命令相当于运行 conan install . --lockfile=conan.lock

conan install .

Graph root
    conanfile.py: .../conanfile.py
Requirements
    zlib/1.2.11#4524fcdd41f33e8df88ece6e755a5dcc - Cache

这样conan不再查找范围内的版本号,并且 zlib/1.2.12也不会被选中,即便它在 zlib/[~1.2]范围内, 因为 conan.lock 将版本强制锁定在了 zlib/1.2.11 和这个revision(4524fcdd41f33e8df88ece6e755a5dcc)。