Khan's Notebook GCC/GNU/Linux Delphi/Window Java/Anywhere

路漫漫,长修远,我们不能没有钱

QtCreator中如何使用Conan包管理工具

要点

  • Conan本身是一个包管理工具, 类似Pyhon的pip, 本身用Python编写
  • QT 6.0 开始引入Conan插件, 从个人观察来看, 似乎该插件仅仅引入了cmake脚本文件
  • Conan本身不依赖QtCreator, 可以随意使用, 其他编译环境可以忽略掉本文章所有关于QT的内容, 其他不变



一 准备环境, 安装Conan

1.1 安装Python 3 及 pip3

 1     brew install curl
 2     brew install python3
 3     curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
 4     sudo python get-pip.py
 5 
 6     python3 -m pip install --upgrade pip
 7     python3 -m pip conan
 8 
 9     #对于QtCreator, 此步骤必须, 否则会找不到conan指令
10     ln -s /opt/homebrew/bin/conan /usr/local/bin 
11 
12     conan --version 
13     > Conan version 1.41.0


以上为OSX 环境安装步骤, 依赖brew, brew环境搭建见 链接

Windows 建议使用 官方MSI安装包安装, 并勾选 pip组件

linux建议使用apt-get yum pacman 之类的包管理工具安装



二 设置Qt Creator

  • Mac : 菜单 Qt Creator --> 关于插件, 在filter中输入conan, 勾选 Conan 插件
  • Win : 菜单 帮助 --> 关于插件, 在filter中输入conan, 勾选 Conan 插件



三 测试样例

  1. 创建Qt工程, 此处选择 Application (Qt Quick) --> Qt Quick Application -Empty, 构建方式选CMake
  2. 在工程根目录下创建 conanfile.txt, 录入:
  3. 1 [requires]
    2 picojson/1.3.0
    3 
    4 [generators]
    5 cmake

  1. 在工程根目录下执行 mkdir build && cd build && conan install .. && cd -
  2. 在CMakeLists.txt 输入:

  3.  1 # 手工修改 第一处
     2 ## 引入conan install产生的 cmake脚本
     3 include(${CMAKE_CURRENT_SOURCE_DIR}/build/conanbuildinfo.cmake)
     4 ## 引入脚本中创建的编译环境变量
     5 include_directories(${CONAN_INCLUDE_DIRS_PICOJSON})
     6 link_directories(${CONAN_LIB_DIRS_PICOJSON})
     7 
     8 find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Quick LinguistTools REQUIRED)
     9 find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Quick LinguistTools REQUIRED)
    10 
    11 # 手工修改第二处
    12 if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    13     qt_add_executable(RantionMidiCenter
    14         MANUAL_FINALIZATION
    15         ${PROJECT_SOURCES}
    16     )
    17     ## link conan引入的picojson静态库, 需要时使用
    18     target_link_libraries(main ${CONAN_LIBS_PICOJSON})
    19     
    20     qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
    21 else()
    22     if(ANDROID)
    23         add_library(RantionMidiCenter SHARED
    24             ${PROJECT_SOURCES}
    25         )
    26     else()
    27         add_executable(RantionMidiCenter
    28           ${PROJECT_SOURCES}
    29         )
    30     endif()
    31 
    32     ## link conan引入的picojson静态库, 需要时使用
    33     target_link_libraries(main ${CONAN_LIBS_PICOJSON})
    34 
    35     qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
    36 endif()
    37 
    38 
    39 ## CONAN_LIBS_PICOJSON 中的 `CONAN_LIBS_xxxx` 可以替换成引入的其他库名称
  1. main.cpp 头部输入:
1 #ifndef PICOJSON_USE_INT64
2    #define PICOJSON_USE_INT64
3    #include <picojson.h>
4 #endif

至此就可以随意使用picojson.h中的功能了

