Conan简易教程(Ubuntu系统)

安装 artifactory-cpp-ce

artifactory-cpp-ce是支持conan的artifactory存储服务器
这里使用简单的docker-compose一键部署,需要提前安装docker及docker-compose
下面是docker-compose.yml的内容

version: "3"
services:
  artifactory-cpp-ce:
    image: akaronte/artifactory-cpp-ce:latest
    container_name: artifactory-cpp-ce
    ports:
      - "8081:8081"
      - "8082:8082"
    user: root
    volumes:
      - "./artifactory_data:/var/opt/jfrog/artifactory"

运行后打开 http://127.0.0.1:8081 进入web管理界面
默认用户名 admin,密码 password

在 artifactory-cpp-ce创建 Conan Repository

  1. 打开本地Repository创建页面
    在这里插入图片描述
  2. 点击New开始创建
    在这里插入图片描述
  3. 选择Conan类型
    在这里插入图片描述
  4. 填写创建信息

在这里插入图片描述
5. 查看创建的Repository信息
在这里插入图片描述
6. 复制Repository地址
在这里插入图片描述

在 artifactory-cpp-ce创建用户并授权

artifactory-cpp-ce 支持完整的用户权限管理,这里只演示简单的使用:创建一个用户并给这个用户分配我们刚刚创建的仓库权限。

  1. 进入用户管理界面
    在这里插入图片描述

  2. 点击New进入创建页面在这里插入图片描述

  3. 输入相关信息,点击Save创建
    在这里插入图片描述

  4. 进入创建权限页面
    在这里插入图片描述

  5. 点击下面的按钮进入创建页面
    在这里插入图片描述

  6. 输入权限名,添加Repository资源
    在这里插入图片描述

  7. 添加构建权限
    在这里插入图片描述

  8. 添加用户到该权限
    在这里插入图片描述

  9. 设置用户详细权限并保存
    在这里插入图片描述

配置本地Conan

配置conan代理(可选)

国内直接下载conan速度会比较慢,配置代理可以加速
编辑 ~/.conan2/global.conf 添加下面配置

# 忽略系统代理,否者no_proxy_match会不生效
core.net.http:clean_system_proxy=True
# 配置代理
core.net.http:proxies={"http" : "http://127.0.0.1:10809", "https" : "http://127.0.0.1:10809"}
# 配置不代理的URL地址
core.net.http:no_proxy_match=["http://127.0.0.1:8081*"]

添加远程仓库

按下面的描述替换命令中的对应位置

  1. $REMOTE: 远程仓库名称(可以和创建时候的不一样)
  2. $URL: 我们创建的远程仓库地址
conan remote add $REMOTE $URL

验证远程仓库

  1. $REMOTE: 与上面相同
  2. $USER_NAME: 上面操作创建的用户
  3. $PASSWORD: 上面操作创建的用户的密码
conan remote login $REMOTE $USER_NAME -p $PASSWORD

初始化本地配置

conan profile detect

添加本地包

这里使用 https://github.com/manx98/conan-tdlib.git 作为示例,需要先提前clone下来仓库。
进入包的根目录下

  1. 构建包到本地缓存目录

    conan create . --build=missing
    

    在这里插入图片描述

  2. 推送包到远程仓库

    1. $RECIPE: 上面构建的包名,这里为 tdlib/1.8.25@user/chanel
      • @和后面的内容可以可选的
      • user:用户(可选,默认“_”)
      • channel:信道(可选,默认“_”)
    2. $REMOTE: 需要推送到的远程仓库,这里与上面的配置相同
    conan upload $RECIPE -r=$REMOTE 
    
  3. 查看远程仓库列表

    conan remote list
    

    在这里插入图片描述

  4. 从指定仓库查找包

    # 这里查找的关键字 td, 远程仓库为 conan-hosted
    # “*”为通配符
    conan search "*td*" -r=conan-hosted
    

    在这里插入图片描述

  5. 删除本地构建缓存

    • -c 不确认,直接删除
    • tdlib* 删除的包名,*为通配符,要删除指定版本: 包名/版本
    conan remove "tdlib*" -c
    

如何创建包

这里以cmake方式进行演示

创建一个包

需要提前创建一个空目录并进入

conan new cmake_lib -d name=包名 -d version=版本号

执行完上面的命令就会在当前目录下创建一个模板工程
在这里插入图片描述
下面是创建好的目录结构

