c++ 二进制类型_基于 Conan 的 C/C++ 持续交付流水线

关注世界领先 DevOps 平台 JFrog

背景

在当下软件应用的开发过程当中,单枪匹马或者小作坊式的模式已经很少见了,协作式的开发成为主流。相应的,应用的代码也不再是从零开始,而是基于或引用很多已有的、共享的模块,如各种开源的框架和共用库,或者协作团队中开发的自研库,这就是软件开发中常说的“依赖”。为了更好地管理这种依赖关系,各种开发语言都逐渐发展出了自己的依赖管理系统,如 Java 的 Maven、NodeJS 的 NPM、Python 的 Pypi 等。这些依赖管理系统的日渐完善和广泛应用,使得相应语言的应用开发更加简洁、高效,大大推动了软件应用的发展和普及。

然而相对的,作为软件开发重要组成部分的 C/C++ 语言,由于其编译型语言的特性,即应用最终要编译成为目标机器可直接执行的程序,使得 C/C++ 的依赖管理一直是一个众所周知的难题和痛点。这主要体现在:

  • 应用二进制接口不兼容。C/C++ 的依赖不仅仅体现在代码上,还包括操作系统、架构、编译器等环境配置上,为了确保一个共享库与其他库、整个应用的兼容性,必须通过各种配置来描述这些配置的依赖信息。

  • 编译构建慢。由于头文件和预处理机制,以及上面提到的兼容性,需要额外的机制来提升编译效率,才能保证只编译那些需要重新编译的代码。

  • 代码链接和内嵌。一个静态的 C/C++ 库能够被另一个库通过头文件包含的方式引用,而一个共享库也能嵌入另一个静态库。在两种情形中,当任何依赖变更时,都必须管理哪些库是需要重新构建的。

  • 生态系统的快速发展。针对不同平台、不同构建任务及应用场景的编译器、构建系统层出不穷,导致解决上述问题的工作量不断地增加。

当然,针对 C/C++ 的依赖管理,业界也开展了很多研究和实践工作,可惜大多数的效果并不理想。而本文将会介绍一种当前已逐步得到业界关注和认可,并得到大力推广的 C/C++ 依赖管理方案--Conan,以及如何基于 Conan、持续集成(CI)工具 Jenkins 和全语言制品库 Artifactory,实现 C/C++ 应用的持续交付流水线。

Conan--C/C++ 的包管理器

Conan 是一个开源项目(FOSS,Free Open Source Software),https://conan.io ,为 C/C++ 的依赖包管理构建了非中心化的管理架构,开发者可以像 Docker Registry 一样搭建自己专属的依赖包仓库。Conan 是跨平台的解决方案,同时兼容各种构建工具,以依赖包的二进制文件为基础来定义、管理依赖关系,使得依赖包的获取和消费更加符合目标环境和配置的特点,提升了整体编译的效率。Conan 是基于 Python 语言的,上手门槛较低,也易于扩展。在被 JFrog 收购之后,Conan 在保持开源特性的同时,还结合了 JFrog 产品在制品管理、DevOps 工具集成等方面的能力,为开发者提供了更为全面的支持。Conan 在当前 C/C++ 依赖管理领域已得到广泛关注和快速发展。

通常之前介绍的像 Maven 这样的依赖管理系统,都包含以下几个部分:

  • 依赖包仓库,用以存储需要引用的依赖包,即各种通用框架或共享模块;

  • 依赖访问协议,用以描述如何在依赖包仓库中定位、获取或上传共享模块;

  • 依赖描述语言,用以描述如何定义依赖关系,以及后台对依赖关系的自动解析;

  • 客户端,根据描述语言中的定义,遵照访问协议,从仓库中获取或上传相应的依赖包。

Conan 也在这几方面提供了成熟的解决方案:

  • 依赖包仓库

b3fa0218566c64288a2d5b464234d2a5.png