上述范例引入了一个 header only的工具库 picojson.h, 仅用于演示功能, 实际上CONAN_LIB_DIRS_PICOJSON  CONAN_LIBS_PICOJSON 变量在CmakeLists文件中的引入动作并无必要



四 2. 自建软件包


因为很多第三方开源项目没有 Conan 官方的支持,使用这些项目的时候就需要自己来编写 Receipe 来告诉 Conan 如何编译、打包第三方库了。


Conan打包过程

这里以bgfx为例来构造一个 Conan 的二进制包,并提交到我们自建的私仓中。

因为bgfx官方构建方式比较复杂,笔者选取了其 CMake 版本来执行构建。此外 Github 上已经有用户创建过对应的构建脚本了,因此这里可以直接参考别人的写法来进行构建。

使用 conan new Hello/0.1 -t 可以创建一个 HelloWorld 的空白 Receipe。可以看到呈现出这样的目录结构:

conanfile.py
test_package
  CMakeLists.txt
  conanfile.py
  example.cpp


其中conanfile.py用来描述构建软件包的编译打包过程,test_package存储一个测试用的样例,用来检查是否成功构建了软件包并且是否能正常使用。

以构建bgfx的脚本为例,修改conanfile.py

 1 from conans import ConanFile, CMake
 2 from distutils.dir_util import copy_tree
 3 
 4 class BgfxConan(ConanFile):
 5     name            = "bgfx"
 6     version         = "20190604.018bbc4"  # 这个地方我乱填的,请遵照SemVer的规范制定版本号
 7     description     = "Conan package for bgfx."
 8     url             = "https://github.com/9chu/bgfx-conan"
 9     license         = "BSD"
