Conan C++ 包管理器
conan
Getting started
背景介绍
Conan是一个分散的包管理器,具有客户端 - 服务器架构。这意味着客户端可以从不同的服务器(“远程”)获取软件包以及上传软件包,类似于git远程控制器的“git”推拉模型。
在较高的层面上,服务器只是包存储。他们不构建也不创建包。这些包由客户端创建,如果二进制文件是从源构建的,则该编译也由客户端应用程序完成。
JFrog Artifactory
- JFrog Artifactory提供柯南存储库; 所以它也可以用作本地服务器。它是一个功能更强大的解决方案,具有WebUI,多种身份验证协议,高可用性等。它还具有云产品,允许您拥有私有包而无需任何本地基础结构。
JFrog Bintray
- JFrog Bintray为OSS Conan软件包提供公共和免费托管服务。用户可以在他们的帐户和组织下创建自己的存储库,并在那里免费上传Conan包,无需审核。但是,您应该考虑到这些软件包是公开的,因此它们必须符合相应的许可证,特别是如果软件包包含第三方代码。只是从Bintray阅读或检索柯南包,不需要帐户,只需要一个帐户来上传包。除此之外,Bintray还提供了一个名为conan -center的*存储库,该存储库经过审核,并且在被接受之前会对包进行审核以确保质量。
柯南最强大的功能之一是它可以管理包的预编译二进制文件。要定义由其名称,版本,用户和通道引用的包,需要包装配方。这样的包配方是一个conanfile.py python脚本,它定义了如何从源构建包,最终的二进制工件是什么,包依赖性等。
当在Conan客户端中使用包装配方,并且从源构建“二进制包”时,该二进制包将与特定设置兼容,例如为其创建的OS,编译器和编译器版本或计算机。建筑。如果从相同的源再次构建包但具有不同的设置(例如,对于不同的体系结构),将生成新的不同二进制文件。顺便说一下,“二进制包”是引号,因为严格来说,它不一定是二进制。例如,仅标头库将仅包含“二进制包”中的标头。
从包装配方生成的所有二进制包都是相干地管理和存储的。将它们上传到遥控器后,它们会保持连接状态。此外,不同的客户端从相同的软件包配方构建二进制文件(如不同操作系统中的CI构建从属服务器),将在同一软件包名称下将其二进制文件上载到远程服务器。
包消费者(安装现有包以在其项目中重用的客户端应用程序用户)通常将检索其系统的预编译二进制文件,以防存在这样的兼容二进制文件。否则,将从客户端计算机上的源构建这些包以创建与其设置匹配的二进制包。
conan 安装
pip install conan
- 1
如果安装有问题可以参考官网文档解决(https://docs.conan.io/en/latest/installation.html)。
简单实用例子(如何安装conan的依赖)
官方网站提供了一个简单例子。这里梳理下流程(https://docs.conan.io/en/latest/getting_started.html)。
我们建立一个简单的项目,项目需要引用md5库。md5库我们通过conan进行下载安装。
官网提供示例项目程序:
git clone https://github.com/conan-community/poco-md5-example.git
- 1
git clone下载示例项目。md5.cpp代码如下:
#include "Poco/MD5Engine.h"
#include "Poco/DigestStream.h"
#include <iostream>
int main(int argc, char** argv)
{
Poco::MD5Engine md5;
Poco::DigestOutputStream ds(md5);
ds << “abcdefghijklmnopqrstuvwxyz”;
ds.close();
std::cout << Poco::DigestEngine::digestToHex(md5.digest()) << std::endl;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
我们下载的项目依赖md5库。我们通过conan下载。
-- 搜索依赖的库。在conan服务器上。
conan search Poco* --remote=conan-center
Existing package recipes:
Poco/aaa@qq.com/stable
Poco/aaa@qq.com/stable
Poco/aaa@qq.com/stable
Poco/aaa@qq.com/stable
Poco/aaa@qq.com/stable
Poco/aaa@qq.com/stable
Poco/aaa@qq.com/stable
Poco/aaa@qq.com/stable
– 查看库的信息
conan inspect Poco/aaa@qq.com/stable
…
name: Poco
version: 1.9.0
url: http://github.com/pocoproject/conan-poco
license: The Boost Software License 1.0
author: None
description: Modern, powerful open source C++ class libraries for building network- and internet-based applications that run on desktop, server, mobile and embedded systems.
generators: (‘cmake’, ‘txt’)
exports: None
exports_sources: (‘CMakeLists.txt’, ‘PocoMacros.cmake’)
short_paths: False
apply_env: True
build_policy: None
settings: (‘os’, ‘arch’, ‘compiler’, ‘build_type’)
options:
enable_apacheconnector: [True, False]
shared: [True, False]
default_options:
enable_apacheconnector: False
shared: False
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
创建 conanfile.txt (conanfile.txt 可以指出构建系统的要求和编译器)
可以指定需要那些库。编译需要那个。
[requires]
Poco/aaa@qq.com/stable
[generators]
cmake
- 1
- 2
- 3
- 4
- 5
Poco/aaa@qq.com/stable
Poco 包的名称,通常与项目/库相同
1.9.0是通常与打包的项目/库的版本匹配的版本
这可以是任何字符串; 它不必是数字,因此,例如,它可以指示这是“开发”还是“主”版本。包可以被覆盖,因此也可以定期重新生成“夜间”或“每周”等包。
pocoproject是此包版本的所有者
stable是渠道。通道提供了另一种方法,可以为同一个库提供不同的包变体,并可以互换使用它们。它们通常将包的成熟度表示为任意字符串,例如“稳定”或“测试”。
GCC编译器> = 5.1 会有兼容性问题。具体参考官网。这里不进行说明。
安装依赖
mkdir build && cd build
conan install ..
...
Requirements
OpenSSL/aaa@qq.com/stable from 'conan-center' - Downloaded
Poco/aaa@qq.com/stable from 'conan-center' - Cache
zlib/aaa@qq.com/stable from 'conan-center' - Downloaded
Packages
OpenSSL/aaa@qq.com/stable:606fdb601e335c2001bdf31d478826b644747077 - Download
Poco/aaa@qq.com/stable:09378ed7f51185386e9f04b212b79fe2d12d005c - Download
zlib/aaa@qq.com/stable:6cc50b139b9c3d27b3e9042d5f5372d327b3a9f7 - Download
zlib/aaa@qq.com/stable: Retrieving package 6cc50b139b9c3d27b3e9042d5f5372d327b3a9f7 from remote ‘conan-center’
…
Downloading conan_package.tgz
[] 99.8KB/99.8KB
…
zlib/aaa@qq.com/stable: Package installed 6cc50b139b9c3d27b3e9042d5f5372d327b3a9f7
OpenSSL/aaa@qq.com/stable: Retrieving package 606fdb601e335c2001bdf31d478826b644747077 from remote ‘conan-center’
…
Downloading conan_package.tgz
[] 5.5MB/5.5MB
…
OpenSSL/aaa@qq.com/stable: Package installed 606fdb601e335c2001bdf31d478826b644747077
Poco/aaa@qq.com/stable: Retrieving package 09378ed7f51185386e9f04b212b79fe2d12d005c from remote ‘conan-center’
…
Downloading conan_package.tgz
[==================================================] 11.5MB/11.5MB
…
Poco/aaa@qq.com/stable: Package installed 09378ed7f51185386e9f04b212b79fe2d12d005c
PROJECT: Generator cmake created conanbuildinfo.cmake
PROJECT: Generator txt created conanbuildinfo.txt
PROJECT: Generated conaninfo.txt
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
在build中会生成 conanbuildinfo.cmake。如果你的项目要引用conan的文件,你需要在你的项目CMakeLists.txt中包含conan生成的conanbuildinfo.cmake文件
cmake_minimum_required(VERSION 2.8.12)
project(MD5Encrypter)
add_definitions("-std=c++11")
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
add_executable(md5 md5.cpp)
target_link_libraries(md5 ${CONAN_LIBS})
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
现在我们准备构建并运行我们的Encrypter应用程序
(win)
$ cmake .. -G "Visual Studio 15 Win64"
$ cmake --build . --config Release
(linux, mac)
$ cmake … -G “Unix Makefiles” -DCMAKE_BUILD_TYPE=Release
$ cmake --build .
…
[100%] Built target md5
$ ./bin/md5
c3fcd3d76192e4007dfb496cca67e13b
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
conan安装依赖(扩展)
你的项目可能使用cmake或者makefile进行构建的。如果你使用conan install libxxx。相关libxxx会下载到conan缓存中(conan 缓存路径下 /home/gpadmin/.conan/ ) 有时候libxxx并没有拷贝到 /usr/local/ 下。如果你想使用必须引用缓存中的路径。但是路径都是绝对路径。随便引用可能出问题。conan文档介绍解决问题几种方法。
● cmake
● make
更多编译请参考官网:https://docs.conan.io/en/latest/integrations.html
cmake 方式
如果您使用CMake构建项目,你需要创建conanbuildinfo.cmake。在CMakeList.txt中引用这个文件。这个文件可以通过conan install 命令进行创建。在使用这个命令之前你需要创建conanfile.txt 文件指定你的编译器是什么。
创建conanfile.txt
...
[requires]
liboss2/aaa@qq.com/testing
[generators]
cmake
- 1
- 2
- 3
- 4
- 5
conan install 创建 conanbuildinfo.cmake
conan install .
- 1
创建的conanbuildinfo.cmake 里面定义了你依赖的库信息
conanbuildinfo.cmake 内容
...
include(CMakeParseArguments)
set(CONAN_LIBOSS2_ROOT "/home/gpadmin/.conan/data/liboss2/master/hashdata/testing/package/de9c231f84c85def9df09875e1785a1319fa8cb6")
set(CONAN_INCLUDE_DIRS_LIBOSS2 "/home/gpadmin/.conan/data/liboss2/master/hashdata/testing/package/de9c231f84c85def9df09875e1785a1319fa8cb6/include")
set(CONAN_LIB_DIRS_LIBOSS2 "/home/gpadmin/.conan/data/liboss2/master/hashdata/testing/package/de9c231f84c85def9df09875e1785a1319fa8cb6/lib")
set(CONAN_BIN_DIRS_LIBOSS2 )
set(CONAN_RES_DIRS_LIBOSS2 )
set(CONAN_BUILD_DIRS_LIBOSS2 "/home/gpadmin/.conan/data/liboss2/master/hashdata/testing/package/de9c231f84c85def9df09875e1785a1319fa8cb6/")
set(CONAN_LIBS_LIBOSS2 )
set(CONAN_DEFINES_LIBOSS2 )
# COMPILE_DEFINITIONS are equal to CONAN_DEFINES without -D, for targets
set(CONAN_COMPILE_DEFINITIONS_LIBOSS2 )
...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
在CMakeList.txt 中引用conanbuildinfo.cmake文件。在CMakeList.txt需要调用conan_basic_setup()宏,这个宏会帮你在CMakeList.txt中声明好你依赖的路径。
IF(EXISTS ${CMAKE_SOURCE_DIR}/conanbuildinfo.cmake)
INCLUDE(${CMAKE_SOURCE_DIR}/conanbuildinfo.cmake)
CONAN_BASIC_SETUP()
ENDIF()
- 1
- 2
- 3
- 4
现在在CMakeList.txt中已经声明了你依赖的库的路径,头文件路径等信息。你需要自己手动去将这些导入到CMakeList.txt里。
这里我使用的 find_package 方法导入依赖lib。具体find_package用法参考(https://blog.csdn.net/haluoluo211/article/details/80559341)
conan cmake 依赖官方文档:https://docs.conan.io/en/latest/integrations.html
make 方式
跟cmake方法相似。首先你需要创建conanfile.txt 指定你编译器是那个
conanfile.txt
[requires]
liboss2/aaa@qq.com/testing
[generators]
make
- 1
- 2
- 3
- 4
makefile 是通过conanbuildinfo.mak 文件获取依赖信息。执行conan install 创建conanbuildinfo.mak
conan install .
- 1
生成conanbuildinfo.mak后你需要修改你本地Makefile。conan文档里提供了修改模版
include conanbuildinfo.mak
#----------------------------------------
Make variables for a sample App
#----------------------------------------
CXX_SRCS =
main.cpp
CXX_OBJ_FILES =
main.o
EXE_FILENAME =
main
#----------------------------------------
Prepare flags from variables
#----------------------------------------
CFLAGS += $(CONAN_CFLAGS)
CXXFLAGS += $(CONAN_CPPFLAGS)
CPPFLAGS += $(addprefix -I, $(CONAN_INCLUDE_PATHS))
CPPFLAGS += $(addprefix -D, $(CONAN_DEFINES))
LDFLAGS += $(addprefix -L, $(CONAN_LIB_PATHS))
LDLIBS += $(addprefix -l, $(CONAN_LIBS))
#----------------------------------------
Make Commands
#----------------------------------------
COMPILE_CXX_COMMAND ?=
g++ -c $(CPPFLAGS) $(CXXFLAGS) $< -o aaa@qq.com
CREATE_EXE_COMMAND ?=
g++ $(CXX_OBJ_FILES)
$(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
-o $(EXE_FILENAME)
#----------------------------------------
Make Rules
#----------------------------------------
.PHONY : exe
exe : $(EXE_FILENAME)
$(EXE_FILENAME) : $(CXX_OBJ_FILES)
$(CREATE_EXE_COMMAND)
%.o : $(CXX_SRCS)
$(COMPILE_CXX_COMMAND)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
修改好模版。你就可以编译你的项目了。
conan 关于make文档参考:https://docs.conan.io/en/latest/integrations/make.html
打包项目
打包项目过程和原理
对于包创建者和Conan用户来说,了解在conan本地缓存中创建包的流程以及所有关于其布局的流程非常有用。
每个包装配方包含本地缓存中的五个重要文件夹:
- export:存储包装配方的文件夹。
- export_source:exports_sources存储使用recipe 属性复制的代码的文件夹。
- source:存储源代码构建源代码的文件夹。
- build:完成源的实际编译的文件夹。每个不同的二进制配置通常会有一个子文件夹
- package:存储最终包工件的文件夹。每个不同的二进制配置将有一个子文件夹
该源和建立文件夹,只有当包已经从源代码构建的存在。
通过conan export命令或更典型地使用conan create命令“导出”包时,该过程开始。该字段指定的conanfile.py和文件 exports_sources将从用户空间复制到本地缓存。
将export和export_source文件复制到源文件夹,然后source() 执行该方法(如果存在)。请注意,所有二进制包只有一个源文件夹。如果在生成代码时,有不同配置的源代码,则无法使用该source()方法生成,而是需要使用该build()方法生成 。
然后,对于每个不同的设置和选项配置,将为此配置以SHA-1哈希的形式计算包ID。源将被复制到build / hashXXX文件夹,并将build()触发该方法。
之后,package()将调用该方法将构件/ hashXXX 文件夹中的工件复制到package / hashXXX文件夹。
最后,package_info()所有依赖的方法将被调用,聚集这样你就可以产生对消费者构建系统文件,作为conanbuildinfo.cmake的cmake 编译器。此imports功能还会将本地缓存中的工件复制到用户空间(如果已指定)。
简单打包方法
让我们为包装配方创建一个文件夹,并使用conan new命令为我们创建一个模版:
$ mkdir mypkg && cd mypkg
$ conan new Hello/0.1 -t
- 1
- 2
会给我们生成以下文件
conanfile.py
test_package
CMakeLists.txt
conanfile.py
example.cpp
- 1
- 2
- 3
- 4
- 5
conanfile.py 中定义了如何打包如何导入源文件。以及项目具体信息。具体conanfile.py里面方法参考:https://docs.conan.io/en/latest/reference/conanfile.html#conanfile-reference
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/memsharded/hello.git")
self.run("cd hello && git checkout static_shared")
# 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"]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
build 是你要具体如何编译项目
source source方法表示导入源文件。但是是为git方式来使用的。例子中会去git上下载源文件导入到conan的缓存中
package 打包你的项目。注意python文件中的 copy 函数,里面的dst是拷贝到conan的package下面。并不能随意的指定路径。
test_package 文件夹里面是“包”测试,你可以在example.cpp中写测试,并验证包是否正确创建,你可以在里面写一些测试case测试你的包是否好使。
test_package 具体参考:https://docs.conan.io/en/latest/creating_packages/getting_started.html#creating-the-package-recipe
执行conan create . demo/testing 创建并打包你的包
conan create . demo/testing
- 1
在柯南创建命令执行以下操作:
- 将conanfile.py从用户文件夹复制(以conan术语“导出”)到conan的本地缓存中。
- 安装包,强制从源构建它。
- 移动到test_package文件夹并创建临时构建文件夹。
- 执行conan install …,以安装test_package / conanfile.py的要求 。请注意,它将从源构建“Hello”。
- 构建并启动示例消费应用程序,分别调用test_package / conanfile.py build()和test()方法。
使用Conan命令,conan create命令将等效于:
$ conan export . demo/testing
$ conan install Hello/aaa@qq.com/testing --build=Hello
# package is created now, use test to test it
$ conan test test_package Hello/aaa@qq.com/testing
- 1
- 2
- 3
- 4
打包项目(扩展)
有些项目并不是第三方开发。是自己开发的。这种就不能通过source导入你的项目。可以通过exports_sources 方法将你的源代码导入到conan的缓存中。
以下是conanfile.py的示例。删除掉source方法。增加exports_sources 表示你的源代码路径。conan在执行conanfile.py时将你的源代码导入到conan的缓存 export_source路径下面。
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()
cmake.install()
# 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):
pass
def package_info(self):
self.cpp_info.libs = ["hello"]
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
-
添加了该exports_sources字段,指示柯南将本地src 文件夹中的所有文件复制到包装配方中。
-
删除了该source()方法,因为不再需要检索外部源。
同时你需要注意你的CMakeList文件是否引用了相关依赖库,如果引用你需要加入conanbuildinfo.cmake到你的CMakeList文件。
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()打包项目-直接打包编译好的项目
直接打包项目。不从源代码开始进行编译。
– 创建一个带有conanfile.py的文件
conan new gdal/aaa@qq.com/testing
– 直接打包文件到conan package文件夹下 --force 如果已经有了直接覆盖
conan export-pkg . gdal/aaa@qq.com/testing -pf=/opt/gpsql --force参考:https://docs.conan.io/en/latest/creating_packages/existing_binaries.html
上一篇: Chrome插件离线安装方法及编程思路