Conan 在 JFrog 的公网制品分发平台 JFrog Bintray 上搭建了公共的依赖包仓库 conan-center(https://conan.bintray.com),开发者可以直接在这里获取所需的各种公共依赖包。

同时,开发者还可以在本地搭建原生的 conan_server,或者直接利用 JFrog Artifactory 制品仓库,做为私有的依赖包仓库。

  • 依赖访问协议

1a9371e493305debcb5caf069a10686a.png

Conan 通过“/@/”的命名规则来定位一个依赖包,其中“/”(user/channel)定义了一个类似于命名空间(NameSpace)的机制,用于区分针对同一个共享库的不同实现。

每一个依赖包都分为 recipe 和 package 两个部分。 recipe 定义了依赖包的基本信息、依赖关系、构建方法等基本信息,package 则根据目标环境和配置,如操作系统、架构、编译器等(即 Conan 中的 setting)的不同,保存对应的二进制实现。这样,客户端访问时,先根据命名规则定位到 recipe,再根据目标 setting 的不同选择对应的二进制 package 来下载、使用。

在 conan-center 中,各种公共库都根据目标 setting 的不同提供了大量的二进制 package 供开发者直接使用,大大提高了 C/C++ 应用的编译效率。

  • 依赖描述语言

Conan提供了简单明了的依赖关系描述方式,在后续的示例中会做详细解读。

  • 客户端

Conan 的客户端提供了丰富的命令行命令,能够方便地实现依赖关系的解析和依赖包的管理。

Conan 客户端的安装也非常简便,大家可以参考文档自己实践(https://docs.conan.io/en/latest/installation.html)。

安装好之后,我们可以运行第一个命令:

c66fd96581012ce01b4d617348631056.png

可以看到 Conan 客户端已经预先配置好了与公共库 conan-center 的连接,开发者可以直接使用其中的公共依赖包。

本文后续将通过示例来展示 Conan 如何利用这些解决方案来提供服务。

Conan 应用示例

本文将基于一个简单的 C++ 应用来展示如何使用 Conan,其代码可以在https://github.com/xingao0803/demo-poco-timer.git  中获得,供大家参考。

  • 描述依赖关系

示例中的 C++ 应用,timer.cpp,是一个简单的 timer 程序,引用了公共库 POCO:

cd45ce1d991a0e49c35d3f26cc356bfa.png

为了在 Conan 中描述与 POCO 的依赖关系,需要编写 conanfile.txt,这就是上一节提到的依赖描述语言。

ea7e7ad8ff7f1426cf0d9a2118e77529.png

其中,[requires] 部分列出了本应用需要的依赖包,这里是 POCO,1.8.0.1版本,而且是由 pocoproject 提供的稳定(stable)版本。

[generators] 则列出了编译本应用使用的编译器类型。Conan 提供的公开示例大多是基于 cmake 的,这里改用更为通用的 compiler_args,不限定编译器的类型。

当然,这里只是一个简单的例子,conanfile.txt 的更多内容请参考 Conan 官方文档https://docs.conan.io/en/latest/reference/conanfile_txt.html。

我们知道,在软件开发中,除了代码中的直接依赖,还会有各种传递依赖。而 conanfile.txt 里只列出了直接依赖。Conan 的客户端提供了“conan info”命令来解析所有的依赖关系。

在 conanfile.txt 所在目录执行:

f3c7d17876e8a8213720f7377b9ae9c1.png

本应用相关的各种依赖传递关系就会在 denpendencies.html 里展示出来,如下图:

e91d5beae05a4aca4bd188aa0524e15b.png

此时再执行:

31523982fd7eb284e88e0dfcc7f4fb29.png

可以看到,相关依赖包的 recipe 已经下载到本地 cache 里了。

  • 下载依赖包二进制文件

“conan info” 命令只是下载了依赖包的 recipe。要下载对应 setting 的 package 二进制包,用以编译,还需要执行 “conan install” 命令。

在 conanfile.txt 所在目录创建构建子目录,并执行 “conan install”:

1ae3e8835c4db0ff4cd838a065c7f66d.png

从运行结果可以看出,Conan 的客户端根据本地的 setting 设置和依赖包的 recipe,自动从 conan-center 上获取对应的二进制 package,下载到本地 cache 里。

当然,由于 C/C++ 生态系统的快速发展,Conan 现有的二进制 package 不一定能够覆盖所有的 setting 组合。“—build=missing” 参数就是指定在没有 setting 对应的二进制 package 时,根据 recipe 中定义的方法,自动从依赖包的源代码编译出对应的二进制包,存储在本地 cache 中。例如:当我在 macbook 上执行上述操作时,POCO 就需要进行重新编译:

083b042d189065c4579e98995eff14d6.png

当我们再次运行 “conan install” 命令时可以发现,此时相关的依赖包已经可以直接从本地 cache 获取了,避免了重复的网络访问和编译工作。

84e273f77bc4844b199eaa0fa7295ea1.png
  • 上传到私有依赖包仓库

在当前团队协作开发的模式下,仅仅把依赖包下载到本地 cache 是远远不够的,我们还需要让整个团队都能够分享这些依赖包。这样即避免了重复的网络访问和编译,又保证了团队中依赖引用的一致性。此时就需要引入私有的依赖包仓库。

Conan 提供了原生的 conan_server 作为本地化部署的私有仓库,可以参考文档https://docs.conan.io/en/latest/uploading_packages/running_your_server.html。

而这里我们要推荐 JFrog 的 Artifactory 全语言制品仓库。Artifactory 不仅仅可以做为 Conan 仓库,其全语言的支持能力还使其能够同时提供 Maven、NPM、Docker 等依赖仓库的服务。 Artifactory 还提供元数据的能力,也就是可以在仓库存储制品的属性上记录整个 DevOps 过程中的关键数据。此外,Artifactory 还可以和 Jenkins 紧密集成,在 Jenkins Pipeline 中提供针对各种开发语言的 DSL,方便持续交付流水线的开发与编排。Artifactory 全语言、元数据,以及集成 Jenkins 的优势在后续示例中都能够得到体现。

Artifactory 的相关信息可以参见文档https://www.jfrog.com/confluence/display/RTF/Welcome+to+Artifactory ,“JFrog 杰蛙 DevOps” 微信公众号上也有很多相关文章和视频课程供大家参考。此外,JFrog Artifactory 还针对 Conan 的应用推出了社区版-- Artifactory CE, https://docs.conan.io/en/latest/uploading_packages/artifactory_ce.html,供大家使用。

为了使用 Artifactory 建设私有的 Conan 依赖包仓库,我们需要在 Artifactory 创建一个 Conan 类型的 local repository。创建方法参见https://www.jfrog.com/confluence/display/RTF/Conan+Repositories 。

然后,我们需要执行 Conan 的客户端命令 “conan remote add” 和 “conna user” 加入这个私有仓库。具体的执行方法在 Artifactory Repository 的  “Set Me Up” 部分有清晰的描述:

3cf41d6aac5c5fce551a97d3b0baea6a.png

其中 作为这个私有仓库的别名,会在后续的命令中用来指定使用该仓库。

私用仓库创建好之后,我们可以使用 “conan upload” 命令来上传下载到本地 cache 的依赖包:

d9da46d9d9ee444b696e70fc0f9acffa.png

其中 -r 用以指定目标私有仓库,--all 指定同时上传 recipe 和 package。

运行之后,在 Artifactory 的 Conan repository 里就可以看到上传的依赖包了。

04253b743b2f2980e685d113548c049f.png

之后当再次需要使用这些依赖包时,就可以在执行 “conan install” 时利用 “-r ” 参数指定从私有仓库获取了。

bc723660f7d10de6f5cbcd949f2a5351.png
  • 编译C++应用

执行 “conan install” 之后,除了会下载相应依赖包的二进制 package 之外,还会自动生成编译相关的参数引用文档。如在前面的示例中,build 目录下会自动生成 conanbuildinfo.args 文件,其中包含了编译过程中如何引用相应依赖包的参数设置。当编译时,可以直接引用这些参数:

540586a35bcc616c858afb9acd857c83.png

可以看出,基于 Conan 的依赖管理,只要通过 conanfile.txt 描述依赖关系,通过 conan install 命令下载依赖包 package,我们就可以便捷地完成 C++ 应用的编译。

  • 管理C++应用

当然,从应用开发过程来看,仅仅完成编译还是不够的,我们还需要管理好编译产出的可执行程序,供后续测试、部署、发布等环节使用。

通常会把应用编译好的可执行程序存储到代码管理系统,如 git 或 svn 中,或者文件服务器,如 ftp 上。但这种方式会丢失掉应用程序特定的 setting 信息,而且会对现有系统造成性能上的影响。

这里我们还是推荐使用 Artifactory,利用其 Generic repository 来存储可执行程序。Artifactory 全语言的支持使得能够在同一个仓库中统一管理 Conan 依赖包和编译好的可执行程序。而其企业级高可用的特性能够保证制品访问的性能和稳定。

在 Artifactory 里创建一个 Generic 的 local repository,在其 “Set Me Up” 部分可以看到如何利用 Artifactory 的 rest api 来上传和下载相应的可执行程序:

c70f0c6b38036fdb1f2dad9b17123980.png

同时,我们可以在 repository 里通过设置不同的目录来记录可执行程序的版本。

a34c4bb506242994182e826c9f274ee7.png

针对可执行程序特定的 setting,也可以通过Artifactoy 的元数据能力记录到对应程序的属性上。

在执行完 “conan install” 之后,build 目录里还会自动生成 conaninfo.txt 文件,记录了本应用及其依赖相关的各种配置参数,其中 [settings]、[full_settings] 部分记录了相关的 setting 信息:

17cde815e846924a79462f3b557e10bd.png

可以将这些 setting 参数提取出来,利用 Artifactory 的 rest api 写入属性:

6f4cfab2ec6d11bbb6138b86a0164261.png

在 Artifactory 的 repository 里就可以看到这些属性了:

5bb61d8e4a0c5cf97d6bbf3309779c93.png

此外,Artifactory 还提供了 AQL(Artifactory Query Language),使得我们能够基于这些元数据属性设置查询条件,从而定位与目标 setting 匹配的可执行程序。

设置 aql 文件 1timer.aql 如下:

ec94ea0c75438913c4ec3590a796585d.png

再利用 Artifactory 的查询 rest api,我们就可以定位和下载符合 setting 需求的可执行程序,供后续的测试、部署等环节使用了。

37d755461ab5ce81c927962d5538cccb.png

同时,我们还可以利用 Artifactory 元数据的能力,将后续环节的关键数据,如测试结果,也记录在该程序的属性中,从而为质量监控审批、出错回溯检查等提供数据支持。

C/C++持续交付流水线

前面的示例,我们利用 Conan 依赖管理和 Artifactory 私有仓库实现了完整的 C++ 应用开发流程。在当前 DevOps 应用背景下,我们还需要能够自动化地重复执行这一流程,以实现 C++ 应用的持续交付。这就需要利用 Conan、Artifactory 和 Jenkins 这一类工具的集成来实现。

Artifactory 提供了 Jenkins 的插件,支持 Jenkins Pipeline 中针对 Artifactory 和 Conan 的 DSL,可以很方便、直观的实现 Artifactory 和 Conan 的各种操作。前面示例中的各种操作,都可以利用相应的 DSL 语句,集成到 Jenkins Pipeline 当中,如:

c8494a21908c888743412529c099bb68.png b7e3e3b7eafe273813ef62d0c60251be.png

完整的 Jenkins Pipeline 代码在https://github.com/xingao0803/demo-poco-timer.git  中可以找到,供大家参考。

在 Jenkins 中执行该 Pipeline,就可以实现 timer 应用的自动化持续交付流水线:

2c780e572df3d2fb20e22b80315686e9.png

总结

C/C++ 的依赖管理一直是软件开发领域的痛点。本文介绍了当前得到广泛关注和迅速发展的 C/C++ 依赖管理解决方案--Conan 的基本原理和应用流程。同时,利用 timer 应用示例,展示了如何基于 Conan、Artifactory 和 Jenkins,实现C/C++应用的持续交付流水线。

当然,本文中的示例只展示了 Conan 最基本的应用场景,大家可以根据相关资料,学习和研究 Conan 更多的案例。我们也会陆续推出后续文章,为大家进一步展示 Conan 的特性和应用方式。

参考文献

  • Conan 官网https://conan.io

  • JFrog 官网 http://www.jfrogchina.com

  • Artifactory 文档 https://www.jfrog.com/confluence/display/RTF/Welcome+to+Artifactory

  • Artifactory社区版 https://docs.conan.io/en/latest/uploading_packages/artifactory_ce.html

  • 示例代码 https://github.com/xingao0803/demo-poco-timer.git

caadc97fe3ef976960aea0872a778e1a.png 3c477cd9730e23c66208ff74ea52a10a.png

联系我们:info@jfrogchina.com

54986e809148847caf282fe75abfc3f9.gif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧农业是一种结合了现代信息技术,包括物联网、大数据、云计算等,对农业生产过程进行智能化管理和监控的新模式。它通过各种传感器和设备采集农业生产中的关键数据,如大气、土壤和水质参数,以及生物生长状态等,实现远程诊断和精准调控。智慧农业的核心价值在于提高农业生产效率,保障食品安全,实现资源的可持续利用,并为农业产业的转型升级提供支持。 智慧农业的实现依赖于多个子系统,包括但不限于设施蔬菜精细化种植管理系统、农业技术资料库、数据采集系统、防伪防串货系统、食品安全与质量追溯系统、应急追溯系统、灾情疫情防控系统、农业工作管理系统、远程诊断系统、监控中心、环境监测系统、智能环境控制系统等。这些系统共同构成了一个综合的信息管理和服务平台,使得农业生产者能够基于数据做出更加科学的决策。 数据采集是智慧农业的基础。通过手工录入、传感器自动采集、移动端录入、条码/RFID扫描录入、拍照录入以及GPS和遥感技术等多种方式,智慧农业系统能够全面收集农业生产过程中的各种数据。这些数据不仅包括环境参数,还涵盖了生长状态、加工保存、检验检疫等环节,为农业生产提供了全面的数据支持。 智慧农业的应用前景广阔,它不仅能够提升农业生产的管理水平,还能够通过各种应用系统,如库房管理、无公害监控、物资管理、成本控制等,为农业生产者提供全面的服务。此外,智慧农业还能够支持政府监管,通过发病报告、投入品报告、死亡报告等,加强农业产品的安全管理和质量控制。 面对智慧农业的建设和发展,存在一些挑战,如投资成本高、生产过程标准化难度大、数据采集和监测的技术难题等。为了克服这些挑战,需要政府、企业和相关机构的共同努力,通过政策支持、技术创新和教育培训等手段,推动智慧农业的健康发展。智慧农业的建设需要明确建设目的,选择合适的系统模块,并制定合理的设备布署方案,以实现农业生产的智能化、精准化和高效化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值