使用 GitLab CI 构建 Windows 版 qBittorrent

使用 GitLab CI 构建 Windows 版 qBittorrent

考虑到官方预编译的 Windows 版 qBittorrent 有些时候不能满足自己稳定运行的要求,因此我决定尝试 GitLab CI 自动构建。

准备 Windows 容器

运行 Windows 容器只需要 WSL 或者 WSL2 支持,但 GitLab Runner 仅支持 Windows Server 平台,因此需要准备一台 Windows Server 宿主机。Windows Server 可以是裸机或者通过虚拟化 Intel VT-x/AMD-v 做到 Nested Virtualization。我使用的是 Windows Server 2019 (version 1809)。

可以在 PowerShell 运行如下命令:

Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/Windows-Containers/Main/helpful_tools/Install-DockerCE/install-docker-ce.ps1" -o install-docker-ce.ps1
.\install-docker-ce.ps1

这会为系统启用 WSL/WSL2 功能,并安装 Docker Engine。

注册 GitLab Runner

为 GitLab Runner 创建一个文件夹例如:C:\\GitLab-Runner二进制文件下载到文件夹中。运行如下指令注册 runner:

.\gitlab-runner.exe register

填写相关信息:

  • 输入 GitLab 的网址,自建或者官网。
  • 输入用以注册 runner 的 token
  • 输入你对 runner 的描述,或者保留默认值,通常它会选择你的系统 hostname
  • 输入 runner 关联的 tag。
  • 输入其他维护信息

顺利的话你就可以在 GitLab runner 状态页面找到这台 runner。

准备 Windows 镜像

你只能运行与宿主系统相同版本的 Windows Server Core 镜像。因此如果运行的是 Windows Server 2019 就应该拉取 mcr.microsoft.com/windows/servercore:1809。其他镜像可以在 Docker Hub 查到。此外相关的 dotnet 镜像等也可以被用来运行 CI 环境。由于 qBittorrent 编译以来的 Visual Studio 2019 CE 依赖 dotnet 环境,因此直接拉取 mcr.microsoft.com/dotnet/framework/runtime:4.8-20220913-windowsservercore-ltsc2019 可以方便后续操作。

除了准备基础镜像,我还需要收集编译依赖的组件。根据 qBittorrent 的 Wiki 我需要为这个系统安装

其中 VS2019CE, cmake, ninja, git 可以通过 chocolatey 安装。剩下的 libboost, openssl, qt5, 可以使用 vcpkg 编译安装。而 Libtorrent 则通过手动编译完成安装。由于大部分的编译依赖并不需要经常更新,因此我决定先将一部分常用的依赖安装并制作成镜像,编译 qBittorrent 时直接使用这个环境。

我使用了如下配置(Dockerfile)创建 Docker 镜像

FROM mcr.microsoft.com/dotnet/framework/runtime:4.8-20220913-windowsservercore-ltsc2019

SHELL [ "powershell", "-Command" ]

# install chocolatey
RUN echo \"**** installing chocolatey ****\"
RUN Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

# install buildtools
RUN echo \"**** installing build-essential ****\"
RUN choco install visualstudio2019community -y --params \"--add Microsoft.VisualStudio.Workload.MSBuildTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.VC.CoreIde --add Microsoft.VisualStudio.Component.VC.CoreBuildTools --add Microsoft.VisualStudio.Component.TextTemplating --add Microsoft.VisualStudio.Component.VC.Redist.14.Latest --add Microsoft.VisualStudio.Component.VC.ATL --add Microsoft.VisualStudio.Component.VC.ATLMFC --add Microsoft.VisualStudio.Component.VC.14.29.16.10.x86.x64 --add Microsoft.VisualStudio.Component.Windows10SDK.19041\"
RUN choco install git -y
RUN choco install cmake -y --installargs 'ADD_CMAKE_TO_PATH=System'
RUN choco install ninja -y

# active build environment
RUN $env:Path = [Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine);
RUN Import-Module \"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\Microsoft.VisualStudio.DevShell.dll\"; Enter-VsDevShell -VsInstallPath \"C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\" -DevCmdArguments \"-host_arch=amd64 -arch=amd64\"

# prepare vcpkg
RUN echo \"**** installing vcpkg ****\" 
WORKDIR "C:\\"
RUN git clone https://github.com/microsoft/vcpkg
WORKDIR "C:\\vcpkg"
RUN .\bootstrap-vcpkg.bat -disableMetrics
RUN .\vcpkg integrate install
RUN .\vcpkg install \
    boost-circular-buffer:x64-windows-static \
    boost-stacktrace:x64-windows-static \
    openssl:x64-windows-static \
    qt5-base:x64-windows-static \
    qt5-svg:x64-windows-static \
    qt5-tools:x64-windows-static \
    qt5-translations:x64-windows-static \
    qt5-winextras:x64-windows-static \
    --clean-after-build

# Storage layer consumed downstream
FROM scratch

