Думать о проекте без CI/CD невообразимо, тем более для кросс-платформенного приложения, где нам приходится переключаться между несколькими платформами.

CI/CD

Непрерывная интеграция (CI) и непрерывная поставка (CD) предлагают несколько преимуществ:

  • Небольшие изменения кода.
  • Более быстрая скорость выпуска.
  • Повышение удовлетворенности пользователей.
  • Более простое обслуживание.

Для проектов на основе Qt, которые по своей структуре являются кроссплатформенными, конвейер CI/CD будет иметь несколько дополнительных преимуществ:

  • Не нужно крутить несколько машин под каждую ОС.
  • Надежные и воспроизводимые сборки для всех целевых ОС.
  • Более простая и быстрая интеграция изменений.

Далее мы увидим, как настроить базовый компакт-диск GitHub Actions для получения двоичных файлов нашего программного обеспечения для Windows, Linux и MacOS. Во второй части мы увидим, как создать онлайн- и автономный установщик Windows с помощью QtInstallerFrameWork.

Инструменты

Для создания нашего пайплайна мы будем использовать несколько инструментов, основной из которых — GitHub Actions framework, Aqtinstall — установщик командной строки для Qt и qmake для компиляции программы Qt.

Окна

Сначала мы создаем папку«.github/workflows» внутри репозитория git нашего проекта. Затем создайте действие с именем «windows.yml».

name: Build Windows

on:
  push:
    branches: [master]
Photo by Vidar Nordli-Mathisen on Unsplash
jobs:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v2
      - uses: ilammy/msvc-dev-cmd@v1
      - uses: actions/setup-python@v2
        with:
          python-version: '3.8'
      - name: install qt6
        run: |
          pip install aqtinstall
          python3 -m aqt install-qt -m qtwebengine qtwebchannel qtpositioning -O ${{ github.workspace }}/Qt/ windows desktop 6.2.0 win64_msvc2019_64
          echo "${{ github.workspace }}/Qt/6.2.0/msvc2019_64/bin/" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
      - name: build
        shell: cmd
        run: |
          cd src/
          qmake6 Program.pro -spec win32-msvc
          nmake release
          nmake clean
          cd release
          windeployqt Program.exe --release --compiler-runtime
          copy ..\assets\icon.ico .
          copy C:\Windows\System32\concrt140.dll . 
          copy C:\Windows\System32\vccorlib140.dll .
          copy C:\Windows\System32\msvcp140.dll .
          copy C:\Windows\System32\vcruntime140.dll .
          7z a C:\Program.zip *
      - name: Windows artefact
        uses: actions/upload-artifact@v1
        with:
          name: WindowsBuild
          path: C:\Program.zip

Во-первых, мы назовем Действия (Сборка Windows) и выберем, когда они будут запускаться, в данном случае при каждой фиксации в ветке master.

Затем мы создаем задание и выбираем средство запуска GitHub, в нашем случае — последнюю доступную версию Windows.

actions/checkout@v2 будет клонировать репозиторий, а ilammy/msvc-dev-cmd@v1настроит среду, в которой мы сможем использовать nmake . Наконец, actions/setup-python@v2 настроит среду Python.

Мы используем aqtinstall для установки Qt на машину. В этом примере мы устанавливаем несколько модулей (qtwebengine, qtwebchannel, qtpositioning) вместе с версией Qt 6.2.0 для 64-разрядной версии MSVC 2019. Наконец, мы устанавливаем путь к установке Qt, используя переменную $env:GITHUB_PATH.

Как обычно, мы собираем программу, используя qmake и nmake.

На этом этапе мы создали один двоичный файл. Чтобы развернуть приложение, нам нужно скопировать соответствующие библиотеки, необходимые для выполнения. Мы используем имя инструмента Qt windeployqt. Имейте в виду, что этот инструмент не будет копировать внешние (не Qt) библиотеки, этот шаг необходимо выполнить вручную. Кроме того, мы вручную копируем несколько dll, которые необходимо распространить для обеспечения автономного выполнения (см. раздел https://doc.qt.io/qt-5/windows-deployment.html Создание пакета приложения).

Наконец, мы используем actions/upload-artifact@v1, чтобы загрузить результирующую папку в качестве артефакта Action, который мы сможем загрузить.

MacOS

macos.yml:

name: Build MacOs

on:
  push:
    branches: [master]

jobs:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: '3.8'
      - name: install qt6
        run: |
          pip install aqtinstall
          python3 -m aqt install-qt -m qtwebengine qtwebchannel qtpositioning -O ${{ github.workspace }}/Qt/ mac desktop 6.2.0
          echo ${{ github.workspace }}/Qt/6.2.0/macos/bin/ >> $GITHUB_PATH
      - name: build
        run: |
          qmake6 src/Program.pro
          make
          make clean
          cd build/
          macdeployqt Program.app -always-overwrite
          wget https://raw.githubusercontent.com/arl/macdeployqtfix/master/macdeployqtfix.py
          python2.7 macdeployqtfix.py Program.app/Contents/MacOS/Program ../../Qt/6.2.0/
          hdiutil create -volname Program -srcfolder Program.app -ov -format UDZO Program.dmg

      - name: Mac artefact
        uses: actions/upload-artifact@v1
        with:
          name: MacOsBuild
          path: ./build/Program.dmg

Процедура для MacOs аналогична. В конце компиляции мы используем macdeployqt, чтобы скопировать нужные библиотеки в бандл и задать правильные rpaths. Для внешних зависимостей возможно, что macdeployqt не завершает работу, чтобы исправить это, мы используем macdeployqtfix. Наконец,мы упаковываем приложение как файл dmg.

линукс

Существует несколько способов выпуска пакетов для Linux, в этом примере мы используем формат AppImage, который будет совместим со всеми дистрибутивами Linux.

linux.yml:

name: Build AppImage

on:
  push:
    branches: [master]

jobs:
  job_1:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-python@v2
        with:
          python-version: '3.8'
      - name: install qt6
        run: |
          pip install aqtinstall
          python3 -m aqt install-qt -m qtwebengine qtwebchannel qtpositioning -O ${{ github.workspace }}/Qt/ linux desktop 6.2.0
          echo ${{ github.workspace }}/Qt/6.2.0/gcc_64/bin/ >> $GITHUB_PATH
      - name: build
        run: |
          qmake6 src/Program.pro
          make
          make clean
      - name: appimage
        run: |
          cd build
          wget -O deploy.AppImage https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
          chmod +x deploy.AppImage
          export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${{ github.workspace }}/Qt/6.2.0/gcc_64/lib/
          ./deploy.AppImage Program -appimage -no-translations -bundle-non-qt-libs
          mv Program*.AppImage Program-x86_64.AppImage
      - name: Linux artefact
        uses: actions/upload-artifact@v1
        with:
          name: LinuxBuild
          path: ./build/Program-x86_64.AppImage

Что касается другого, процедура такая же. Мы используем linuxdeployqt для создания файла AppImage в конце перед загрузкой файла в качестве артефакта действия.

Вывод

Настройка CI/CD, которая будет собирать программу Qt в Linux, Windows и MacOs, не очень сложна и приведет к значительной экономии времени. В следующей части серии Qt мы увидим, как создавать исполняемые файлы (автономные и онлайновые) для Windows с помощью Qt Installer Framework и GitHub Actions.