Conan 是一个开源的、跨平台的、去中心化的 C++ 包管理器。通过它可以安装、解决构建依赖,更重要的是可以直接集成到 Build System 中使用。同时它也允许你搭建自己的私有仓库,供私有项目使用。具体到细节,当向 Conan 请求安装依赖时,Conan 会拿着编译相关的配置信息去服务器请求是否有对应平台的预构建二进制包,如果有,则直接下载并解压到本地的缓存仓库中,否则,会执行对应的构建脚本,构建出符合当前平台的二进制包。
Conan 基于 Python 编写,故需要在开始前安装好 Python3。然后使用标准的 pip 安装即可
pip install conan
在Linux下Conan 会在第一次启动时自动配置好默认的 Profile 和 Remote 设置。它的配置以及本地的二进制仓库均存储在用户目录下~/.conan/中。
Profile 则存储在profiles文件夹中,用于设定各种编译环境和选项。默认会创建一个名为 default 的 Profile
Conan 使用这样的格式来描述一个软件包:名称/版本@用户/渠道。其中渠道(Channel)用来描述是稳定版(Stable)还是测试版(Testing)等信息
boost/1.64.0@conan/stable
boost/1.65.1@conan/stable
boost/1.66.0@conan/stable
在conan安装路径下,存在一个本地缓存,在编译的时候首先会先在缓存中进行查找,当缓存中不存在的时候,再去源端下载并编译二进制代码。
用户目录的软件包仓库被称为本地缓存(Local Cache);那么同样的,服务器上也有一个软件包的仓库,文档中称为远端(Remote)
其中,目录结构为:
drwxr-xr-x 1 root root 4096 Aug 27 16:18 ./
drwx------ 1 root root 4096 Aug 27 16:18 ../
-rw-r--r-- 1 root root 12288 Aug 10 18:44 .conan.db
-rw-r--r-- 1 root root 0 Aug 10 18:44 artifacts.properties
-rw-r--r-- 1 root root 351649 Aug 10 18:44 cacert.pem
-rw-r--r-- 1 root root 1002 Aug 10 18:44 conan.conf
-rw-r--r-- 1 root root 185 Aug 10 18:44 config_install.json
drwxrwxr-x 13 1007 1007 4096 Aug 27 15:31 data/
drwxr-xr-x 2 root root 4096 Aug 27 15:28 hooks/
drwxr-xr-x 2 root root 4096 Aug 10 18:44 profiles/
-rw-r--r-- 1 root root 303 Aug 10 18:44 remotes.json
-rw-r--r-- 1 root root 5979 Aug 10 18:44 settings.yml
-rw-r--r-- 1 root root 6 Aug 10 18:44 version.txt
通过Conan help来查找
conan使用类似cmake的方式,通过conanfile.txt来描述工程相关的依赖和相关的文件,或者可以直接通过conanfile.py来控制,在通过conanfile.txt过程中,编写的方式为:
[requires]//依赖
Poco/1.7.8p3@pocoproject/stable
[generators]//构建工具
cmake
如果有包 A 依赖包 C 的 1.0 版本,包 B 依赖包 C 的 1.2 版本,此时就会出现冲突。通过手动在 Requires 中写入C/1.2@xxx/yyy这样的依赖可以强制提升 C 的版本号为最新
project(FoundationTimer)
cmake_minimum_required(VERSION 2.8.12)
add_definitions("-std=c++11")
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
add_executable(timer timer.cpp)
target_link_libraries(timer ${CONAN_LIBS})
conanfile.py,其中conanfile.py用来描述构建软件包的编译打包过程,默认的,Conan 以lib、include、bin等文件夹标识头文件库文件目录,也可以在package_info函数中进行修改。此外,Conan 提供了一系列的驱动包装函数来执行各种第三方工具,以及定制版本号规则、设定依赖等等。
from conans import ConanFile, CMake
from distutils.dir_util import copy_tree
class BgfxConan(ConanFile):
name = "bgfx"
version = "20190604.018bbc4" # 这个地方我乱填的,请遵照SemVer的规范制定版本号
description = "Conan package for bgfx."
url = "https://github.com/9chu/bgfx-conan"
license = "BSD"
settings = "arch", "build_type", "compiler", "os" # 这些选项会被作为包的标识,区分不同的ABI
generators = "cmake"
options = {"shared": [True, False]}
default_options = "shared=False"
def source(self):
self.run("git clone https://github.com/JoshuaBrookover/bgfx.cmake")
copy_tree("bgfx.cmake", ".")
self.run("git reset --hard 018bbc4")
self.run("git submodule update --init --recursive")
def build(self):
cmake = CMake(self)
shared_options = "-DBUILD_SHARED_LIBS=ON" if self.options.shared else "-DBUILD_SHARED_LIBS=OFF"
fixed_options = "-DBGFX_BUILD_EXAMPLES=OFF"
tool_options = "-DBGFX_BUILD_TOOLS=OFF" if self.settings.os == "Emscripten" else ""
opengl_version = "-DBGFX_OPENGL_VERSION=33"
self.run("cmake %s %s %s %s %s" % (cmake.command_line, shared_options, fixed_options, tool_options, opengl_version))
self.run("cmake --build . %s -j8" % cmake.build_config)
def collect_headers(self, include_folder):
self.copy("*.h" , dst="include", src=include_folder)
self.copy("*.hpp", dst="include", src=include_folder)
self.copy("*.inl", dst="include", src=include_folder)
def package(self):
self.collect_headers("bgfx/include")
self.collect_headers("bimg/include")
self.collect_headers("bx/include" )
self.copy("*.a" , dst="lib", keep_path=False)
self.copy("*.so" , dst="lib", keep_path=False)
self.copy("*.lib", dst="lib", keep_path=False)
self.copy("*.dll", dst="bin", keep_path=False)
def package_info(self):
self.cpp_info.libs = ["bgfxd", "bimgd", "bxd"] if self.settings.build_type == "Debug" else ["bgfx", "bimg", "bx"]
self.cpp_info.libs.extend(["astc-codec", "astc", "edtaa3", "etc1", "etc2", "iqa", "squish", "nvtt", "pvrtc"])
if self.settings.os == "Macos":
self.cpp_info.exelinkflags = ["-framework Cocoa", "-framework QuartzCore", "-framework OpenGL", "-weak_framework Metal"]
if self.settings.os == "Linux":
self.cpp_info.libs.extend(["GL", "X11", "pthread", "dl"])
整个脚本分为若干个函数。其中,source函数,用于源代码拉取和准备,比如对源码进行一些修改;build函数,调用 CMake 进行构建;package函数,用于执行打包操作;package_info则用于输出构建相关的信息,比如需要链接包中的哪些库文件
cmake_minimum_required(VERSION 3.1)
project(test CXX)
######################################## conan package manager ########################################
# Download automatically, you can also just copy the conan.cmake file
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://github.com/conan-io/cmake-conan/raw/v0.14/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake")
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
######################################## dependencies ########################################
conan_cmake_run(
REQUIRES
bgfx/20190604.018bbc4@9chu/stable
BASIC_SETUP CMAKE_TARGETS
BUILD missing)
######################################## compiler flags ########################################
set(CMAKE_CXX_STANDARD 11)
if(MSVC)
add_definitions(-D_WIN32_WINNT=0x0600 -D_GNU_SOURCE -D_CRT_SECURE_NO_WARNINGS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wextra -Wno-implicit-fallthrough")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Wextra -Wno-implicit-fallthrough")
endif()
######################################## targets ########################################
file(GLOB_RECURSE TEST_SRC ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
add_executable(test ${TEST_SRC})
target_include_directories(test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(test CONAN_PKG::bgfx)