QT C++工程CI环境笔记
开发环境
- Ubuntu18.04 or Ubuntu20.04
- Qt Creator 4.6.x (Based on Qt 5.11.x)
- APT list: apt-transport-https git dh-make build-essential autoconf autotools-dev qt5-default libssl-dev qt5keychain-dev devscripts
项目结构
项目主体结构是根据Qt, 用.pro文件组织, 项目最外层TEMPLATE用subdirs, 用于引入项目主pro文件, 这样便于将源代码放入子目录, 实际的项目pro文件在子目录下. 最外层还有对应的说明文件, 授权文件和Gitlab CI配置等.
├── .git
├── .gitignore
├── .gitlab-ci.yml # Gitlab CI配置文件
├── LICENSE
├── README.md # 项目Readme
├── rockbb # 实际源代码目录
│ ├── app-entry # 为debian/ubuntu提供的桌面图标配置文件及图标文件
│ │ ├── rockbb.desktop
│ │ └── rockbb.png
│ ├── *.cpp
│ ├── *.h, *.ui
│ ├── config.h # 全局配置, namespace rockbb
│ ├── debian # deb打包时需要的文件
│ │ ├── changelog # 软件历史版本信息, 有格式要求
│ │ ├── compat # debhelper压缩级别, 最新的是10, 如果要兼容可以用9
│ │ ├── control # 软件的包名, 维护者, 编译工具依赖, 安装依赖等
│ │ ├── copyright # 标准版权信息, 例如GPLv3
│ │ └── rules # 编译和打包命令, 在这里将资源文件复制到deb包的标准位置
│ ├── res.qrc # 资源文件, 在这个文件里记录images目录里的各个文件
│ ├── images
│ │ ├── rockbb-off.png
│ │ ├── rockbb-on.png
│ │ ├── rockbb.png
│ ├── main.cpp # 程序入口
│ └── rockbb.pro # 主要项目文件
├── rockbb-project.pro # 项目入口文件(用于引入rockbb.pro)
└── rockbb-project.pro.user # Qt Creator产生的本地开发配置文件, 需要从gitignore中排除
Qt对非Qt项目文件的支持不好, 在project视图下默认不展示不相关的文件, 如果要显示, 需要在.pro文件中使用 OTHER_FILES 将需要显示在工作区的文件包含进来.
如果切换到File System视图, 默认不显示点开头的隐藏文件, 需要在模块右上角选项中勾上"Show Hidden Files", 才会展示.gitlab-ci.yml这些文件.
开发编译和测试
在本地通过Qt Creator完成, 编译, Debug和运行有Ctrl+B, F5, Ctrl+R等快捷方式.
项目文件中常用的变量及说明
- QT
指定项目用到的Qt模块, 在编译阶段, 被指定的Qt模块头文件会被include并且被链接. 默认Qt会包含core和gui, 如果项目不需要gui, 需要用 QT -= gui 显式排除. - QTPLUGIN
指定需要链接到最终可执行文件的静态Qt插件, 成为内建资源. - CONFIG
在这里设置项目编译选项, 不同的值对应qmake内部不同的处理, 常用值包括 release, debug, debug_and_release, warn_on, warn_off, c99, c11, c++11, static等 - DEFINES
qmake adds the values of this variable as compiler C preprocessor macros (-D option). - DESTDIR
指定最终生成的可执行文件的路径. - OBJECTS_DIR
指定存放编译过程中中间对象的存放路径 - MOC_DIR
Specifies the directory where all intermediate moc files should be placed. - RCC_DIR
Specifies the directory for Qt Resource Compiler output files. - LIBS
指定需要被链接到项目的库. 如果使用Unix形式的 -l(library) 和 -L (library path) 参数, qmake 可以在Windows下正确识别处理. - QMAKE_CXXFLAGS
Specifies the C++ compiler flags for building a project. The value of this variable is typically handled by qmake or qmake.conf and rarely needs to be modified. The flags specific to debug and release modes can be adjusted by modifying the QMAKE_CXXFLAGS_DEBUG and QMAKE_CXXFLAGS_RELEASE variables, respectively. - SOURCES
Specifies the names of all source files in the project - HEADERS
Defines the header files for the project. - PWD
解析为包含被解析的当前文件的完整路径. This can be useful to refer to files within the source tree when writing project files to support shadow builds. - INCLUDEPATH
指定编译时 #include 应该查找的目录, 如果目录带空格, 需要用双引号包围. - TARGET
指定最后生成的可执行文件名. 默认等于项目文件名.
项目文件中的语法
变量赋值方式
VAR = foobar => 在qmake执行的时候给VAR变量赋值(值为foobar)
$$VAR => 在qmake执行的时候, 使用VAR对应的QMake变量值, 例如$$PWD
$${VAR} => 和上面一样只不过将变量显式指出
$(VAR) => 在Makefile运行时取环境变量的值
$$(VAR) => 在qmake运行时取环境变量的值
包含第三方项目的pri文件
include(path/to/some.pri)
区分debug和release做不同配置
debug: {
...
}
release: {
...
}
代码仓库
在本地通过 git remote add 将github添加为上游仓库, 这样项目对应的就有 origin 和 github 两个上游, 在本地编译通过后, push origin master可以触发测试环境的gitlab进行集成, 在gitlab测试通过后, 可以push gitlab master将代码提交到github.
测试集成
测试环境的持续集成, 使用Gitlab + Gitlab Runner实现. 有条件的话Gitlab Runner应当跑在独立的服务器上, 另外如果需要构建异构系统例如Windows, OSX等, 都需要将Runner跑在独立的服务器上. 如果只需要构建Linux下的发行版, 可以放在一起. Gitlab Runner需要Docker环境, 最好使用Ubuntu较新的发行版.
gitlab 12.10.6, gitlab-runner 12.10.2, docker 19.03.6
Gitlab配置
略. 这里主要是创建group, project, user, 获取group下的runner token
Gitlab Runner配置
准备Docker镜像, 对于不同的发行版发布, 要准备对应的发行版镜像, 再将这些镜像作为Runner, 注册到Gitlab. 举例Ubuntu18.04的Dockerfile
from ubuntu:bionic
ADD setup.sh /opt/
RUN /bin/bash /opt/setup.sh
和setup.sh, 这个脚本用于切换到较快的apt源, 以及准备编译环境.
#!/bin/sh
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ bionic main restricted" > /etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ bionic-updates main restricted" >> /etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ bionic universe" >> /etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ bionic-updates universe" >> /etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ bionic multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ bionic-updates multiverse" >> /etc/apt/sources.list
echo "deb http://mirrors.ustc.edu.cn/ubuntu/ bionic-backports main restricted universe multiverse" >> /etc/apt/sources.list
echo "deb http://security.ubuntu.com/ubuntu bionic-security main restricted" >> /etc/apt/sources.list
echo "deb http://security.ubuntu.com/ubuntu bionic-security universe" >> /etc/apt/sources.list
echo "deb http://security.ubuntu.com/ubuntu bionic-security multiverse" >> /etc/apt/sources.list
#requirements
apt-get update
apt-get -y install apt-transport-https git dh-make build-essential autoconf autotools-dev qt5-default libssl-dev qt5keychain-dev devscripts
对于Ubuntu20.04, 在apt install 过程中会出现tzdata等需要交互的安装导致镜像制作失败, 需要在apt-get update前加上这句
export DEBIAN_FRONTEND=noninteractive
制作镜像, 将镜像注册为Runner
# 制作镜像
docker build -t ubuntu_focal_runner:1.0 ubuntu_focal/
# 注册到gitlab
gitlab-runner register --non-interactive --url "http://172.17.54.139/" --registration-token "x7sx4rte_acSXrmznJBz" --description "Ubuntu 20.04 x64 runner" --executor "docker" --docker-image "ubuntu_focal_runner:1.0" --tag-list "ubuntu-2004-64" --run-untagged="false" --locked="false" --access-level="not_protected"
测试镜像是否可用:
对于刚建好的容器镜像, 需要在跑任务前实际执行一下构建, 可以通过 docker run -it --rm [image] bash 的方式, 在命令行下手动git clone项目文件, 执行编译. 如果有问题, 需要在这一步重新制作镜像来解决. 不同的发行版, gcc/g++版本可能会不一样, Ubuntu16.04(GCC 5.4), Ubuntu18.04(GCC 7.5), Ubuntu20.04(GCC9.3), Debian8&10(GCC 8.3)
对于runner, 需要注意的有两点:
- 每个runner需要带一个 --tag-list "ubuntu-2004-64" 参数, 里面可以配一个或多个tag, 这个tag-list 结合 .gitlab-ci.yml文件里的 tags 参数, 可以让发行版各自执行对应的任务.
- 如果希望Runner就近pull镜像, 在注册完runner后, 需要修改 /etc/gitlab-runner/config.toml 文件, 在每个runner的[runners.docker]配置下, 增加一行配置. 默认为"always", 会主动去docker hub 拉取, 因为自建的镜像只存在本地, 从而导致任务失败.
volumes = ["/cache"]
pull_policy = "if-not-present" # 增加这行
shm_size = 0
项目 .gitlab-ci.yml 配置
参考
https://docs.gitlab.com/ee/ci/quick_start/
https://docs.gitlab.com/ee/ci/yaml/
根据.gitlab-ci.yml里的任务配置, gitlab在收到新的push后, 会触发产生pipeline, 里面是满足条件的, 分配到对应runner的job. 如果中途有job失败, 整个pipeline就会失败, 不再往下执行.
Github发布
对于版本间一个完整的开发周期, 以上一个版本号Tag提交为开始, 以下一个版本号提交为结束.
开发阶段
假设已经发布的版本号为1.1, 进入当前开发周期后, 首先修改以下文件
- config.h: 版本号修改为 1.2-dev
因为测试集成产生的版本号为特殊版本号, 并且会完全覆盖debian/changelog, 故这一阶段还不需要修改changelog
预发布阶段
在测试结束后, 进入发布准备工作, 需要修改以下文件
- config.h: 版本号修改为 1.2
- debian/changelog: 加入自上个版本至今的改动说明
对commit ID打tag, 并生成正式版的release
# 加tag
git tag -a 0.1.0 94ca32cbc4bd685774f22d95c66d58c79dccf95f
# 触发测试执行任务, 打包正式版
push origin --tags
本地对release进行测试
发布阶段
将tag推送到github
git push github --tags
之后, github会自动对新tag产生release, 可以手工在此release下添加文字和对应的release软件包