├── CMakeLists.txt  源码
├── conanfile.py    conan配方描述
├── include         源码
│   └── my_package.h
├── src             源码
│   └── my_package.cpp
└── test_package    conan测试包,用于测试包的可用性(可选)
    ├── CMakeLists.txt
    ├── conanfile.py
    └── src
        └── example.cpp
源码

可以自定义不用按照生成的模板结构来,只要保证是cmake工程就行

conanfile.py

这个很重要,这个是告诉conan如何构建当前包的配置文件

from os.path import join

from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout
from conan.tools.env import VirtualBuildEnv
from conan.tools.files import apply_conandata_patches, copy, export_conandata_patches, get, replace_in_file, rmdir


# 类名这个可以随意更改
class my_packageRecipe(ConanFile):
    # 包名这个需要保证全小写
    name = "my_package"
    # 版本号(这个可以删除,然后在构建的时候--version传进去)
    version = "1.0"
    # 包类型(可选)
    # application:包是一个应用程序。
    # library:包是一个通用库。
    # 更多请参考 https://docs.conan.io/2/reference/conanfile/attributes.html#package-type
    package_type = "library"
    # 元数据信息(可选)
    license = "<Put the package license here>"
    author = "<Put your name here> <And your email here>"
    url = "<Package recipe repository url here, for issues about the package>"
    description = "<Description of my_package package here>"
    topics = ("<Put some tag here>", "<here>", "<and here>")
    # settings里面的配置是全局配置
    # 通常是通过profile进行配置,保存系统环境信息
    settings = "os", "compiler", "build_type", "arch"
    # options 当前包的配置(非全局)
    # shared 这个选项是必须配置的,其它选项可以自由添加
    # 结构为 "选项名": [可选值...], 可选值有个特殊的值 "ANY" 表示任意值
    options = {"shared": [True, False], "fPIC": [True, False]}
    # default_options 配置options的默认值
    # 这里也能设置依赖包的配置值,可以使用*来表示通配符
    # "包名/版本:配置名": 配置值
    default_options = {"shared": False, "fPIC": True, "openssl/*:shared": False}
    # 这里是需要导出的资源文件,会一并保存到配方压缩包中
    # 当你只需要导出 conanfile.yml、conandata.yml、conanfile.txt时可以省略
    exports_sources = "CMakeLists.txt", "src/*", "include/*"

    # config_options 方法用于在为包中的可用选项分配值之前对其进行配置或约束。典型的用例是删除给定平台中的选项。例如fPIC标志在Windows中不存在,因此应在此方法中将其删除
    def config_options(self):
        if self.settings.os == "Windows":
            self.options.rm_safe("fPIC")

    # configure 方法应用于配方中的settings和options,以便稍后在generate()、build()或package()方法在构建依赖图并扩展包依赖项的同时执行。
    # 这意味着当该方法执行时,依赖项仍然不存在,它们不存在,并且无法访问self.dependencies
    def configure(self):
        if self.options.shared:
            self.options.rm_safe("fPIC")
        self.settings.rm_safe("compiler.libcxx")

    # 在 layout()方法中,您可以调整 self.folders 和 self.cpp
    # 详细用法请参考 https://docs.conan.io/2/reference/conanfile/methods/layout.html
    # 这里直接使用cmake_layout加载cmake项目布局,如果CMakeList.txt文件和conanfile.py不在同一级,你需要传入src_folder(默认当前目录)指向其所在的目录
    def layout(self):
        cmake_layout(self, src_folder=".")

    # requirements()方法用于指定包的依赖关系。
    # self.requires(依赖坐标): 用于添加依赖
    # 依赖坐标写法:
    # 	指定特定版本: 依赖名/版本
    # 	匹配任意版本: 依赖名/[*]
    # headers: 依赖关系头文件将位于主机上下文中。
    # lib: 对于直接共享库和静态库,此特征通常为 True,但对于通过共享库使用的间接静态库,此特征可能为 False。
    # options: 依赖包的options配置
    # force: 这个 requires 将强制其版本位于上游依赖关系图中,覆盖其他现有版本,甚至是传递依赖关系,并解决潜在的现有冲突。下游消费者的force特征始终具有更高的优先级。
    # override: 与 force 特征相同,但不添加 direct 依赖项。如果没有可覆盖的传递依赖项,则此 require 将被丢弃。
    #           此特征仅在定义 requires 时存在,但一旦关系图被完全评估,它就不会作为实际的 requires 存在
    # 完整说明:https://docs.conan.io/2/reference/conanfile/methods/requirements.html
    def requirements(self):
        self.requires("jemalloc/[*]", headers=True, libs=True, options={"shared": True})

    # source() 方法可用于检索必要的源代码以从源代码构建包,并在必要时对此类源代码应用补丁。
    # 当从源代码构建包时,它将被调用,例如 conan create 或 conan install  --build=pkg*,但如果正在使用包预编译的二进制文件,则不会调用它。
    # 这意味着如果存在预编译的二进制文件,则不会下载源代码。
    # get:通过http链接下载源码到源码目录, strip_root=True时,会自动解压下载的源码压缩的第一级目录下的所有文件到源码目录
    # apply_conandata_patches:对下载的源码根据conandata.yml的配置打对应版本的补丁
    def source(self):
        get(self, **self.conan_data["sources"][self.version], strip_root=True)
        apply_conandata_patches(self)

    # 相当于 exports_sources 属性,但采用方法形式。
    # 此方法将在 export 时间调用,这发生在 conan export 和 conan create 命令中,其目的是允许将文件从用户文件夹复制到 Conan 缓存文件夹,这些文件成为配方源的一部分。
    # 这些源将与配方一起上传到服务器,但通常不会下载,除非从源构建包。
    def export_sources(self):
        # 导出conandata.yml中定义的补丁文件
        export_conandata_patches(self)
        # 复制LICENSE.md文件到导出目录
        copy(self, "LICENSE.md", self.recipe_folder, self.export_sources_folder)

    # generate 方法将在依赖图的计算和安装之后运行。这意味着它将在 conan install 命令之后运行,或者当在缓存中构建包时,它将在调用 build() 方法之前运行。
    def generate(self):
        # CMakeDeps生成器为每个依赖项生成必要的文件,以便能够使用cmake的find_package() 函数来查找依赖项。
        deps = CMakeDeps(self)
        deps.generate()
        # 覆盖构建环境中已设置的环境变量的值
        buildenv = VirtualBuildEnv(self)
        buildenv.environment().define("MY_BUILD_VAR", "MY_BUILDVAR_VALUE_OVERRIDDEN")
        buildenv.generate()
        # CMakeToolchain是CMake 的工具链生成器。它生成的工具链文件可用于 CMake 的命令行调用-DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake。
        # 此生成器将当前的包配置、设置和选项转换为 CMake 工具链语法。
        tc = CMakeToolchain(self)
        # 应用上面设置的环境变量
        tc.presets_build_environment = buildenv.environment()
        # 与 variables 不同,这些变量是单一配置的。
        # 它们将存储在CMakePresets.json文件中(在configurePreset 中的cacheVariables 处),并在使用CMake() 构建助手调用cmake.configure 时与-D 参数一起应用。
        # 分配给cache_variable的布尔值将转换为CMake中的(True)ON,(False)OFF符号。
        tc.cache_variables["foo"] = True
        # 分配给变量的布尔值将转换为CMake中的(True)ON,(False)OFF符号。
        # 将生成句子:set(FOO ON ...) 和 set(VAR OFF ...)。
        tc.variables["MYVAR"] = "MYVAR_VALUE"
        # 此属性允许为多个配置(调试、发布等)定义编译器预处理器定义。
        tc.preprocessor_definitions["MYDEFINE"] = "MYDEF_VALUE"
        tc.generate()

    # build() 方法用于定义从包的源代码构建。实际上,这意味着调用一些构建系统,这可以显式完成或使用 Conan 提供的任何构建助手:
    def build(self):
        # 在conanfile.py中,只能使用self.output来输出日志
        self.output.info("starting build....")
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    # package() 方法负责将文件从 source_folder 和临时 build_folder 复制到 package_folder,
    # 仅复制这些文件和工件这将成为最终包的一部分,如标头、编译器静态和共享库、可执行文件、许可证文件等。
    def package(self):
        cmake = CMake(self)
        cmake.install()
        # copying headers from source_folder
        copy(self, "*.h", join(self.source_folder, "include"), join(self.package_folder, "include"))
        # copying compiled .lib from build folder
        copy(self, "*.lib", self.build_folder, join(self.package_folder, "lib"), keep_path=False)

    # package_info() 方法负责向包的消费者定义信息,因此消费者可以轻松自动地消费这个包。
    # 消费者的generate()方法就是这个地方其中package_info()中定义的信息将映射到使用者的特定构建系统。
    # 然后,如果我们希望不同的构建系统使用一个包(就像社区的 ConanCenter 食谱一样),那么此信息的完整性非常重要。
    def package_info(self):
        # 对应CMake中的find_pkg(MyPackage REQUIRED)
        self.cpp_info.set_property("cmake_file_name", "MyPackage")
        # 对应CMake中的pkg_check_modules(my_package REQUIRED my_package)
        self.cpp_info.set_property("pkg_config_name", "my_package")
        # 消费者应链接的已编译库(包含在包中)的有序列表。默认为空。
        self.cpp_info.libs = ["my_package"]
        # 消费者应链接的系统库的有序列表(不包含在包中)。默认为空。
        self.cpp_info.system_libs = []
        # 可以找到标头的目录的相对路径列表(从包根目录开始)。默认情况下它被初始化为['include'],并且很少改变。
        self.cpp_info.includedirs = ['include']
        # 在其中查找库对象二进制文件(*.lib、*.a、*.so、*.dylib)的目录的相对路径列表(从包根目录开始)。默认情况下它被初始化为['lib'],并且很少改变。
        self.cpp_info.libdirs = ['lib']
        # 在其中查找库运行时二进制文件(如可执行 Windows .dll)的目录的相对路径列表(从包根目录开始)。默认情况下它被初始化为['bin'],并且很少改变。
        self.cpp_info.bindirs = ['bin']
        # components:字典,以名称作为键,以组件对象作为值来建模包可能具有的不同组件:库、可执行文件……
        self.cpp_info.components["crypto"].set_property("cmake_file_name", "Crypto")
        self.cpp_info.components["crypto"].libs = ["libcrypto"]
        self.cpp_info.components["crypto"].defines = ["DEFINE_CRYPTO=1"]
        # requires 此包(及其使用者)应链接的需求中的组件的实验列表。它将被添加对组件功能的支持的生成器使用。
        self.cpp_info.components["crypto"].requires = ["zlib::zlib"]
        self.cpp_info.components["ssl"].set_property("cmake_file_name", "SSL")
        self.cpp_info.components["ssl"].includedirs = ["include/headers_ssl"]
        self.cpp_info.components["ssl"].libs = ["libssl"]
        self.cpp_info.components["ssl"].requires = ["crypto", "boost::headers"]
        # buildenv_info和runenv_info之间的区别,前者是在 Conan 从源代码构建某些东西时应用的,就像在build()方法中一样,而后者将在“主机”上下文中执行需要激活运行时的东西时使用。
        # 没有必要添加bindirs到PATH环境变量中,这将由消费者VirtualBuildEnv和VirtualRunEnv生成器自动完成。
        # 同样,也没有必要向环境变量添加includedirs,libdirs或任何其他目录,因为此信息通常由其他生成器管理。
        self.buildenv_info.define("MYVAR", "1")
        self.buildenv_info.prepend_path("MYPATH", "my/path")
        if self.settings.os == "Android":
            arch = "myarmarch" if self.settings.arch == "armv8" else "otherarch"
            self.buildenv_info.append("MY_ANDROID_ARCH", f"android-{arch}")
        self.runenv_info.append_path("MYRUNPATH", "my/run/path")
        if self.settings.os == "Windows":
            self.runenv_info.define_path("MYPKGHOME", "my/home")
conandata.yml

常见结构

# 源码
sources:
  # 源码版本号
  "1.2.18":
    # 源码压缩包下载地址
    url: "https://github.com/Yellow-Camper/libevhtp/archive/refs/tags/1.2.18.tar.gz"
    # 源码压缩包sha256校验值(可大写)
    sha256: "316ede0d672be3ae6fe489d4ac1c8c53a1db7d4fe05edaff3c7c853933e02795"
# 补丁
patches:
  # 补丁对应的源码版本号
  "1.2.18":
  	# 补丁文件相对路径
    - patch_file: patches/fix-cmake-1.2.18.path

官方配方仓库

你可以在查看到官方已经适配的所有包配方
https://github.com/conan-io/conan-center-index/tree/master/recipes

cmake-conan

cmake-conan是conan官方提供的与cmake项目集成的插件
https://github.com/conan-io/cmake-conan

如何使用

  1. 进入上面的项目地址,下载 conan_provider.cmake
  2. 将其放入到你的项目中与CMakeLists.txt平级的目录下
  3. 添加CMake参数
    -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=conan_provider.cmake
    
  4. 重新加载项目即可
  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值