实战:GitLab 上C++项目实现自动化构建

文章目录

  • Step 1:实现C++构建
  • Step 2:实现自动化
    • 确定目标:使用 gitlab-ci 实现
    • 选择 GitLab Runner 的最佳实践方案:GitLab Runner on Kubernetes
    • 设计项目自动化流程:掌握 .gitlab-ci.yml基本语法
  • Step 3:引入业界常用的功能模块
    • 加速编译-ccache
    • 静态代码分析-cppcheck
    • 构建产物持久化-JFrog Bintray

Step 1:实现C++构建

这个环节主要工作是选择并使用适合自己项目的 C++ 构建系统,例如 CMake、QMake、Autotools(config/make)等。这个过程本身并不复杂,但往往会涉及到 C++ 工程化的老大难问题——如何提供 C++ 构建所需的第三依赖库。

想要了解 C++ 构建系统和依赖管理混乱的原因,可以查看 为什么 C++ 的构建系统和依赖管理这么混乱?

为了解决这个问题,本质上有三种解决方案:

  1. 方案一:最理想化的解决方案,源码工程不依赖任何二进制形式的三方库,即将三方库以源码形式进行引入后直接从源码进行编译;
  2. 方案二:最简便也是最常见的解决方案,在编译环境中将构建过程中的所需三方库提前进行准备(直接存储于编译环境本地或者编译前从远端进行拉取);
  3. 方案三:最工程化的解决方案,使用 C++ 依赖管理工具,将所有工程及其依赖库纳入管理。

下表简要对比了三种解决方案优缺点:

如何提供 C++ 构建所需三方依赖库 编译速度 启动成本 维护成本 备注
方案一:将三方库以源码形式进行引入 较慢 较低 部分项目不可行(如不提供基础库源码)
方案二:在编译环境中提前准备所需三方库
方案三:使用 C++ 依赖管理工具 较快 一般

因此,我们在项目实践策略上一般会这样进行:

  • 如果项目可以将三方库以源码形式引入,就尽量选择为方案一
  • 如果项目必须使用二进制形式的第三方依赖库且第三方库变更频率低,则选择方案二
  • 如果项目必须使用二进制形式的第三方依赖库且第三方库变更频率高且依赖关系较为复杂,再选择方案三

如果选择方案三,推荐使用 Conan 工具来进行管理。

Step 2:实现自动化

确定目标:使用 gitlab-ci 实现

了解更多关于 gitlab-ci 的细节可以查看官方文档:GitLab Continuous Integration (GitLab CI/CD)

首先,需要明确:在 GitLab 上实现自动化构建的最佳方式(没有之一)是 gitlab-ci。这是因为 gitlab-ci 是 GitLab 官方提供 CI 工具,因此在 GitLab 平台上它具备其他 CI 工具无法比拟的巨大优势——将自动化与代码无缝衔接。
实战:GitLab 上C++项目实现自动化构建_第1张图片
gitlab-ci 中的重要定义:

  • Pipeline:自动化的抽象概念,Pipeline 其实相当于一个完整的自动化任务定义,里面可以包含多个 Stage
  • Stage:自动化的抽象概念,Stage 表示构建阶段,当一个 Pipeline 中定义多个 Stages,这些 Stages 会有以下特点:
    • 所有 Stages 会按照顺序运行,即当前 Stage 执行完成后,下一个 Stage 才会开始
    • 如果当前 Stage 失败,那么后面的 Stages 不会再执行
  • Job: 自动化的具体定义,Jobs 表示具体的构建工作,当一个 Stage 里面定义多个 Jobs,这些 Jobs 会有以下特点:
    • 相同 Stage 中的 Jobs 支持并行执行
    • 相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功
  • .gitlab-ci.yml :gitlab-ci 约定位于项目根目录下 .gitlab-ci.yml 用于定义当前项目的 Pipeline,任何提交或者 Merge Request 的合并都可以触发该 Pipeline 执行。
  • GitLab Runner:在 GitLab 中,Job 需要明确定义在什么样的 GitLab Runners 中运行。目前 GitLab Runners 支持 GNU/Linux, macOS, FreeBSD 和 Windows等系统,并且支持部署于 Kubernetes 之上。

选择 GitLab Runner 的最佳实践方案:GitLab Runner on Kubernetes

如果按照传统的方式,即只是将 GitLab-Runner 安装于某个或某几个机器上的方式,容易出现如下的问题:

  • 很难保障每个 Runner 所在机器环境一致,因此 Job 在设计上要多考虑一些情况增加 CI 实现的复杂度
  • 缺乏统一调度,资源分配容易出现不平衡

为了解决这些痛点,我们可以采用在 Kubernetes 集群中运行 GitLab-Runner 来动态执行 gitlab-ci 脚本任务,它整个流程如下图:
实战:GitLab 上C++项目实现自动化构建_第2张图片
具体实现步骤如下:

  1. 搭建 Kubernetes 并安装 GitLab Runner :参考 Run GitLab Runner on a Kubernetes cluster
  2. 定制满足项目要求的 Docker Image:参考 Docker — 从入门到实践、Best practices for writing Dockerfiles
  3. 将定制的 Docker Image 上传至 Docker Registry 进行管理:参考 Harbor User Guide:Pulling and pushing images using Docker client

设计项目自动化流程:掌握 .gitlab-ci.yml基本语法

想要系统了解 .gitlab-ci.yml 语法可查看官方文档:Configuration of your pipelines with .gitlab-ci.yml

这里给出 gitlab-ci 给出的 C++ 项目 .gitlab-ci.yml 模板作为参考:

# This file is a template, and might need editing before it works on your project.
# use the official gcc image, based on debian
# can use verions as well, like gcc:5.2
# see https://hub.docker.com/_/gcc/
image: gcc

build:
  stage: build
  # instead of calling g++ directly you can also use some build toolkit like make
  # install the necessary build tools when needed
  # before_script: 
  #   - apt update && apt -y install make autoconf 
  script: 
    - g++ helloworld.cpp -o mybinary
  artifacts:
    paths:
      - mybinary
  # depending on your build setup it's most likely a good idea to cache outputs to reduce the build time
  # cache:
  #   paths:
  #     - "*.o"

# run tests using the binary built before
test:
  stage: test
  script:
    - ./runmytests.sh

Step 3:引入业界常用的功能模块

加速编译-ccache

# Sharing caches across the same branch and the same job
cache:
	paths:
  		- key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
  		- ccache/

ccache-build:
	before_script:
		- apt-get update -yqq 
		- apt-get install -y -qq # List truncated for web
		- # CCache Config
		- mkdir -p ccache
		- export CCACHE_BASEDIR=${PWD}
		- export CCACHE_DIR=${PWD}/ccache
	script:
		- cmake . -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
		- make

其他的 cache 策略可以参考:Cache dependencies in GitLab CI/CD

静态代码分析-cppcheck

cppcheck:
	before_script:
		- sudo apt install -y --no-install-recommends cppcheck=1.82-1
		- cppcheck --version
	script:
		- cppcheck *.cpp --verbose --enable=all --inconclusive --language=c++

构建产物持久化-JFrog Bintray

deploy-bintray:
	before_script:
		- sudo apt install -y --no-install-recommends curl
	scrtpt:
		- cmake .
		- make
	after_script:
		- curl -u ${USERNAME}:${PASSWORD} -T build/app "${JFROG_BINTRAY_LOCATION}/${TARGET_FILE_PATH}"
	artifacts:
		expire_in: 1 day
		paths:
			- build/app 

你可能感兴趣的:(持续集成)