Conan教程(5)—— 创建包

本文档详细介绍了使用Conan进行软件包创建的流程,涵盖从创建包配方、设置源码位置、创建与测试包、处理设置与选项,到打包现有二进制文件的多个方面。教程通过实例展示了如何创建包配方、测试包功能、定义包的ABI兼容性以及使用工具链文件。同时,文档强调了Conan在构建系统集成、源码管理与二进制兼容性上的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        本文将介绍如何创建、构建和测试包。

一、开始

        本节译自:https://docs.conan.io/en/latest/creating_packages/getting_started.html

        为了开始学习如何创建包,我们将从现有的源码存储库中创建一个包:https://github.com/conan-io/hello。我们可以检查该项目,它是一个非常简单的 “hello world”的C++库,使用CMake作为构建系统来构建库和可执行文件。它不包含与Conan的任何关联。
        我们使用类似的GitHub存储库作为示例,但是相同的过程也适用于其他源码来源,例如从网上下载zip或tarball。
        注意: 对于这个具体的示例,除了C++编译器之外,还需要在路径中安装CMake和git。它们不是Conan所要求的,因此可以使用自己的构建系统和版本控制。

1、创建包配方

        首先,为包配方创建一个文件夹,并使用创建工作包配方的conan new帮助命令:

$ mkdir mypkg && cd mypkg
$ conan new hello/0.1 -t

        将生成以下文件:

conanfile.py
test_package
	  CMakeLists.txt
	  conanfile.py
	  example.cpp

        在根目录,有一个conanfile.py,它是主要的配方文件,负责定义我们的包。此外,还有一个test_package文件夹,其中包含一个简单的测试项目,该项目需要并与创建的包链接。用于测试包能够正常运行。
        让我们看一下包配方conanfile.py

from conans import ConanFile, CMake, tools

class HelloConan(ConanFile):
    name = "hello"
    version = "0.1"
    license = "<Put the package license here>"
    url = "<Package recipe repository url here, for issues about the package>"
    description = "<Description of hello here>"
    settings = "os", "compiler", "build_type", "arch"
    options = {
   "shared": [True, False]}
    default_options = {
   "shared": False}
    generators = "cmake"

    def source(self):
        self.run("git clone https://github.com/conan-io/hello.git")
        # This small hack might be useful to guarantee proper /MT /MD linkage
        # in MSVC if the packaged project doesn't have variables to set it
        # properly
        tools.replace_in_file("hello/CMakeLists.txt", "PROJECT(MyHello)",
                              '''PROJECT(MyHello)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()''')

    def build(self):
        cmake = CMake(self)
        cmake.configure(source_folder="hello")
        cmake.build()

        # Explicit way:
        # self.run('cmake %s/hello %s'
        #          % (self.source_folder, cmake.command_line))
        # self.run("cmake --build . %s" % cmake.build_config)

    def package(self):
        self.copy("*.h", dst="include", src="hello")
        self.copy("*hello.lib", dst="lib", keep_path=False)
        self.copy("*.dll", dst="bin", keep_path=False)
        self.copy("*.so", dst="lib", keep_path=False)
        self.copy("*.dylib", dst="lib", keep_path=False)
        self.copy("*.a", dst="lib", keep_path=False)

    def package_info(self):
        self.cpp_info.libs = ["hello"]

        这是一个完整的包配方。以下是基础信息:

  • settings字段定义不同二进制包的配置。在此示例中,对操作系统、编译器、构建类型或架构定义的任何修改都将生成不同的二进制包。
    注意,如果包是交叉编译的,那么运行的配方和正在构建的包所在的平台与运行代码的最终平台 (self.settings.osself.settings.arch) 是不同的。因此,如果想在当前系统编译别的系统的库,需要检查:
def build(self):
    if platform.system() == "Windows":
        cmake = CMake(self)
        cmake.configure(source_folder="hello")
        cmake.build()
    else:
        env_build = AutoToolsBuildEnvironment(self)
        env_build.configure()
        env_build.make()
  • 包配方还能够使用shared选项为静态和动态链接库创建不同的二进制包,该选项默认设置为False(即默认情况下,它使用静态链接)。
  • source()方法执行git clone从Github检索源,其他的如下载zip压缩文件同样是可以的。正如所见,可以执行对代码的任何操作,例如签出任何分支或标签,或修补源码。在此示例中,将在现有CMake代码中添加两行,以确保二进制兼容性。
  • build()配置项目,然后使用标准CMake命令进行构建。CMake对象仅用于将Conan设置转换为CMake命令行参数。请注意,并非一定需要CMake。还可以通过调用make、MSBuild、SCons或任何其他构建系统直接构建包。
  • package()方法将(头文件、libs))从构建文件夹复制到最终的包文件夹。
  • 最后,package_info()方法定义使用者在使用此包时必须与“hello”库链接。也可以定义如包含(或lib)路径的其他信息。这些信息在由生成器创建的文件中使用,如conanbuildinfo.cmake

2、test_package文件夹

        注意:test_package与库单元测试或集成测试不同,后者可能更全面些。 这些测试是“包”测试,它们验证程序包是否正确创建,且包使用者是否能够链接到该包并复用它。
        如果查看test_package文件夹,将发现example.cppCMakeLists.txt文件没有特别之处。test_package/conanfile.py文件只是另一个配方,和之前的conanfile.txt没什么区别:

