Новый адрес: MKlimenko.github.io
Для начала: GitLab это git-сервис с открытым исходным кодом. Около года назад, когда я спросил о наличии каких-либо развёрнутых систем контроля версий, админы дали мне доступ к нашему серверу git. Достаточно долго я использовал лишь малую часть его возможностей, в основном просто push, чтобы сохранить проделанную работу. Однако, этому было суждено измениться. Сейчас я работаю над достаточно сложным проектом, который включает в себя несколько типов программных продуктов (программы для DSP и ARM, API, графическое приложение), которые в свою очередь требуют множество сред и тулчейнов для сборки. И после того как пришлось ждать три часа, пока скачается и установится Qt (привет корпоративным прокси!), я решил, что было бы здорово настроить build-сервер, который бы при каждом новом коммите стягивал последние исходники и собирал их. Беглое гугление рассказало про Jenkins, но в тот день мне было лениво его настраивать. Позднее в тот же день я зашел в веб-интерфейс нашего git и один пункт меню приковал моё внимание: “Builds”. Если не вдаваться в детали, это интегрированный планировщик задач, который запускается при каждом новом коммите (а так же merge request).
Для начала: 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.
Билды под windows - больная тема, очень полезная статья.
ReplyDeleteМожет быть есть какая-то возможность в гитлабе комбинировать разные среды сборки? Чтобы одни проекты собирались в windows, другие в linux. А ещё лучше чтобы один и тот же проект собирался разными компиляторами: mingw, win32, gcc.
Вообще, для кросс-платформенной сборки лучше держать CMake-проекты, там это наиболее безболезненно идёт. Для запуска сборки на разных серверах надо в gitlab-ci скрипте указать теги двух (и более) разных runner-ов, один из которых будет крутиться на Windows-сервере, а второй — на Linux.
DeleteЕсли все компиляторы есть под Windows и VS, тогда задача упрощается до минимума и передачи нужных ключей в MSBuild