# set version label
ARG BUILD_DATE
ARG VERSION
LABEL build_version="efs.zone version:- ${VERSION} Build-date:- ${BUILD_DATE}"
LABEL maintainer="EFS"

使用上述配置的镜像体积高达 43.6GB 因此并不适合上传到 Docker Hub,但我可以通过上传到本地的 docker registry 完成对镜像的管理。可以通过上一篇日志所叙述的方式搭建本地的 docker registry。

配置 GitLab CI

使用上一个步骤生成的镜像就可以编译 qBittorrent。编译 qBittorrent 需要如下步骤。

  • 通过 vcpkg 安装然后删除 Libtorrent 以完成 Libtorrent 的编译依赖
  • 编译 Libtorrent
  • 编译 qBittorrent
  • 提取打包所需二进制及其他必要文件
  • 安装 NSIS 打包环境
  • 打包并上传 artifacts

以下配置为实现方法(.gitlab-ci.yml):

.shared_windows_runners:
    tags:
    - build-windows
    image: local.registry/efs/qt5-cmake-vs2019:latest

stages:
    - build-binary
    - packaging

build:
    extends:
        - .shared_windows_runners
    stage: build-binary
    timeout: 8h
    script:
        # prepare base environment
        - Import-Module "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\Microsoft.VisualStudio.DevShell.dll"; Enter-VsDevShell -VsInstallPath "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community" -DevCmdArguments "-host_arch=amd64 -arch=amd64"
        # install build environment
        - cd "C:\vcpkg"
        - .\vcpkg integrate install
        - .\vcpkg install libtorrent:x64-windows-static
        - .\vcpkg remove libtorrent:x64-windows-static
        # build binary
        # Libtorrent-Rasterbar
        - cd "$CI_PROJECT_DIR"
        - git clone `
            --branch RC_1_2_EFS `
            --depth 1 `
            --recurse-submodules `
            https://gitlab-ci-token:${CI_JOB_TOKEN}@selfhost.gitlab.com/efs/libtorrent.git
        - cd ".\libtorrent"
        - cmake `
            -B build `
            -G "Ninja" `
            -DCMAKE_BUILD_TYPE=Release `
            -DCMAKE_EXPORT_COMPILE_COMMANDS=ON `
            -DCMAKE_INSTALL_PREFIX="$CI_PROJECT_DIR/buildd" `
            -DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake" `
            -DVCPKG_TARGET_TRIPLET="x64-windows-static" `
            -DBUILD_SHARED_LIBS=OFF `
            -Ddeprecated-functions=OFF `
            -Dstatic_runtime=ON
        - cmake --build build
        - cmake --install build
        # qBittorrent
        - cd "$CI_PROJECT_DIR"
        - git clone `
            https://gitlab-ci-token:${CI_JOB_TOKEN}@selfhost.gitlab.com/efs/qbittorrent.git
        - cd ".\qBittorrent"
        - cmake `
            -B build `
            -G "Ninja" `
            -DCMAKE_BUILD_TYPE=Release `
            -DCMAKE_EXPORT_COMPILE_COMMANDS=ON `
            -DCMAKE_TOOLCHAIN_FILE="C:/vcpkg/scripts/buildsystems/vcpkg.cmake" `
            -DLibtorrentRasterbar_DIR="$CI_PROJECT_DIR/buildd/lib/cmake/LibtorrentRasterbar" `
            -DMSVC_RUNTIME_DYNAMIC=OFF `
            -DVCPKG_TARGET_TRIPLET=x64-windows-static `
            -DVERBOSE_CONFIGURE=ON `
            --graphviz=build/target_graph.dot
        - cmake --build build
        # prepare uploads
        - cd $CI_PROJECT_DIR
        - If(!(test-path -PathType container upload)){New-Item -ItemType Directory -Path upload}
        - Copy-Item "$CI_PROJECT_DIR/qBittorrent/build/qbittorrent.exe" "upload"
        - Copy-Item "$CI_PROJECT_DIR/qBittorrent/build/qbittorrent.pdb" "upload"
        - Copy-Item "$CI_PROJECT_DIR/qBittorrent/dist/windows/qt.conf" "upload"
        # cmake additionals
        - If(!(test-path -PathType container upload/cmake)){New-Item -ItemType Directory -Path upload/cmake}
        - Copy-Item "$CI_PROJECT_DIR/qBittorrent/build/compile_commands.json" "upload/cmake"
        - Copy-Item "$CI_PROJECT_DIR/qBittorrent/build/target_graph.dot" "upload/cmake"
        - If(!(test-path -PathType container upload/cmake/libtorrent)){New-Item -ItemType Directory -Path upload/cmake/libtorrent}
        - Copy-Item "$CI_PROJECT_DIR/libtorrent/build/compile_commands.json" "upload/cmake/libtorrent"
        # qt-translations
        - Copy-Item "C:/vcpkg/installed/x64-windows-static/share/qt5/translations" "$CI_PROJECT_DIR/translations/" -Recurse
    cache:
        key: build-cache
        paths:
            - upload/
            - translations/

