Автоматизированная сборка C++ проектов в Gitlab CI

Для начала: GitLab это git-сервис с открытым исходным кодом. Около года назад, когда я спросил о наличии каких-либо развёрнутых систем контроля версий, админы дали мне доступ к нашему серверу git. Достаточно долго я использовал лишь малую часть его возможностей, в основном просто push, чтобы сохранить проделанную работу. Однако, этому было суждено измениться. Сейчас я работаю над достаточно сложным проектом, который включает в себя несколько типов программных продуктов (программы для DSP и ARM, API, графическое приложение), которые в свою очередь требуют множество сред и тулчейнов для сборки. И после того как пришлось ждать три часа, пока скачается и установится Qt (привет корпоративным прокси!), я решил, что было бы здорово настроить build-сервер, который бы при каждом новом коммите стягивал последние исходники и собирал их. Беглое гугление рассказало про Jenkins, но в тот день мне было лениво его настраивать. Позднее в тот же день я зашел в веб-интерфейс нашего git и один пункт меню приковал моё внимание: “Builds”. Если не вдаваться в детали, это интегрированный планировщик задач, который запускается при каждом новом коммите (а так же merge request).

Чтобы начать использовать CI (continuous integration), необходимо всего-либо расположить в корне репозитория один файл. Он предоставляет много возможностей, например, произвести В, только если А пройдёт успешно/неуспешно и т.д. Я не слишком серьезно настроил эти скрипты, в моём случае перед сборкой скачиваются подмодули для получения последних версий библиотек, после чего осуществляется сборка. Если сборка провалилась, автор коммита получает письмо на почту, что он сломал билд. Когда я тестировал различные возможности CI, я получал по 50 писем в час (простите, админы).

В сети много примеров содержимого файла .gitlab-ci.yml для популярных языков, однако я не нашёл пример для проектов Visual Studio (кроме C#, но это другая песня) или Qt. Если вы пришли сюда за этим, надеюсь вам это поможет.

MSBuild:

 Job_name:  
  script:  
  - 'setlocal'  
  - 'chcp 65001'  
  - 'call "%VS120COMNTOOLS%..\..\vc\vcvarsall.bat" x86_amd64'  
  - 'msbuild.exe make\vs120\Project_name.sln /t:Rebuild /p:Configuration=Release /p:Platform="x64" /m'  
  - 'if not exist "%BUILDS%\Project_name" (mkdir "%BUILDS%\Project_name")'  
  - 'copy make\vs120\x64\Release\Project_name.exe "%BUILDS%\Project_name"'  
  • Строка “Job_name:” является обязательной и обозначает, как будет называться задача runner-а. Также под этим именем она будет отображена в веб-интерфейсе.
  • ”- ‘chcp 65001’” необходмо для корректного отображения кириллицы, печатаемой при выводе MSBuild.
  • ”- ‘call “%VS120COMNTOOLS%....\vc\vcvarsall.bat” x86_amd64’” добавляет необходимые переменные окружения чтобы cmd нашёл MSBuild, компилятор и т.д.

Последние две строчки помогают мне всегда иметь в собранном виде последнюю версию программ. Это очень помогает, когда кому-то требуется что-то из моих разработок.

Достаточно просто, да? Давайте перейдём к более интересным вещам, а в частности проектам из Qt.

Another_Job_name:  
  script:  
  - 'setlocal'  
  - 'chcp 65001'  
  - 'call "%VS120COMNTOOLS%..\..\vc\vcvarsall.bat" x86_amd64'  
  - 'cd make\qt5'  
  - 'call "%QT_ROOT_x86_64%\bin\qmake.exe" Qt_project.pro -r -spec win32-msvc2013'  
  - 'call "%QT_CREATOR%\bin\jom.exe" -f Makefile.Release'   
  - 'rd /s/q deploy'  
  - 'mkdir deploy'  
  - 'copy release\Qt_project.exe deploy'  
  - 'set curr_dir=%cd%'  
  - 'cd /d "%QT_ROOT_x86_64%\bin"'  
  - 'windeployqt.exe "%curr_dir%\deploy\Qt_project.exe" -no-translations'  
  - 'cd /d %curr_dir%'  
  - 'if not exist "%BUILDS%\Qt_project" (mkdir "%BUILDS%\Qt_project")'  
  - 'xcopy /s /y deploy "%BUILDS%\Qt_project"'  

Вот это уже интереснее. Несколько схожих команд, затем вызывается qmake для генерации makefile-ов из файла проекта .rpo, а затем jom (многопоточный make) производит сборку Release-версии.

Приложения, написанные в Qt требуют множества библиотек во время работы, соответственно для распространения нам необходимо, чтобы они все находились в директории с программой. Вместе с Qt поставляется утилита windeployqt, которая анализирует исполняемый файл и кладёт все его зависимости рядом с ним. До сих пор не понимаю почему, но мне не удалось заставить её работать без смены директории (ругалась на Python2.7), хотя какая разница. xcopy используется для копирования всего содержимого внутренней директории в каталог с общим доступом.

Осмысление того, как всё необходимо осуществлять с qmake, jom и windeployqt заняло некоторое время, но опять же, ничего слишком сложного. А теперь я вам представляю скрипт для сборки проектов под ARM.

 ARM_project_job:  
  script:  
  - 'setlocal'  
  - 'chcp 65001'  
  - 'set command=""%DS-5_DIR%\sw\eclipse\eclipsec.exe" -nosplash --launcher.suppressErrors -application org.eclipse.cdt.managedbuilder.core.headlessbuild -data "%ARM_WORKSPACE%" -import make\eclipse\arm_project -cleanBuild arm_project"'   
  - 'echo "%command%" | "%DS-5_DIR%\bin\cmdsuite.exe" 2> error.txt'  
  - 'for %%A in (error.txt) do set fileSize=%%~zA'  
  - 'del /f /q error.txt'   
  - 'if not %fileSize%==0 (exit /b 1)'  
  - 'if not exist "%BUILDS%\arm_project" (mkdir "%BUILDS%\arm_project")'  
  - 'copy make\eclipse\arm_project\Release\arm_project.axf "%BUILDS%\arm_project"'  

Самая интересная часть тут это перенаправление вывода %command% в cmdsuite.exe. Cmdsuite это командная строка DS-5, т.н. batch job, в котором происходит некоторая внутренняя магия с лицензиями и конфигурированием баз данных. Я называю это магией в связи с тем, что мне не удалось экспортировать все переменные окружения и настройки в основную командную строку. Вопрос в том, как передать команду в созданную командную строку из родителя? Каким-то образом это работает через символ |, т.н. pipe. Сама по себе команда — это просто вызов Eclipse без логотипа с командой для сборки проекта в режиме командной строки. Внимание. Если у вас в workspace уже имеется одноимённый проект, вы не сможете его импортировать и собрать. После этого я осуществляю переадресацию вывода ошибок сборки в текстовый файл с последующим чтением в основном потоке (командной строке). Это необходимо в связи с тем, что вывод batch job подавлен и недоступен для анализа из gitlab CI. Если файл не пуст, принимается решение о наличии ошибок и возвращается код 1, что отмечает коммит, как не прошедший сборку. Иначе в общую директорию кладётся новейшая программа под ARM.


© 2022. All rights reserved.

Powered by Hydejack v9.1.6