安装 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
- 打开本地Repository创建页面
- 点击New开始创建
- 选择Conan类型
- 填写创建信息
5. 查看创建的Repository信息
6. 复制Repository地址
在 artifactory-cpp-ce创建用户并授权
artifactory-cpp-ce 支持完整的用户权限管理,这里只演示简单的使用:创建一个用户并给这个用户分配我们刚刚创建的仓库权限。
-
进入用户管理界面
-
点击New进入创建页面
-
输入相关信息,点击Save创建
-
进入创建权限页面
-
点击下面的按钮进入创建页面
-
输入权限名,添加Repository资源
-
添加构建权限
-
添加用户到该权限
-
设置用户详细权限并保存
配置本地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*"]
添加远程仓库
按下面的描述替换命令中的对应位置
- $REMOTE: 远程仓库名称(可以和创建时候的不一样)
- $URL: 我们创建的远程仓库地址
conan remote add $REMOTE $URL
验证远程仓库
- $REMOTE: 与上面相同
- $USER_NAME: 上面操作创建的用户
- $PASSWORD: 上面操作创建的用户的密码
conan remote login $REMOTE $USER_NAME -p $PASSWORD
初始化本地配置
conan profile detect
添加本地包
这里使用 https://github.com/manx98/conan-tdlib.git 作为示例,需要先提前clone下来仓库。
进入包的根目录下
-
构建包到本地缓存目录
conan create . --build=missing
-
推送包到远程仓库
- $RECIPE: 上面构建的包名,这里为 tdlib/1.8.25@user/chanel
- @和后面的内容可以可选的
- user:用户(可选,默认“_”)
- channel:信道(可选,默认“_”)
- $REMOTE: 需要推送到的远程仓库,这里与上面的配置相同
conan upload $RECIPE -r=$REMOTE
- $RECIPE: 上面构建的包名,这里为 tdlib/1.8.25@user/chanel
-
查看远程仓库列表
conan remote list
-
从指定仓库查找包
# 这里查找的关键字 td, 远程仓库为 conan-hosted # “*”为通配符 conan search "*td*" -r=conan-hosted
-
删除本地构建缓存
- -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
如何使用
- 进入上面的项目地址,下载 conan_provider.cmake
- 将其放入到你的项目中与CMakeLists.txt平级的目录下
- 添加CMake参数
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=conan_provider.cmake
- 重新加载项目即可