packaging:
    extends:
        - .shared_windows_runners
    stage: packaging
    timeout: 8h
    script:
        # prepare base environment
        - Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        - choco install git -y
        - choco install nsis -y
        - choco install 7zip -y
        - $env:Path = [Environment]::GetEnvironmentVariable('Path', [System.EnvironmentVariableTarget]::Machine);
        - cd "$CI_PROJECT_DIR"
        - git clone `
            https://gitlab-ci-token:${CI_JOB_TOKEN}@selfhost.gitlab.com/efs/qbittorrent.git
        - cd ".\qBittorrent\dist\windows\nsis plugins"
        - 7z x -o".\FindProcDLL" .\FindProcDLL_mod_by_hnedka.7z
        - Copy-Item ".\FindProcDLL\Unicode\FindProcDLL.dll" "C:\Program Files (x86)\NSIS\Plugins\x86-unicode"
        - 7z x -o".\nsisFirewall" .\nsisFirewall.zip
        - Copy-Item ".\nsisFirewall\bin\nsisFirewallW.dll" "C:\Program Files (x86)\NSIS\Plugins\x86-unicode"
        - 7z x -o".\UAC" .\UAC.zip
        - Copy-Item ".\UAC\Plugins\x86-unicode\UAC.dll" "C:\Program Files (x86)\NSIS\Plugins\x86-unicode"
        # prepare binary
        - Copy-Item "$CI_PROJECT_DIR\upload\qbittorrent.exe" "$CI_PROJECT_DIR\qBittorrent\dist\windows"
        - Copy-Item "$CI_PROJECT_DIR\upload\qbittorrent.pdb" "$CI_PROJECT_DIR\qBittorrent\dist\windows"
        - Copy-Item "$CI_PROJECT_DIR\upload\qt.conf" "$CI_PROJECT_DIR\qBittorrent\dist\windows" -Force
        - Copy-Item "$CI_PROJECT_DIR\qBittorrent\COPYING" "$CI_PROJECT_DIR\qBittorrent\dist\windows\license.txt"
        - Copy-Item "$CI_PROJECT_DIR\translations\" "$CI_PROJECT_DIR\qBittorrent\dist\windows\translations\" -Recurse
        # run package
        - cd "$CI_PROJECT_DIR\qBittorrent\dist\windows"
        - Start-Process -NoNewWindow -FilePath "C:\Program Files (x86)\NSIS\makensis.exe" -ArgumentList "qbittorrent.nsi" -Wait
        - Copy-Item "$CI_PROJECT_DIR\qBittorrent\dist\windows\qbittorrent*setup.exe" "$CI_PROJECT_DIR\upload"
    cache:
        key: build-cache
        paths:
            - upload/
            - translations/
    artifacts:
      paths: 
          - upload/qbittorrent*setup.exe
      name: qBittorrent-installer_Windows-x64_libtorrent-1.2.x
      expire_in: 2 hr

其中以 https://gitlab-ci-token:${CI_JOB_TOKEN}@selfhost.gitlab.com/efs/qbittorrent.git 形式存在的 git url 可以在开启 Limit CI_JOB_TOKEN access 并赋予相应 Repo 权限后自动完成鉴权以达到拉取其他 Repo 完成编译的效果。

参考文档

https://docs.gitlab.com/runner/install/windows.html

https://docs.gitlab.com/runner/register/

https://docs.gitlab.com/runner/executors/docker.html#supported-windows-versions

https://learn.microsoft.com/en-us/virtualization/windowscontainers/quick-start/set-up-environment?tabs=dockerce

https://github.com/qbittorrent/qBittorrent/wiki/Compilation:-Windows-(MSVC-2019,-64-bit,-static-linkage)

https://github.com/c0re100/qBittorrent-Enhanced-Edition/blob/v4_4_x/.github/workflows/ci_windows.yaml

Amefs, docker, EFS, IT, 教程
上一篇文章
自建本地 docker registry 简易教程
下一篇文章
ASUS ROG Ally 双引导

3条评论. Leave new

  • 您好~我是腾讯云开发者社区运营,关注了您分享的技术文章,觉得内容很棒,我们诚挚邀请您加入腾讯云自媒体分享计划。完整福利和申请地址请见:https://cloud.tencent.com/developer/support-plan
    作者申请此计划后将作者的文章进行搬迁同步到社区的专栏下,你只需要简单填写一下表单申请即可,我们会给作者提供包括流量、云服务器等,另外还有些周边礼物。

    回复
  • github ci 对比 gitlab ci 有啥太大差别不

    回复
    • 除了语法用法有区别,基本功能一致。GitHub 有很多调用如 actions/upload-artifact@v2 是基于 TS 的。GitLab 这类的操作是 runner 直接内置提供的。

      回复

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

Fill out this field
Fill out this field
请输入有效的电子邮箱地址。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据

keyboard_arrow_up