from conans import ConanFile, CMake
import os

class HelloTestConan(ConanFile):
    settings = "os", "compiler", "build_type", "arch"
    generators = "cmake"

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def imports(self):
        self.copy("*.dll", dst="bin", src="bin")
        self.copy("*.dylib*", dst="bin", src="lib")

    def test(self):
        os.chdir("bin")
        self.run(".%sexample" % os.sep)

        上述conanfile.py具有以下特征:

  • 它没有名称和版本,因为我们没有创建包,所以没有必要。
  • 不需要package()package_info()方法,因为我们没有创建包。
  • test()方法指定需要运行哪些二进制文件。
  • imports()方法设置为将动态链接库复制到bin文件夹。当应用动态链接时,test()方法启动example可执行文件, example也将会运行。

3、创建和测试包

        运行以下命令,就可以使用默认设置创建和测试包:

$ conan create . demo/testing
...
Hello world Release!

        如果显示“Hello world Release!”,就表示成功。
        conan create命令执行以下操作:

  • conanfile.py从用户文件夹复制到本地缓存(用Conan术语来讲是“export”)。
  • 安装包,强制从源码构建它。
  • 切换到test_package文件夹并创建一个临时build文件夹。
  • 执行conan install ..以安装test_package/conanfile.py的要求。注意,它将从源代码构建“hello”。
  • 构建并启动示例应用程序,分别调用test_package/conanfile.pybuild()test()方法。

        使用Conan命令conan create命令等同于:

$ conan export . demo/testing
$ conan install hello/0.1@demo/testing --build=hello
# package is created now, use test to test it
$ conan test test_package hello/0.1@demo/testing

        conan create命令接收与conan install相同的命令行参数,因此可以将相同的设置、选项和命令行开关传递给它。如果要为不同的配置创建和测试包,可以如下:

$ conan create . demo/testing -s build_type=Debug
$ conan create . demo/testing -o hello:shared=True -s arch=x86
$ conan create . demo/testing -pr my_gcc49_debug_profile
...
$ conan create ...

4、省略user/channel

        警告:这是一个实验特性,在未来的版本中会有突破性的变化。
        可以创建一个省略了user/channel的包:$ conan create .
        要引用该包,还必须省略user/channle
        示例

  • 在配方中指定要求:
 class HelloTestConan(ConanFile):
     settings = "os", "compiler", "build_type", "arch"
     requires = "packagename/1.0"

     ...
  • 安装单个包。使用conan install我们必须使用packagename/1.0@的语法(始终有效)来消除参数的歧义,该参数也可用于指定路径:
$ conan install packagename/1.0@
  • 搜索引用的二进制包。conan search命令需要使用packagename/1.0@的语法(始终有效)来消除用法歧义:
$ conan search packagename/1.0@

Existing packages for recipe packagename/1.0:

Package_ID: 9bfdcfa2bb925892ecf42e2a018a3f3529826676
	[settings]
		arch: x86_64
        build_type: Release
        compiler: gcc
        compiler.libcxx: libstdc++11
        compiler.version: 7
        os: Linux
	Outdated from recipe: False
  • 移除包:
$ conan remove packagename/1.0
  • 上传包:
conan upload packagename/1.0

5、Settings和Options

        我们已经使用了settings中的osarchcompiler等设置。注意上面的包配方还包含一个sharedoptions(定义为options = {“shared”: [True,False]})。那么settingsoptions直接有什么区别呢?

  • settings是项目范围的配置,通常会影响正在构建的整个项目。例如,对于依赖关系图中的所有包,操作系统或编译环境自然是要相同的。想为Windows应用程序链接Linux库是不可能的。
  • settings在包配方中不能给定默认值。给定库的配方不能说其默认值为os=Windowsos将从环境得到,这是强制性的。
  • settings是可配置的。可以在settings.yml文件中编辑、添加、删除设置或设置子集。
  • options是特定于包的配置。静态或共享库不是适用于所有包的设置。有些包是仅只有头文件,而其他包可能只有数据或可执行文件。包可以包含不同文件的混合。shared是一个常见的选项,但是包可以定义和使用他们想要的任何选项。
  • options在包配方中定义,包括其支持的值,而其他选项可以由包配方本身默认。库的包可以很好地定义默认情况下它将是静态库(默认值)。如果未指定其他,包将是静态库。

        上述情况有一些例外。例如,可以使用命令行按包定义设置:

$ conan install . -s MyPkg:compiler=gcc -s compiler=clang ..

        这将对MyPkg使用gcc,对其余依赖项使用clang(非常罕见的情况)。
        在某些情况下,许多包使用相同的选项,从而允许在使用模式后设置其值,例如:

$ conan install . -o *:shared=True

二、配方与源码在不同的位置

        本节译自:https://docs.conan.io/en/latest/creating_packages/external_repo.html

        在前面,我们从外部存储库中获取了库的源码。通常打包第三方库采用此流程。
        从外部存储库获取源码有两种方式:

  • 使用前面展示的source()方法:
from conans import ConanFile, CMake, tools

class HelloConan(ConanFile):
    ...

    def source(self):
        self.run("git clone https://github.com/conan-io/hello.git")
        ...

        还可以使用tools.Git类:

from conans import ConanFile, CMake, tools

class HelloConan(ConanFile):
    ...

    
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值