10     settings        = "arch""build_type""compiler""os"  # 这些选项会被作为包的标识,区分不同的ABI
11     generators      = "cmake"
12     options         = {"shared": [True, False]}
13     default_options = "shared=False"
14 
15     def source(self):
16         self.run("git clone https://github.com/JoshuaBrookover/bgfx.cmake")
17         copy_tree("bgfx.cmake"".")
18         self.run("git reset --hard 018bbc4")
19         self.run("git submodule update --init --recursive")
20 
21     def build(self):
22         cmake          = CMake(self)
23         shared_options = "-DBUILD_SHARED_LIBS=ON" if self.options.shared else "-DBUILD_SHARED_LIBS=OFF"
24         fixed_options  = "-DBGFX_BUILD_EXAMPLES=OFF"
25         tool_options   = "-DBGFX_BUILD_TOOLS=OFF" if self.settings.os == "Emscripten" else ""
26         opengl_version = "-DBGFX_OPENGL_VERSION=33"
27         self.run("cmake %s %s %s %s %s" % (cmake.command_line, shared_options, fixed_options, tool_options, opengl_version))
28         self.run("cmake --build . %s -j8" % cmake.build_config)
29 
30     def collect_headers(self, include_folder):
31         self.copy("*.h"  , dst="include", src=include_folder)
32         self.copy("*.hpp", dst="include", src=include_folder)
33         self.copy("*.inl", dst="include", src=include_folder)
34 
35     def package(self):
36         self.collect_headers("bgfx/include")
37         self.collect_headers("bimg/include")
38         self.collect_headers("bx/include"  )
39         self.copy("*.a"  , dst="lib", keep_path=False)
40         self.copy("*.so" , dst="lib", keep_path=False)
41         self.copy("*.lib", dst="lib", keep_path=False)
42         self.copy("*.dll", dst="bin", keep_path=False)
43 
44     def package_info(self):
45         self.cpp_info.libs = ["bgfxd""bimgd""bxd"if self.settings.build_type == "Debug" else ["bgfx""bimg""bx"]
46         self.cpp_info.libs.extend(["astc-codec""astc""edtaa3""etc1""etc2""iqa""squish""nvtt""pvrtc"])
47         if self.settings.os == "Macos":
48             self.cpp_info.exelinkflags = ["-framework Cocoa""-framework QuartzCore""-framework OpenGL""-weak_framework Metal"]
49         if self.settings.os == "Linux":
50             self.cpp_info.libs.extend(["GL""X11""pthread""dl"])


可以看到整个脚本分为若干个函数。其中:

  • source 函数,用于源代码拉取和准备,比如对源码进行一些修改;
  • build 函数,调用 CMake 进行构建;
  • package 函数,用于执行打包操作;
  • package_info 则用于输出构建相关的信息,比如需要链接包中的哪些库文件。

默认的,Conan 以libincludebin等文件夹标识头文件库文件目录,也可以在package_info函数中进行修改。此外,Conan 提供了一系列的驱动包装函数来执行各种第三方工具,以及定制版本号规则、设定依赖等等。具体可以通过查阅官方文档来进一步了解,本文仅作抛砖引玉的目的。

在构建完成后,Conan 会以 Settings  Options 的取值 Hash 后为软件包指定一个 package_id,因而不同的构建选项会对应到不同的 Id 上。最终拉取预编译包时就会以这个 Id 作为基准。因此,如果构建一个 Header-Only 的包,则可以去掉这些选项,这样在各个平台上都不需要额外构建即可使用了。

编写完 Receipe 后,就可以执行 Conan 来进行构建了。

conan install bgfx/20190604.018bbc4@9chu/stable --build=bgfx

构建完成后会自动执行test_package的内容进行测试。最后使用命令上传到我们的私仓:

conan upload bgfx/20190604.018bbc4@9chu/stable --all -r=my_local_server

然后,我们就能在 Artifactory 中看到我们提交的包了。


配合 CMake 实战

上传完自己制作的包,接下来就可以将其作为依赖引入自己的项目之中了。

在这里,推荐使用 Conan 官方提供的 CMake 脚本将其引入项目中。

 1 cmake_minimum_required(VERSION 3.1)
 2 project(test CXX)
 3 
 4 ######################################## conan package manager ########################################
 5 
 6 # Download automatically, you can also just copy the conan.cmake file
 7 if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
 8     message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
 9     file(DOWNLOAD "https://github.com/conan-io/cmake-conan/raw/v0.14/conan.cmake"
10         "${CMAKE_BINARY_DIR}/conan.cmake")
11 endif()
12 
13 include(${CMAKE_BINARY_DIR}/conan.cmake)
14 
15 ######################################## dependencies ########################################
16 
17 conan_cmake_run(
18     REQUIRES
19         bgfx/20190604.018bbc4@9chu/stable
20     BASIC_SETUP CMAKE_TARGETS
21     BUILD missing)
22 
23 ######################################## compiler flags ########################################
24 
25 set(CMAKE_CXX_STANDARD 11)
26 
27 if(MSVC)
28     add_definitions(-D_WIN32_WINNT=0x0600 -D_GNU_SOURCE -D_CRT_SECURE_NO_WARNINGS)
29     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8")
30     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /utf-8")
31 else()
32     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -Wall -Wextra -Wno-implicit-fallthrough")
33     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -Wall -Wextra -Wno-implicit-fallthrough")
34 endif()
35 
36 ######################################## targets ########################################
37 
38 file(GLOB_RECURSE TEST_SRC ${CMAKE_CURRENT_SOURCE_DIR}/include/*.hpp ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
39 
40 add_executable(test ${TEST_SRC})
41 target_include_directories(test PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
42 target_link_libraries(test CONAN_PKG::bgfx)


通过 conan_cmake_run 来直接指定依赖,这样就不需要写 conanfile.txt 并且会在 CMake 构建的时候自动把依赖安装上,集成到 CMake 中,非常的方便。

此外,由于使用了CMAKE_TARGETS模式,依赖的指定方法也变成了CONAN_PKG::bgfx的方式,这里可以根据需要自行调整。



附录1 Conan常用指令

# 在远程仓库搜索 picojson库, 包名支持通配符, 官方仓库为conancenter, conan-center已废弃
conan search picojson -r all
conan search picojson -r conancenter
conan search boost* -r conancenter

# 在本地缓存搜索 picojson库
conan search picojson 

# 查看picojson/1.3.0包的详细信息, picojson为包名, 1.3.0为版本号
conan inspect picojson/1.3.0

# 根据 ..目录的conanfile.txt文件, 下载依赖包
conan install ..

# 远端管理

## 查阅所有远程仓库配置

conan remote list

## 添加源
conan remote add my-repo http://my-repo.com/xxx

# 或者使用insert来将其作为首个源
conan remote update my-repo http://my-repo.com/xxx --insert=0


# 删除一个源
conan remote remove my-repo


附录2 自建仓库

Conan 官方提供了一个迷你的服务端来提供仓库的功能,同时也推荐使用Artifactory Community Edition for C/C++来自建仓库。当然,如果是为了开源项目,可以直接在 Bintray 上申请一个开源项目账号来上传自制软件包而无需自建仓库(但是实在是太慢了)。

本文使用 Artifactory 来自建仓库,因为功能相对完善。Artifactory 支持配置用户和组以及对应的权限,商业版本还支持高可用和分布式。

安装

sudo docker pull docker.bintray.io/jfrog/artifactory-cpp-ce
sudo docker run 
---restart=always \
    
--name artifactory \
    
-/data/artifactory:/var/opt/jfrog/artifactory \
    
-8081:8081 \
    
-e EXTRA_JAVA_OPTIONS='-Xms512m -Xmx2g -Xss256k -XX:+UseG1GC' \
    docker
.bintray.io/jfrog/artifactory-pro:latest


暴露在本机的8081端口上,同时挂载数据目录到/data/artifactory目录下

注意: Artifactory 默认会以 UserID 1030 运行服务,一定要注意宿主机的数据目录的权限是否满足要求,如果启动时出现 Permission Denied 错误,请修改目录权限:

sudo chown 1030:1030 /data/artifactory
sudo chmod 0755 /data/artifactory

你也可以使用--user 1234:4321的方式来指定 Docker 使用哪个用户/权限来执行容器。

配置

首次访问 http://localhost:8081 即可打开配置向导。默认的,配置好 Admin 账户的密码,初始化默认的 Conan 仓库配置即可。向导会提示你创建一个 HTTP Proxy,如果网络够好或者只作私仓使用则可以忽略该配置,否则,建议创建一个代理设置来加速访问 Remote 仓库。

Artifactory 提供了三种类型的 Conan 仓库供不同目的使用:

  • 本地仓库(Local):即当前 Artifactory 服务器上存储软件包的仓库;
  • 远端仓库(Remote):即第三方的软件仓库,在本服务器上作为 Proxy 和 Cache 运作;
  • 虚拟仓库(Virtual):作为一个索引中心,能将其他两类仓库整合到一个仓库名下,方便使用。

初始化之后,Artifactory 会创建好一个本地仓库,一个到 Conan Center 的远程仓库和包含上述两个仓库的虚拟仓库。

需要注意的是,默认配置下 Artifactory 是允许匿名访问的,必须在 Admin > Security Configuration 页面中关闭匿名访问才能真正作为私仓使用。

添加到 Conan

在仓库管理页面,点击虚拟仓库 Conan,在右上角点击 Set Me Up 按钮即可显示当前仓库如何在 Conan 中配置并作为一个源。

posted on 2021-10-19 16:09 Khan 阅读(1125) 评论(0)  编辑 收藏 引用 所属分类: GCC/G++跨平台开发


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


<2022年8月>
31123456
78910111213
14151617181920
21222324252627
28293031123
45678910

导航

统计

常用链接

留言簿(33)

随笔分类(225)

随笔档案(169)

相册

技术

友情链接

最新随笔

搜索

积分与排名

最新随笔

最新评论

阅读排行榜

评论排行榜