精华内容
下载资源
问答
  • 本文将介绍如何使用Conan处理交叉构建场景,以及如何使用Windows子系统(Cygwin,MSYS2)。 一、交叉构建         本节译自:...

            本文将介绍如何使用Conan处理交叉构建场景,以及如何使用Windows子系统(Cygwin,MSYS2)。

    一、交叉构建

            本节译自:https://docs.conan.io/en/latest/systems_cross_building/cross_building.html

    二、Windows 子系统

            本节译自:https://docs.conan.io/en/latest/systems_cross_building/windows_subsystems.html

    展开全文
  • Conan是一个开源的、跨平台的、去中心化的C和C++包管理器,它的源码在https://github.com/conan-io/conan ,License为MIT,最新发布版本为1.38.0,由Python实现。版本更新较频繁,但保持向前兼容。 Conan特点: ...

        Conan是一个开源的、跨平台的、去中心化的C和C++包管理器,它的源码在https://github.com/conan-io/conan ,License为MIT,最新发布版本为1.38.0,由Python实现。版本更新较频繁,但保持向前兼容。

        Conan特点

        (1).它是完全去中心化的:用户可以将他们的包托管在他们的私有服务器上,与JFrog Artifactory 和ConanCenter集成。具有客户端----服务器架构,客户端可以从不同的服务器(“远程”)获取包,也可以将包上传到不同的服务器,similar to the “git” push-pull model to/from git remotes.

        (2).它适用于所有平台:包括Linux、OSX、Windows、Android、iOS,也支持嵌入式,还支持交叉编译。

        (3).管理二进制文件:它可以为任何配置和平台甚至包括交叉编译创建、上传和下载二进制文件,从而节省大量开发和持续集成时间。二进制兼容性也可以配置和定制。在所有平台上以相同的方式管理所有工件。

        (4).与任何构建系统集成,包括任何专有和定制系统:为主要构建系统(CMake、Visual Studio MSBuild、Makefiles、Meson等)提供经过测试的支持。

        (5).可扩展。

        ConanCenter:是一个中央公共存储库,包含数百个流行的开源库包,以及许多针对主流编译器版本的预编译二进制文件。

        JFrog Artifactory Community Edition (CE):是推荐的、免费的、Conan服务器,可在你的控制下私下托管你自己的包。它是JFrog Artifactory for Conan包的免费社区版。

        Conan client:命令行工具,用于创建包和使用包,可创建本地仓库支持离线使用。

        Conan server:可私有化部署的服务器,是一个与Conan客户端一起分布的小型服务器。 它是一个简单的开源实现,提供基本功能。

      安装Conan:这里通过Conda安装Conan,关于Conda的介绍可以参考:https://blog.csdn.net/fengbingchun/article/details/86212252 ,python的版本需要3.8

    conda create -n test_conan python=3.8
    conda activate test_conan
    pip install conan #conda install -c conda-forge conan

        在Conan中,一个包的定义:包名/版本@用户/渠道

        Conan客户端常用命令

        (1).查看conan版本:conan --version

        (2).搜索软件包,如opencv:conan search opencv* -r=all (或-r=conan-center)

        (3).显示所有源:conan remote list

        (4).通过conanfile.txt安装依赖包:conan install .

        下面是下载openssl 1.0.2s依赖包示例,conanfile.txt内容如下:

    [requires]
    openssl/1.0.2s
    
    [generators]
    cmake

        在conanfile.txt目录下执行以下命令:

    ~/Disk/anaconda3/envs/test_conan/bin/conan install . -s arch=x86_64 -s compiler=gcc -s compiler.libcxx=libstdc++ -s compiler.version=4.9 -s os=Linux --build=openssl --build=zlib

        执行结果如下图所示,会在~/.conan/data/openssl/1.0.2s目录下生成对应的头文件和库:

        执行上述命令前,在当前目录下仅有conanfile.txt一个文件,执行完后会多出几个文件,如下图所示:

    展开全文
  • conan是一个跨平台的包管理工具,面向C和C++开发者,但是它能够从源码,依赖和预编译二进制包。 二、安装 先决条件 1、安装Python3.5以上版本。 2、安装过程中要安装pip。 安装过程 1、安装命令:pip install conan...

    一、conan简介

            conan是一个面向C和C++开发者的包管理器:

    • 去中心的。用户可以在自己的服务器上托管自己的包。
    • 可移植的。可以工作在所有平台,包括Linux、OSX、Windows、Solaris、FreeBSD、嵌入式和交叉编译、Docker,、WSL。
    • 二进制文件管理。它可以为任何配置和平台创建、上传和下载二进制文件,甚至交叉编译,节省了开发和持续集成的大量时间。二进制文件的兼容性可以配置和定制。
    • 可以集成所有构建系统。为主要的构建系统(CMake、MSBuild、Makefile、Meson等)提供测试支持。
    • 可扩展:基于python。
    • 有大型和活跃的社区,特别是在Github和Slack。
    • 这个社区还在ConanCenter以及Bintray的Bincrafters仓库中创建和维护包。

    二、安装

    • 先决条件
      1、安装Python3.5以上版本。
      2、安装过程中要安装pip
    • 安装过程
      1、安装命令:pip install conan
      2、验证命令:conan,查看响应结果,成功则响应如下:
    Consumer commands
            install    Installs the requirements specified in a recipe (conanfile.py or conanfile.txt).
            config     Manages Conan configuration.
            get        Gets a file or list a directory of a given reference or package.
            info       Gets information about the dependency graph of a recipe.
            search     Searches package recipes and binaries in the local cache or a remote.
    
    • 更新过程
      输入命令:pip install conan --upgrade

    三、链接

    展开全文
  • Conan教程(5)—— 创建包

    千次阅读 2021-01-04 10:56:03
    本节译自:https://docs.conan.io/en/latest/creating_packages/getting_started.html 二、配方与源码在不同的位置 本节译自:https://docs.conan.io/en/latest/creating_packages/external_repo.html 三、配方与...

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

    一、开始

            本节译自: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):
        ...
    
        def source(self):
            git = tools.Git(folder="hello")
            git.clone("https://github.com/conan-io/hello.git", "master")
            ...
    
    • 使用ConanFile的scm属性:
      注意:这是一项实验性功能,可能会在将来版本中发生重大改变。
    from conans import ConanFile, CMake, tools
    
    class HelloConan(ConanFile):
         scm = {
            "type": "git",
            "subfolder": "hello",
            "url": "https://github.com/conan-io/hello.git",
            "revision": "master"
         }
        ...
    

            Conan将克隆scm url并检出scm revision
            source()方法将在检出过程之后调用,因此仍然可以使用它来修补某些内容或检索更多源,但在大多数情况下这不是必需的。

    三、配方与源码在相同的位置

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

            有时将配方和源码放在同一存储库中会更方便。如果正在开发和打包自己的库,而不是第三方库,则更应该如此。
            有两种不同的方法:

    • 使用conanfile的exports source属性将源码与配方一起导出。这样,配方是独立的,从源码构建时不需要从外部来源获取代码。它可以被认为是源代码的 “快照”。
    • 使用conanfile的scm属性自动捕获存储库的远程和提交。

    1、导出带有配方的源:exports_sources

            如果希望包配方与打包的源码位于同一存储库中,这可能是一种合适的方法。
            首先,获取初始源代码并创建基本包配方:

    $ conan new hello/0.1 -t -s
    

            将生成以下文件:

    conanfile.py
    src
    	CMakeLists.txt
    	hello.cpp
    	hello.h
    test_package
    	CMakeLists.txt
    	conanfile.py
    	example.cpp
    

            使用之前的示例(hello)源码创建src文件夹,现在看看conanfile.py

    from conans import ConanFile, CMake
    
    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"
        exports_sources = "src/*"
    
        def build(self):
            cmake = CMake(self)
            cmake.configure(source_folder="src")
            cmake.build()
    
            # Explicit way:
            # self.run('cmake "%s/src" %s' % (self.source_folder, cmake.command_line))
            # self.run("cmake --build . %s" % cmake.build_config)
    
        def package(self):
            self.copy("*.h", dst="include", src="src")
            self.copy("*.lib", dst="lib", keep_path=False)
            self.copy("*.dll", dst="bin", keep_path=False)
            self.copy("*.dylib*", dst="lib", keep_path=False)
            self.copy("*.so", dst="lib", keep_path=False)
            self.copy("*.a", dst="lib", keep_path=False)
    
        def package_info(self):
            self.cpp_info.libs = ["hello"]
    

            有两个重要的变化:

    • 添加了exports_source字段,指示Conan将本地src文件夹中的所有文件复制到包配方中。
    • 删除了source()方法,因为不再需要检索外部源。

            另外,可以注意到两行CMake:

    include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
    conan_basic_setup()
    

            它们不会添加到包配方中,因为它们可以直接添加到src/CMakeLists.txt文件中。
            如前所述,只需为userchannel设置值为demo/testing创建包:

    $ conan create . demo/testing
    ...
    hello/0.1@demo/testing test package: Running test()
    Hello world Release!
    

    2、捕获远程服务器并提交:scm

            警告:这是一项实验性功能,可能会在将来的版本中发生重大改变。尽管这是实验性的功能,但是使用scm_to_conandata的功能被认为是稳定的。
            可以将scm属性的urlrevision字段设置为auto。当导出配方时(或在调用conan create时),导出的配方将捕获本地存储库的远程和提交。

    import os
    from conans import ConanFile, CMake, tools
    
    class HelloConan(ConanFile):
    	scm = {
    		"type": "git",  # Use "type": "svn", if local repo is managed using SVN
            "subfolder": "hello",
            "url": "auto",
            "revision": "auto",
            "password": os.environ.get("SECRET", None)
        }
        ...
    

            可以将conanfile.py提交并推送到原始存储库,该存储库将始终保留auto值。当文件导出到Conan本地缓存时(除非有未提交的更改,请阅读下文),这些数据将存储在conanfile.py本身(Conan将修改文件)或在一个特殊的文件conandata.yml并与配方一起存储,具体取决于配置参数scm_to_conandata的值。

    • 如果未激活scm_to_conandata(Conan v1.x中的默认行为),则Conan将存储conanfile.py的修改版本,其中字段的值为纯文本。
    import os
    from conans import ConanFile, CMake, tools
    
    class HelloConan(ConanFile):
    	scm = {
    		"type": "git",
            "subfolder": "hello",
            "url": "https://github.com/conan-io/hello.git",
            "revision": "437676e15da7090a1368255097f51b1a470905a0",
            "password": "MY_SECRET"
        }
        ...
    

            因此,当将配方上传到Conan远程服务器时,配方将包含 “已解决” 的URL并提交。

    • 如果scm_to_conandata被激活,这些字段的值(usernamepassword除外)将存储在conandata.yml文件中,该文件将与配方一起自动导出。

            无论选择哪个选项,Conan都会在加载配方文件时将解析的数据分配到相应的字段,并且它们可用于配方中定义的所有方法。此外,如果从源码构建包,Conan将在运行方法source()(如果已定义)之前获取捕获的url/commit中的代码。
            由于scm属性是在本地目录上下文中求值的(请参阅scm属性),因此可以编写更复杂的函数来检索适当的值,此源文件conanfile.py也将有效:

    import os
    from conans import ConanFile, CMake, tools
    
    def get_remote_url():
    	""" Get remote url regardless of the cloned directory """
        here = os.path.dirname(__file__)
        svn = tools.SVN(here)
        return svn.get_remote_url()
    
    class HelloConan(ConanFile):
        scm = {
    		"type": "svn",
            "subfolder": "hello",
            "url": get_remote_url(),
            "revision": "auto"
        }
        ...
    

    提示:
            在执行conan createconan export时,Conan将在本地缓存中捕获本地scm项目文件夹的源。
            这允许构建包对源代码进行更改,而无需提交它们并将它们推送到远程存储库。从本地存储库克隆时,这便于加快包的开发。
            因此,如果正在使用scm功能,带有一些用于url/revisonauto字段,并且在存储库中有未提交的更改,则会打印一条警告消息:

    $ conan export . hello/0.1@demo/testing
    
     hello/0.1@demo/testing: WARN: There are uncommitted changes, skipping the replacement of 'scm.url'
     and 'scm.revision' auto fields. Use --ignore-dirty to force it.
     The 'conan upload' command will prevent uploading recipes with 'auto' values in these fields.
    

            正如警告消息所解释的那样,除非指定--ignore-dirty,否则将不会替换auto字段,并且默认情况下,conan upload将阻止配方的上传。这可以防止上传的配方输出错误的scm值。可以使用conan upload --force强制上传配方,但auto值未替换。

    四、打包现有的二进制文件

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

            在某些情况下,需要从现有的二进制文件创建包,例如,从从第三方创建包,或者使用由其他不使用Conan流程或团队所预先构建的二进制文件,此种情况下,我们并不想从源码构建。以下情况,我们应该打包本地文件:

    • 当无法从源构建包时(只有预构建的二进制文件可用)。
    • 在本地开发软件包时,想将构建的二进制库导出到本地缓存。 由于不想再次重建(清除副本)二进制库,因此不希望调用conan create。 如果使用的是IDE或本地调用conan build命令,则此方法将保留构建缓存。

    1、打包预构建的二进制库

            运行build()方法时,如果要打包的是本地文件,则不会产生任何附加值,因为从用户文件夹复制来的文件是无法复制的。对于这种情况,直接运行conan export-pkg命令。
            仍然需要Conan配方,但非常简单,只需包含包的元信息。可以使用conan new命令创建基本配方:$ conan new hello/0.1 --bare
            这将在创建并在本地缓存中存储以下包配方:

    class HelloConan(ConanFile):
        name = "hello"
        version = "0.1"
        settings = "os", "compiler", "build_type", "arch"
    
        def package(self):
            self.copy("*")
    
        def package_info(self):
            self.cpp_info.libs = self.collect_libs()
    

            提供的package_info()方法将扫描包文件,为最终用户提供要链接的库的名称。可以进一步自定义此方法以提供其他构建标志(通常取决于设置)。默认的package_info()的应用如下:它定义“include”文件夹中的头文件、“lib”文件夹中的库以及“bin”文件夹中的二进制文件。可以在package_info()方法中定义不同的包目录布局。
            还可以扩展此包配方,以支持更多配置(例如,添加选项:shared/static,或使用不同的设置)、添加依赖项(requires)等。
            基于上面所述,假设当前目录包含一个lib文件夹,其中包含此“hello”二进制库libhello.a,例如与Windows MinGW(gcc)4.9版本兼容:

    $ conan export-pkg . hello/0.1@myuser/testing  -s os=Windows -s compiler=gcc -s compiler.version=4.9 ...
    

            仍然强烈建议在上传之前在本地使用test_package文件夹测试包。由于不想从源码构建包,因此流程为:

    $ conan new hello/0.1 --bare --test
    # customize test_package project
    # customize package recipe if necessary
    $ cd my/path/to/binaries
    $ conan export-pkg PATH/TO/conanfile.py hello/0.1@myuser/testing  -s os=Windows -s compiler=gcc -s compiler.version=4.9 ...
    $ conan test PATH/TO/test_package/conanfile.py hello/0.1@myuser/testing -s os=Windows -s compiler=gcc -s ...
    

            对于任意数量的配置,可以重复最后两个步骤。

    2、下载和打包预构建的二进制库

            在此种情况下,创建一个完整的Conan配方,并详细检索二进制文件是首选方法,因为它是可复制的,并且可以跟踪原始二进制文件。为此,请参照样品配方:

    class HelloConan(ConanFile):
        name = "hello"
        version = "0.1"
        settings = "os", "compiler", "build_type", "arch"
    
        def build(self):
            if self.settings.os == "Windows" and self.settings.compiler == "Visual Studio":
                url = ("https://<someurl>/downloads/hello_binary%s_%s.zip"
                       % (str(self.settings.compiler.version), str(self.settings.build_type)))
            elif ...:
                url = ...
            else:
                raise Exception("Binary does not exist for these settings")
            tools.get(url)
    
        def package(self):
            self.copy("*") # assume package as-is, but you can also copy specific files or rearrange
    
        def package_info(self):  # still very useful for package consumers
            self.cpp_info.libs = ["hello"]
    

            通常,预编译的二进制文件用于不同的配置,因此build()方法必须实现的唯一任务是将settings映射到不同的URLs。
            注意:

    • 这是一个标准的Conan包,即使二进制文件正在从其他地方检索。推荐的方法是使用conan create,并在上述配方之外包含一个小工程用于本地测试,然后继续将带有二进制文件的使用conan upload命令上传到Conan远程仓库。
    • 同样的构建策略应用。如果未创建任何Conan包,并且未定义--build参数,则配方失败。这种包的典型用法是定义build_policy="missing",尤其是当URLs也在团队控制下时。如果它们是外部的(在网上),最好创建包并将其存储在自己的Conan服务器上,以便构建不依赖于第三方URL。

    五、了解打包

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

    1、手动创建和测试包

            使用test_package子文件夹的create方法不是必需的(尽管强烈建议使用)。如果不想使用test_package功能,可以自己编写配方,或者使用不带-tconan new命令。

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

            这将只创建conanfile.py配方文件。现在可以创建包:

    $ conan create . demo/testing
    

            相当于:

    $ conan export . demo/testing
    $ conan install hello/0.1@demo/testing --build=hello
    

            创建软件包后,可以通过向项目的conanfile.txtconanfile.py文件中添加需求hello/0.1@demo/test,并运行以下命令,像使用其他任何包一样使用它:

    $ conan install .
    # build and run your project to ensure the package works
    

    2、包的创建过程

            对于包创建者和Conan用户来说,了解在Conan本地缓存中创建包的流程及其布局是非常有用的。
            每个包配方在本地缓存中包含五个重要文件夹:

    • export:存储包配方的文件夹。
    • export_source:使用配方exports_sources属性复制的代码存储在该文件夹中。
    • source:该文件夹用来存储从源码构建的源代码。
    • build:完成实际源码编译的文件夹。 对于每种不同的二进制配置,通常会有一个子文件夹。
    • package:最终包所在的文件夹。 每个不同的二进制配置都有一个子文件夹。

            只有当从源构建包时,source文件夹和build文件夹才存在。
    在这里插入图片描述
            当包通过conan export命令“导出”时,该过程开始,或者使用conan create命令。conanfile.py和由exports_source字段指定的文件从用户空间复制到本地缓存。
            将exportexport_source中的文件复制到source文件夹,然后执行source()方法(如果存在的话)。请注意,所有二进制包只有一个源文件夹。如果在生成代码时,源码因不同配置而有所不同,则不能使用source()方法生成,而需要使用build()生成方法。
            然后,对于每个不同的设置和选项的配置,将以该配置的SHA-1哈希的形式计算包ID。源将被复制到build/hashXXX文件夹中,并且将触发build()方法。
            之后,将调用package()方法将包文件从build/hashXXX文件夹复制到package/hashXXX文件夹。
            最后,将调用并收集所有依赖项的package_info()方法,以便可以为使用者生成构建系统文件,就像cmake生成器的conanbuildinfo.cmake文件一样。此外,imports功能还会将包文件从本地缓存复制到用户空间(如果有指定的话)。

    六、定义包的ABI兼容性

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

            每个包配方可以从中生成N个二进制包,具体取决于以下三个选项:settingsoptionsrequires
            当包配方的任意设置发生变化时,它将引用不同的二进制文件:

    class MyLibConanPackage(ConanFile):
        name = "mylib"
        version = "1.0"
        settings = "os", "arch", "compiler", "build_type"
    

            当包由conanfile.txt、另一个包由conanfile.py或直接安装时:

    $ conan install mylib/1.0@user/channel -s arch=x86_64 -s ...
    

            它的流程为:

    • Conan获取用户输入的settingsoptions。这些settingsoptions可以来自命令行、配置文件或最新的conan install执行时缓存的值。
    • Conan检索mylib/1.0@user/channel配方,读取settings属性,并分配必要的值。
    • 使用当前包的settings值(还有optionsrequires),它将计算出一个SHA1哈希值,该哈希值将用作二进制包ID,例如,c6d75a933080ca17eb7f076813e7fb21aaa740f2
    • Conan将尝试查找c6d75...二进制包。如果它存在,它将被检索。如果不存在,将会失败,并提示可以使用conan install -- build从源中构建它。

            如果使用不同的设置(例如,在32位体系结构上)再次安装包:

    $ conan install mylib/1.0@user/channel -s arch=x86 -s ...
    

            将使用不同的生成包ID重复该过程,因为arch设置了不同的值。这中场景同样适用于不同的编译器、编译器版本和构建类型。生成多个二进制文件时,会为每个配置生成一个单独的ID。
            当使用该包的开发人员使用与那些已上载的二进制文件之一相同的设置时,计算出的包ID将相同,从而无需重新从源代码中重建二进制文件即可对其进行检索和重用。
            options的行为非常相似。 主要区别在于,可以在包级别更轻松地定义options,并且可以将其作为默认值。
            请注意仅有头文件的库的情况。这时包不需要构建,也不会有任何ABI问题。此类包的配方将不再生成单个二进制包。很容易通过在配方中不声明settingsoptions来实现,如下所示:

    class MyLibConanPackage(ConanFile):
        name = "MyLib"
        version = "1.0"
        # no settings defined!
    

            无论用户定义了哪些设置(包括编译器或版本),包的settingsoptions都将始终相同(保留为空),并且它们将散列为相同的二进制包ID。 这些包包通常仅包含头文件。
            如果有一个库,它可以用GCC 4.8构建并且可以保留与GCC 4.9兼容的ABI,会发生什么?(例如,对于纯C库,这种兼容性更容易实现)。
            尽管值得用4.9对它进行重新构建,以获得修复和性能改进。 假设我们不想创建2个不同的二进制文件,而只是创建一个使用GCC 4.8构建的二进制文件,并且还需要与GCC 4.9兼容。

    1、自定义package_id()

            默认的package_id()直接使用所定义的settingsoptions,并假定在require中定义了依赖项的语义版本
            可以覆盖此package_id()方法来控制包ID的生成。在package_id()中,可以访问self.info对象,该对象经过散列然后计算二进制ID,包含:

    • self.info.settings:包含所有声明的设置,始终作为字符串值。我们可以访问/修改设置,例如self.info.settings.compiler.version
    • self.info.options: 包含所有声明的选项,也始终作为字符串值,例如self.Info.options.shared

            最初,此info对象包含原始的设置和选项,但可以不受任何其他字符串值的约束而对其进行更改。
            例如,如果确定包ABI兼容GCC > 4.5和< 5.0之间的版本,可以执行以下操作:

    from conans import ConanFile, CMake, tools
    from conans.model.version import Version
    
    class PkgConan(ConanFile):
        name = "pkg"
        version = "1.0"
        settings = "compiler", "build_type"
    
        def package_id(self):
            v = Version(str(self.settings.compiler.version))
            if self.settings.compiler == "gcc" and (v >= "4.5" and v < "5.0"):
                self.info.settings.compiler.version = "GCC version between 4.5 and 5.0"
    

            我们使用任意字符串设置了self.info.settings.compiler.version,该字符串的值并不重要(可以是任何字符串)。 唯一重要的是,对于4.5到5.0之间的任何GCC版本,它都是相同的。 对于所有这些版本,编译器版本将始终哈希为相同的ID。
            让我们尝试使用GCC 4.5 时它是否正常工作:

    $ conan create . pkg/1.0@myuser/mychannel -s compiler=gcc -s compiler.version=4.5 ...
    
    Requirements
        pkg/1.0@myuser/mychannel from local
    Packages
        pkg/1.0@myuser/mychannel:af044f9619574eceb8e1cca737a64bdad88246ad
    ...
    

            可以看到,计算出的包ID是af04 ... 46ad(这里只是举例)。 如果指定GCC 4.6会发生什么?

    $ conan install pkg/1.0@myuser/mychannel -s compiler=gcc -s compiler.version=4.6 ...
    
    Requirements
        pkg/1.0@myuser/mychannel from local
    Packages
        pkg/1.0@myuser/mychannel:af044f9619574eceb8e1cca737a64bdad88246ad
    

            所要求依赖的包ID同样为af04 ... 46ad。 现在可以尝试使用GCC 4.4(< 4.5):

    $ conan install Pkg/1.0@myuser/mychannel -s compiler=gcc -s compiler.version=4.4 ...
    
    Requirements
        pkg/1.0@myuser/mychannel from local
    Packages
        pkg/1.0@myuser/mychannel:7d02dc01581029782b59dcc8c9783a73ab3c22dd
    

            计算出的包ID是不同的,这意味着需要针对GCC 4.4的提供不同二进制包。
            与调整self.info.settings的方式相同,如果需要,可以设置self.info.options值。

    2、兼容包

            警告: 这是一项实验性功能,可能会在将来的版本中发生重大更改。
            上面的方法为不同的输入配置定义了1个程序包ID。 例如,无论用于构建的gcc是什么版本,所有(v >= "4.5" and v < "5.0")版本范围内的gcc将具有完全相同的包ID。 它的工作原理类似于信息擦除,一旦二进制文件构建完成,就不可能知道是哪个gcc构建了它。
            但是可以定义具有不同包ID的兼容二进制文件。 例如,每个gcc版本可以有不同的二进制文件,因此gcc 4.8构建的包ID将不同于gcc 4.9构建的包ID,并且仍然可以定义在使用gcc 4.9构建时使用gcc 4.8构建的包。
            可以定义一个兼容包的有序列表,如果配置文件定义的包ID不可用,则会对其进行检查。 例子:
            假如正在使用gcc 4.9进行配置。 但是对于给定的包,如果找不到使用gcc 4.9构建的二进制文件,希望退回到使用gcc 4.8gcc 4.7构建的二进制文件。 可以这样定义:

    from conans import ConanFile
    
    class Pkg(ConanFile):
        settings = "os", "compiler", "arch", "build_type"
    
        def package_id(self):
            if self.settings.compiler == "gcc" and self.settings.compiler.version == "4.9":
                for version in ("4.8", "4.7"):
                    compatible_pkg = self.info.clone()
                    compatible_pkg.settings.compiler.version = version
                    self.compatible_packages.append(compatible_pkg)
    

            注意,如果输入配置为gcc 4.8,则由于不满足条件,它将不会尝试回退到gcc 4.7的二进制文件。
            self.info.clone()方法从配方的当前实例中复制settingsoptionsrequires的值,以便可以对其进行修改来模拟兼容性。
            开发人员需要确保此类二进制文件具有兼容性。例如:

    from conans import ConanFile
    class Pkg(ConanFile):
        options = {"optimized": [1, 2, 3]}
        default_options = {"optimized": 1}
        def package_id(self):
            for optimized in range(int(self.options.optimized), 0, -1):
                compatible_pkg = self.info.clone()
                compatible_pkg.options.optimized = optimized
                self.compatible_packages.append(compatible_pkg)
    

            此配方定义二进制文件与其自身以较低的优化值所构建的二进制文件兼容。 它最多有3种不同的二进制文件,每个optimized选项的不同值对应一个。 package_id()定义了一个以optimized=1构建的二进制文件,它可以链接和运行,即使在配置中定义了optimized=2optimized=3。如果所配置的是optimized=1,则不会使用optimized=2构建的二进制文件。

    3、兼容编译器

            一些编译器使用基本编译器进行操作,例如,intel编译器在Windows环境中使用Visual Studio编译器,在Linux环境中使用gcc
            intel编译器在setting.yml中以这种方式声明:

    intel:
        version: ["11", "12", "13", "14", "15", "16", "17", "18", "19"]
        base:
            gcc:
                <<: *gcc
                threads: [None]
                exception: [None]
            Visual Studio:
                <<: *visual_studio
    

            请记住,可以扩展Conan以支持其他编译器。
            可以使用package_id()方法来定义base编译器生成的包和parent编译器生成的包之间的兼容性。 您可以将以下辅助程序与兼容包功能一起使用:

    • 当配置文件中的输入编译器为intel时,使用本机Visual Studio包(如果没有intel包可用)。
    • 反之,当使用者配置文件将Visual Studio指定为输入编译器时(如果没有可用的Visual Studio程序包),将使用intel编译器程序包。
    • base_compatible():此函数把用于计算包ID的设置转换为 “base” 编译器。
    def package_id(self):
    
        if self.settings.compiler == "intel":
            p = self.info.clone()
            p.base_compatible()
            self.compatible_packages.append(p)
    

            使用上述package_id()方法,如果使用者指定使用intel配置文件(-s complier=="intel"),并且没有可用的二进制文件,它将解析为与基本编译器对应的Visual Studio包ID。

    • parent_compatible(compiler="compiler", version="version"):此函数使用指定的设置作为基本编译器,将编译器的设置转换为父编译器的设置。由于无法猜测“parent”兼容的详细信息,因此必须将它们作为关键字参数提供给函数。“compiler”参数是强制性的,其余的关键字参数将用于初始化info.settings.com piler.XXX对象,以计算正确的包ID。
    def package_id(self):
    
       if self.settings.compiler == "Visual Studio":
          compatible_pkg = self.info.clone()
          compatible_pkg.parent_compatible(compiler="intel", version=16)
          self.compatible_packages.append(compatible_pkg)
    

            在这种情况下,对于指定Visual Studio编译器的使用者,如果找不到包,它将为16版本搜索“ intel”包。
            考虑到也可以不使用“兼容软件包”功能而使用这些辅助程序:

    def package_id(self):
    
       if self.settings.compiler == "Visual Studio":
          self.info.parent_compatible(compiler="intel", version=16)
    

            在上面的示例中,我们将Visual Studio包的ID转换为与intel 16相同的包ID,但是这样将无法区分使用intel构建的包与Visual Studio所构建的包,因为它们有相同的包ID,这种方式并不总是可取的。

    4、依赖问题

            假设有一个简单的场景,其中有两个包:my_other_lib/2.0和依赖于它的my_lib/1.0。 假设它们的配方和二进制文件已经创建并上传到Conan远程服务器。
            现在发布了my_other_lib/2.1的新版本,其中包含改进的配方和新的二进制文件。my_lib/1.0已修改,需要升级到my_other_lib/2.1
            注意: 如果项目my_lib/1.0定义了对my_other_lib/2.1的依赖关系,而该依赖项优先于my_lib/1.0中的现有项,则此方案将相同。
            问题是:是否有必要构建新的my_lib/1.0二进制包?还是现有的包仍然有效?
            答案是:视情况而定。
            假设这两个包都被编译为静态库,并且my_other_lib通过公共头向my_lib/1.0公开的API没有改变。在这种情况下,不需要为my_lib/1.0构建新的二进制文件,因为最终的使用者将同时链接到my_lib/1.0my_other_lib/2.1
            另一方面,公共头中my_other_lib公开的API可能发生了变化,但是不会因为任何原因影响my_lib/1.0二进制文件(例如由my_lib不使用新功能的更改)。如果MyOtherLib只有头文件,同样的推断也适用。
            但是,如果名为myadd.h的my_other_lib的头文件从2.0更改为2.1,该如何呢?
    2.0版中的myadd.h头文件:

    int addition (int a, int b) { return a - b; }
    

    2.1版中的myadd.h头文件:

    int addition (int a, int b) { return a + b; }
    

            假设my_lib/1.0对应的代码调用了addition()函数?
            这样的话,需要为新的依赖项版本构建my_lib/1.0的新二进制文件。
            否则,它将保持旧的、有缺陷的addition()版本。即使my_lib/1.0的代码在配方中没有任何更改,重新构建my_lib所生成的二进制文件也需要my_other_lib/2.1,并且包也不同。

    5、对包依赖使用package_id()

            self.info对象还有一个require对象。 它是一个字典,其中包含每个需求,所有直接和传递依赖项的必要信息。 例如,self.info.requires["my_other_lib"]RequirementInfo对象。

    • 每个RequirementInfo都有以下只读字段:
      full_name:完整要求的名称,例如,my_other_lib
      full_version:完整要求的版本,例如,1.2
      full_user:完全要求的用户,例如,my_user
      full_channel:完整要求的通道,例如,stable
      full_package_id:完整要求的软件包ID,例如,c6d75a…
    • 以下字段用于package_id()计算:
      name:默认情况下,与full_name的值相同,例如,my_other_lib
      version:默认情况下,full_version的主版本表示形式。 例如,对于full_version为1.2版本时,字段为1.Yfull_version为1.2.3版本时,字段为1.Y.Z
      user:默认情况下为None(不影响包ID)
      channel:默认情况下为None(不会影响包ID)
      package_id:默认情况下为None(不影响包ID)

            在为模型依赖关系定义包ID时,必须考虑两个因素:

    • 遵循要求的版本控制模式,semver?custom?
    • 正在构建或复用的库的类型,共享库(.so、.dll、.dylib)?静态库?

    七、定义包的信息

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

            创建用于类库包的配方时,重要的是定义有关包的信息,以便使用者可以正确获取信息。 Conan通过将包的信息与使用生成器所需的格式解耦来实现此目的,生成器将通用信息转换为适当的格式文件。
            使用package_info()方法在配方内部定义此通用信息。 在这里,可以声明包信息,例如头文件的位置,库名,定义,标志等等。

    from conans import ConanFile
    
    class MyConan(ConanFile):
        name = "cool_library"
        ...
    
        def package_info(self):
            self.cpp_info.includedirs = ["include/cool"]
            self.cpp_info.libs = ["libcool"]
            self.cpp_info.defines= ["DEFINE_COOL=1"]
    

            包信息使用cpp_info对象的属性完成。此信息将由Conan汇总,并通过self.deps_cpp_info向使用者和生成器公开。
            重要: 该信息非常重要,因为它以一种非常简单的语法以通用的方式描述了包内容,随后可以将其转换为合适的格式。 在这里拥有此信息的优点是,可以从用于编译该库的另一种构建系统中使用该包。 例如,使用Autotools构建的库可以稍后在CMake中使用任何CMake生成器使用此信息来使用。

    1、使用组件

            如果包包含多个库,或者想定义单独的组件,以便使用者可以使用更详细的信息,则可以在package_info()方法中使用组件。
            警告: 这是一项实验性功能,可能会在将来的发行版本中进行重大更改。
            创建Conan包时,建议每个包仅包含一个库(.lib,.a,.so,.dll…)。 但是,特别是对于Boost,Poco或OpenSSL等第三方项目,它们将在其中包含多个库。
            通常,同一包中的那些库相互依赖,并且需要对它们之间的关系进行建模。
            使用组件,可以在同一程序包中对库和可执行文件进行建模,以及它们如何相互依赖。 每个库或可执行文件都是cpp_info中的一个组件,如下所示:

    def package_info(self):
        self.cpp_info.name = "OpenSSL"
        self.cpp_info.components["crypto"].names["cmake_find_package"] = "Crypto"
        self.cpp_info.components["crypto"].libs = ["libcrypto"]
        self.cpp_info.components["crypto"].defines = ["DEFINE_CRYPTO=1"]
        self.cpp_info.components["ssl"].names["cmake"] = "SSL"
        self.cpp_info.components["ssl"].includedirs = ["include/headers_ssl"]
        self.cpp_info.components["ssl"].libs = ["libssl"]
        self.cpp_info.components["ssl"].requires = ["crypto"]
    

            可以使用require属性和组件名称定义不同组件之间的依赖关系。 将为每个字段计算组件的依赖性图,并以正确的顺序汇总值。

    def package_info(self):
        self.cpp_info.components["LibA"].libs = ["liba"]      # Name of the library for the 'LibA' component
        self.cpp_info.components["LibA"].requires = ["LibB"]  # Requires point to the name of the component
    
        self.cpp_info.components["LibB"].libs = ["libb"]
    
        self.cpp_info.components["LibC"].libs = ["libc"]
        self.cpp_info.components["LibC"].requires = ["LibA"]
    
        self.cpp_info.components["LibD"].libs = ["libD"]
        self.cpp_info.components["LibD"].requires = ["LibA"]
    
        self.cpp_info.components["LibE"].libs = ["libe"]
        self.cpp_info.components["LibE"].requires = ["LibB"]
    
        self.cpp_info.components["LibF"].libs = ["libf"]
        self.cpp_info.components["LibF"].requires = ["LibD", "LibE"]
    

            对于使用者和生成器,此组件图中的库顺序为:

    self.deps_cpp_info.libs == ["libf", "libe", "libd", "libc", "liba", "libb"]
    

            还允许从其他包中声明要求:

    class MyConan(ConanFile):
        ...
        requires = "zlib/1.2.11", "openssl/1.1.1g"
    
        def package_info(self):
            self.cpp_info.components["comp1"].requires = ["zlib::zlib"]  # Depends on all components in zlib package
            self.cpp_info.components["comp2"].requires = ["comp1", "openssl::ssl"]  # Depends on ssl component in openssl package
    

            默认情况下,组件不会链接到配方所需的任何其他包。 requires列表必须显式地使用来自其他包的组件列表来填充:可以是完整需求(zlib::zlib)或单个组件(openssl::ssl)。
            重要: 组件的信息汇总到全局cpp_info范围,并且组件的使用应透明。
            使用者可以照常通过self.deps_cpp_info获取此信息,并将其用于任何依赖配方的build()方法中:

    class PocoTimerConan(ConanFile):
        ...
        requires = "zlib/1.2.11", "openssl/1.0.2u"
        ...
    
        def build(self):
            # Get the include directories of the SSL component of openssl package
            self.deps_cpp_info["openssl"].components["ssl"].include_paths
    

            需要包声明组件的配方也可以利用这种粒度,它们可以在要求的组件列表属性cpp_info.requires中声明:

    class Library(ConanFile):
        name = 'library'
        requires = "openssl/1.0.2u"
    
        def package_info(self):
            self.cpp_info.requires = ['openssl::ssl']
    

            在前面的示例中,“library”包及其所有使用者将只与openssl包中的ssl组件链接。

    八、工具链

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

            工具链是在Conan中与构建系统集成的新的试验性方法。 配方可以定义一个generate()方法,该方法将返回一个对象,该对象可以从当前配置生成文件,供构建系统使用。 Conan生成器提供有关依赖项的信息,而工具链提供Conan的settingsoptions以及配方定义的配置到构建系统可以理解的内容的“翻译”。 没有依赖关系的配方不需要生成器,但仍可以使用工具链。
            可以在内置工具链中使用以下属性定义工具链:

    generators = "<ToolChainClassName>"
    

            例如,使用CMake工具链可以如下声明:

    generators = "CMakeToolchain"
    

            注意:当前(Conan 1.32),有效的内建工具链有:CMakeToolchainMakeToolchainMSBuildToolchainMesonToolchain
            在更多的情况下,如果它需要任何超出默认配置的特定配置:

    from conan.tools.cmake import CMakeToolchain
    
    def generate(self):
        tc = CMakeToolchain(self)
        # customize toolchain "tc"
        tc.generate()
    

            可以使用generate()方法来创建文件,通常是从当前的self.settingsself.options配置导出。

    from conans.tools import save
    
    def generate(self):
        # Based on the self.settings, self.options, the user
        # can generate their own files:
        save("mytoolchain.tool", "my own toolchain contents, deduced from the settings and options")
        # The "mytoolchain.tool" file can be used by the build system to
        # define the build
    

            和平常一样,可以创建自己的工具链助手,把它们放在python_requires包中,并在所有的配方中可以进行复用。
            工具链具有一些重要的优点:

    • 它们在conan install时执行。 它们生成文件而不是命令行参数,从而提供了更好的可重复性和构建调试。
    • 他们提供了更好的开发人员体验。 开发人员在本地使用的命令行(例如cmake ...)将与conan build或使用conan create在缓存中完成的构建实现相同的构建,并带有相同的标识。
    • 它们更具可扩展性和可配置性。

            工具链实现了大多数构建系统逻辑,而使诸如CMake()之类的构建助手的工作量减少了,并且基本上充当了构建系统的高级包装器。 这些构建助手的许多现有参数,属性或方法将不可用。 检查每个工具链的文档,以检查相关联的构建助手的可用功能。

    from conan.tools.cmake import CMakeToolchain, CMake
    
    def generate(self):
        tc = CMakeToolchain(self)
        # customize toolchain "tc"
        tc.generate()
    
    def build(self):
        # NOTE: This is a simplified helper
        # Not all arguments attributes and methods might be available
        cmake = CMake(self)
    

    1、CMakeToolchain

    2、MakeToolchain

    3、MesonToolchain

    九、检查包

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

            可以通过运行conan get命令来检查上传的包以及本地缓存中的包。

    • 列出本地配方文件夹的文件:
    $ conan get zlib/1.2.11@ .
    
    Listing directory '.':
     conandata.yml
     conanfile.py
     conanmanifest.txt
    
    • 打印二进制包的conaninfo.txt文件:
    $ conan get zlib/1.2.11@:2144f833c251030c3cfd61c4354ae0e38607a909
    
    • 从远程包打印conanfile.py
    import os
    import stat
    from conans import ConanFile, tools, CMake, AutoToolsBuildEnvironment
    from conans.errors import ConanException
    
    class ZlibConan(ConanFile):
        name = "zlib"
        version = "1.2.11"
        url = "https://github.com/conan-io/conan-center-index"
        homepage = "https://zlib.net"
    
        #...
    

    十、打包方式

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

            包配方有三种方法来控制包的二进制兼容性和实现不同的打包方法:package_id()build_id()package_info()
            这些方法让包创建者选择每个库的最合适方法。

    1、1 config (1 build) -> 1 package

            一种典型的方法是为每个包设置一个配置。例如,使用这种方法,debug版预编译库将和release版预编译库将会位于不同的包中。
            因此,如果有一个构建“hello”库的包配方,那么将有一个包含“hello.lib”发行版本的包和一个包含该库的调试版本的包(在图中表示为“hello_d.lib”,为了清楚起见,没有必要使用不同的名称)。
    在这里插入图片描述
            使用这种方法,package_info()方法允许为使用者设置适当的值,让他们知道包库的名称、必要的定义和编译标识。

    class HelloConan(ConanFile):
    
        settings = "os", "compiler", "build_type", "arch"
    
        def package_info(self):
            self.cpp_info.libs = ["mylib"]
    

            请务必注意,它将build_type声明为一种设置。这意味着将为该设置的每个不同值生成不同的包。
            包声明的值(默认情况下已经定义了includelibbin子文件夹,因此它们定义了包的include和library路径)被生成器转换为各个构建系统的变量。也就是说,运行cmake生成器会将上述定义转换conanbuildinfo.cmake中的以下内容:

    set(CONAN_LIBS_MYPKG mylib)
    # ...
    set(CONAN_LIBS mylib ${CONAN_LIBS})
    

            这些变量将在conan_basic_setup()宏中使用,以实际设置相关的cmake变量。
            如果开发人员想要切换依赖项的配置,他们通常会这样切换:

    $ conan install -s build_type=Release ...
    # when need to debug
    $ conan install -s build_type=Debug ...
    

            这种切换将很快,因为所有依赖项都已在本地缓存。
            此过程有许多优点:

    • 实施和维护非常容易。
    • 包的大小很小,因此磁盘空间和传输速度更快,并且从源构建也保持在最低限度。
    • 配置的解耦可能有助于隔离与混合不同类型的工件的相关问题,并保护有价值的信息免受部署和发布错误的影响。例如,调试工件可能包含符号或源码,这可以帮助或直接提供逆向工程的方法。因此,错误地发布调试工件可能是一个非常危险的问题。

    2、N configs -> 1 package

            你可能希望将debug版和release版工件打包在同一个包中,以便可以在IDEs(如Visual Studio)中使用。这使得可以从IDE更改debug/release配置,而无需在命令行中指定。这种类型的包可以包含不同配置的不同工件,并且可以用于在同一包中包括库的debug版和release版。
    在这里插入图片描述
            注意: 可以在在示例存储库中可以找到以下代码的完整工作示例:https://github.com/conan-io/examples

    $ git clone https://github.com/conan-io/examples.git
    $ cd features/multi_config
    $ conan create . user/channel
    

            创建多配置的debug/release包很简单。
            第一步是从设置中删除build_type。它将不是输入设置,并且生成的包将始终包含debug和release工件。
            Visual Studio运行时对于debug和release(MDd或MD)而言是不同的,并且使用默认运行时(MD/MDd)进行设置。如果这满足需要,建议在configure()方法中删除compiler.runtime子设置。

    class HelloConan(ConanFile):
        # build_type has been omitted. It is not an input setting.
        settings = "os", "compiler", "arch"
        generators = "cmake"
    
        # Remove runtime and use always default (MD/MDd)
        def configure(self):
            if self.settings.compiler == "Visual Studio":
                del self.settings.compiler.runtime
    
        def build(self):
            cmake_release = CMake(self, build_type="Debug")
            cmake_release.configure()
            cmake_release.build()
    
            cmake_debug = CMake(self, build_type="Release")
            cmake_debug.configure()
            cmake_debug.build()
    

            在本示例中,二进制文件将在CMake语法中使用后缀进行区分,因此必须将此信息添加到package_info()函数中提供给使用者的数据中:

    set_target_properties(mylibrary PROPERTIES DEBUG_POSTFIX _d)
    

            这样的包可以将其信息定义为:

    def package_info(self):
        self.cpp_info.release.libs = ["mylibrary"]
        self.cpp_info.debug.libs = ["mylibrary_d"]
    

            这将转换为CMake变量:

    set(CONAN_LIBS_MYPKG_DEBUG mylibrary_d)
    set(CONAN_LIBS_MYPKG_RELEASE mylibrary)
    # ...
    set(CONAN_LIBS_DEBUG mylibrary_d ${CONAN_LIBS_DEBUG})
    set(CONAN_LIBS_RELEASE mylibrary ${CONAN_LIBS_RELEASE})
    

            这些变量将由conan_basic_setup()助手正确地应用于每个配置。
            在这种情况下,仍然可以使用常规变量而不是特定于配置的变量。例如,当默认设置为include时,debug和release的包含目录保持不变。这些通用变量将应用于所有配置。

            重要: 上面的代码假定包始终使用默认的Visual Studio运行时(MD/MDd)。要使包可配置为支持VS运行时库的静态(MT)/动态(MD)链接,可以执行以下操作:

    • 保持compile.runtime设置,例如,不要实现configure()方法将其删除。
    • 不要让CMake辅助程序定义CONAN_LINK_RUNTIME变量来定义运行时,而应定义CONAN_LINK_RUNTIME_MULTI来替代。
    • CMakeLists.txt文件中,使用CONAN_LINK_RUNTIME_MULTI变量正确设置debug和release标识的运行时。

            所有这些步骤已经在仓库https://github.com/conan-io/examples/tree/master/features/multi_config进行了编码。

    3、N configs (1 build) -> N packages

            现有的构建脚本可能同时为不同的配置(如debug/release)或不同的体系结构(32/64 位)或库类型(共享/静态)构建二进制文件。如果在前面的“单一配置包”方法中使用这样的构建脚本,它肯定可以毫无问题地工作。但是,我们将会浪费宝贵的构建时间,因为我们将为每个包重建项目,然后为相关配置提取相关工件,而忽略其他工件。
            构建逻辑会更有效,从而可以复用相同的构建来创建不同的包:
    在这里插入图片描述
            这可以通过在包配方中定义指定逻辑的build_id()方法来完成。

    settings = "os", "compiler", "arch", "build_type"
    
    def build_id(self):
        self.info_build.settings.build_type = "Any"
    
    def package(self):
        if self.settings.build_type == "Debug":
            #package debug artifacts
        else:
            # package release
    

            请注意,build_id()方法使用self.info_build对象来更改构建哈希。如果方法没有改变它,哈希将与包文件夹匹配。通过设置build_type="Any",强制对build_type的Debug和Release值进行处理,哈希值是一样的(特定字符串几乎不相关,只要两种配置相同)。请注意,构建哈希sha3将不同于sha1sha2包标识符。
            这并不意味着将有严格的一个构建文件夹。每个配置(架构、编译器版本等)都将有一个构建文件夹。因此,如果我们只有Debug/Release构建类型,并且我们为N种不同的配置生成N个包,那么我们将拥有N/2个构建文件夹,从而节省了一半的构建时间。

    十一、包创建器工具

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

            使用Python(或仅使用纯shell或bash)脚本,可以针对许多不同的配置轻松自动化整个包的创建和测试过程。例如,可以将以下脚本放在包根文件夹中,命名为build.py

    import os, sys
    import platform
    
    def system(command):
        retcode = os.system(command)
        if retcode != 0:
            raise Exception("Error while executing:\n\t %s" % command)
    
    if __name__ == "__main__":
        params = " ".join(sys.argv[1:])
    
        if platform.system() == "Windows":
            system('conan create . demo/testing -s compiler="Visual Studio" -s compiler.version=14 %s' % params)
            system('conan create . demo/testing -s compiler="Visual Studio" -s compiler.version=12 %s' % params)
            system('conan create . demo/testing -s compiler="gcc" -s compiler.version=4.8 %s' % params)
        else:
            pass
    

            这是一个纯Python脚本,与Conan无关,应该这样运行:

    $ python build.py
    

            我们为包创建者开发了另一个FOSS工具,即Conan Package Tools,可帮助从包配方生成多个二进制包。它提供了一种简单的方法来定义不同的配置并调用conan test。此外还提供像Travis CIAppveyorBamboo这样的CI集成,用于基于云的自动化二进制包创建、测试和上传。
            此工具可通过简单的$ git push在云上创建数百个二进制包,并支持:

    • 轻松生成具有不同配置的多个Conan包。
    • Travis/Appveyor服务器中的自动/远程包生成,以及CI作业中的分布式构建,用于大/慢的构建。
    • Docker:在Linux和Travis CI中为几个版本的gcc和clang自动生成包。
    • 使用apple-clang和Travis-CI自动创建OSX包。
    • Visual Studio:使用检测到的设置自动配置命令行环境。

            它在pypi中可用:

    $ pip install conan_package_tools
    
    展开全文
  • Conan教程(1)—— 简介

    千次阅读 2020-12-30 15:59:25
    Conan是一个去中心的C/C++语言的包管理器。它是免费开源的,可以在所有平台上工作:Windows、Linux、OSX、FreeBSD、Solaris等,并且可以用于开发所有目标,包括:嵌入式、移动端(iOS、Android)、裸机。同样集成了...
  • xmake 是一个基于 Lua 的轻量级跨平台...这是用来干什么的呢,做过交叉编译以及有 C/C++ 项目移植经验的同学应该知道,折腾各种交叉编译工具链,移植编译项目是非常麻烦的一件事,需要自己下载对应工具链,并且配置工
  • 但是它们有区别,使用Windows + Cygwin,可以在Windows上学习Linux命令,还可以在Windows上做Linux软件的开发,包括用GCC编译elf(交叉编译);使用Windows/Linux + MingW,可以不使用Windows的MSVC,用GNU的自由...
  • napi cmake 编译node包 使用napi提供的方法把cmake c++项目打成node包,提供给javaScript用require引用 环境准备 第一步: 下载cmake-js npm i cmake-js -g 第一步: 改造CMakeLists.txt文件 cmake_minimum_...
  • cmake指定编译器: set(TOOLCHAIN "/opt/psdk/gcc-arm-aarch64-none-linux-gnu") #指定C编译器 set(CMAKE_C_COMPILER "${TOOLCHAIN}/bin/aarch64-none-linux-...这个在交叉编译中经常使用到,使用cmake构建工程时,需要
  • C++开源库列表

    千次阅读 2020-05-11 06:28:00
    conan vcpkg build2 cget hunter 通用 Boost - 大量通用库的汇集( Boost 许可) GSL - Guideline Support Library 实现,为 Bjarne Stroustrup, Herb Sutter 和 Co 在《 C++ 核心方针》中推荐 BDE - 来自 Bloomberg...
  • PDCurses: 具有源代码和预编译库的公共域curses库。 replxx: 支持UTF-8、语法高亮、提示的readline和libedit替换,可在Unix和Windows上工作。 tabulate: 现代C++的表格制作工具。 TCLAP: 用于在ANSI C++中定义和...
  • xmake 是一个基于 Lua 的轻量级跨平台构建工具,使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,...尽管 bpf 对 编译工具链有一定的要求,比如需要较新的 llvm/clang 和 android ndk 工具链,但是 xmak
  • R语言知识体系概览

    2016-10-11 19:01:14
    摘要: 现代的计算机“语言”,已经远远超越了机器编译、人机对话这些传统计算机科学的范畴,而是与世界交流的一种思维方式。这里介绍R语言的涉及到的内容,可谓博大精深。 R语言知识体系概览 R的极客理想系列...
  • ,包括 Linux、OS X、Windows、Solaris、FreeBSD、嵌入式和交叉编译、docker、WSL。它可以与任何构建系统集成,为 CMake、MSBuild、Makefiles 等工具提供了经过测试的支持。除此之外,它还获得了奔驰、华为等大公司...
  • 深入理解http协议

    2014-06-20 13:12:23
    1. 基础概念篇 1.1 介绍 ...它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0...
  • 然后准备gdb和gdbserver,远程调试需要在目标手机上有个类似调试客户端的东西来给gdb传送数据什么的,然后在linux上接受这些信息,进行调试,所以需要这两个东西,在网上看的资料各种在线下载或者交叉编译什么的才能...
  • 【读书笔记】Java并发编程的艺术

    千次阅读 2020-10-07 09:12:46
    例如:Java 在调用数据库时,禁止在 for 循环里写 sql 就是为了减少数据库连接的资源消耗 第二章:Java 并发机制的底层实现原理 Java 代码在编译后会变成 Java 字节码,字节码被类加载器加载到 JVM 里,JVM 执行字节...
  • Haskell趣学指南1-3

    千次阅读 2010-04-27 10:21:00
    这就意味着很大一部分错误都可以在编译时被发现,若试图将一个数字和字符串相加,编译器就会报错。haskell拥有一套强大的类型系统,支持自动类型推导。这一来你就不需要在每段代码上都标明它的类型,像计算a=5+4,你...
  • 下图是一个普通的决策树: 规则流:规则流又称决策流,它整个的结构类似于工作流,用来对已有的决策集、决策表、交叉决策表、决策树、评分卡、复杂评分卡或其它决策流的执行顺序进行编排,以清晰直观的实现一个大的...
  • 康奈尔大学课程高级编译。 cs6120 65.mikejohonson的个人主页。 mikejohonson51 66.帮你记住你的python装饰器。 memo 67.Python库RavenPy,用于设置和运行水文模型框架Raven。 RavenPy 68.R语言包doc2vec,用于构建...
  • 认识规则引擎

    2021-07-14 22:13:46
    下图是一个普通的决策树: 规则流:规则流又称决策流,它整个的结构类似于工作流,用来对已有的决策集、决策表、交叉决策表、决策树、评分卡、复杂评分卡或其它决策流的执行顺序进行编排,以清晰直观的实现一个大的...
  • 规则引擎入门篇

    2021-03-23 22:13:06
    下图是一个普通的决策树: ​ 规则流:规则流又称决策流,它整个的结构类似于工作流,用来对已有的决策集、决策表、交叉决策表、决策树、评分卡、复杂评分卡或其它决策流的执行顺序进行编排,以清晰直观的实现一个大...
  • monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到 方法结束处和异常处 .任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态. 9.锁的升级与对比 ...
  • 包管理器可以帮助你更方便地安装依赖关系,并决定所安装的版本,提高你的开发幸福感。许多语言都有自己的包管理器,像 ...1. Conan(C/C++ Package Manager) 官网:https://conan.io/ GitHub 项目地址:https:/...
  • 2 Java并发机制的底层实现原理 Java代码在编译后会变成Java字节码,字节码被类加载器加载到JVM里,JVM执行字节码,最终需要转化为汇编指令在CPU上执行,Java中所使用的并发机制依赖于JVM的实现和CPU的指令。...

空空如也

空空如也

1 2
收藏数 28
精华内容 11
热门标签
关键字:

conan交叉编译