#!/bin/bash # # Сборка nlve. # # ./build.sh редактор под эту систему # ./build.sh current то же самое # ./build.sh windows редактор под Windows (кросс-сборка) # ./build.sh tool консольный инструмент проверок # ./build.sh macos две сборки под macOS: nlve_intel и nlve_arm # ./build.sh test инструмент плюс прогон проверок # ./build.sh all всё перечисленное # ./build.sh run собрать под эту систему и запустить # ./build.sh clean убрать промежуточные файлы сборки # # Тулчейн берётся из fpcupdeluxe, а не из системы. Это не придирка: # системный Lazarus другой версии, и собранные им модули LCL с нашими # несовместимы — сборка падает на ровном месте. set -u HERE=$(cd "$(dirname "$0")" && pwd) FPCUP=${FPCUP:-/home/chaiman/fpcupdeluxe} LAZBUILD="$FPCUP/lazarus/lazbuild" LAZCONF="$FPCUP/config_lazarus" # Компилятор нужен напрямую для консольных проверок без формы. FPC="$FPCUP/fpc/bin/x86_64-linux/fpc.sh" # Собранный виджетсет только один — gtk2. Ни qt5, ни gtk3 в этом # тулчейне нет, подставлять их бессмысленно. LCL_LINUX=gtk2 # Под Windows виджетсет называется win32 и работает в том числе на 64 битах: # это имя интерфейса, а не разрядности. LCL_WINDOWS=win32 status=0 fail() { echo "ОШИБКА: $*" >&2 exit 1 } note() { echo echo "=== $* ===" } check_toolchain() { [ -x "$LAZBUILD" ] || fail "не найден lazbuild: $LAZBUILD Задайте другой корень через переменную FPCUP, например: FPCUP=/путь/к/fpcupdeluxe ./build.sh" } # Из вывода lazbuild интересны только ошибки и итог. Подсказок о # неиспользованных параметрах там сотни, и за ними не видно главного. run_lazbuild() { local title=$1 local rc shift note "$title" "$LAZBUILD" --primary-config-path="$LAZCONF" "$@" 2>&1 \ | grep -viE "^Hint: \(lazbuild\)|^Hint: \(lazarus\)|Start of reading config|End of reading config" \ | grep -iE "error|fatal|warning|Linking|lines compiled|Compiling package" # Код возврата берём у lazbuild, а не у grep: grep возвращает 1 просто # потому, что ничего не нашёл, и это не ошибка сборки. # # PIPESTATUS читается сразу же и в переменную. Любая следующая команда # его затирает — даже двоеточие. На этом скрипт уже один раз соврал: # сборка падала, а он докладывал «готово». rc=${PIPESTATUS[0]} return "$rc" } # Номер сборки. Растёт на единицу при каждой сборке редактора и попадает # в заголовок окна. # # Зачем: по заголовку сразу видно, та ли это сборка, где правка уже есть. # Без него человек проверяет старым двоичным файлом и видит прежнее # поведение — так уже случалось, и время ушло на выяснение, у кого что # не работает. # # Счётчик лежит рядом с исходниками, но в репозиторий не входит: он про # эту машину, а не про историю проекта. bump_version() { local file="$HERE/build.number" n n=0 [ -f "$file" ] && n=$(cat "$file" 2>/dev/null || echo 0) case "$n" in ''|*[!0-9]*) n=0 ;; esac n=$((n + 1)) echo "$n" > "$file" cat > "$HERE/src/uBuildInfo.inc" <&2 status=1 fi } build_windows() { check_toolchain if run_lazbuild "Редактор под Windows (x86_64)" \ --cpu=x86_64 --os=win64 --ws="$LCL_WINDOWS" "$HERE/nlve.lpi"; then echo "готово: $HERE/nlve.exe" # Печатаем, что именно получилось: перепутать разрядность легко, а # заметить это без запуска под Windows нечем. file "$HERE/nlve.exe" 2>/dev/null | cut -d: -f2- | sed 's/^/ /' else echo "не собралось" >&2 status=1 fi # Кросс-сборка оставляет модули для Windows в том же каталоге, что и # родные. Следующая сборка под Linux их не тронет и возьмёт как свои, # после чего компоновщик выдаст непонятную ошибку. Поэтому чистим. rm -rf "$HERE/lib/x86_64-win64" } build_macos() { check_toolchain # Сборка под macOS кладёт файл туда же, куда и сборка под Linux, и # затирает её: имя цели в проекте одно на все системы. Поэтому каждый # файл переименовывается сразу, а линуксовая сборка в конце делается # заново. if run_lazbuild "Редактор под macOS (Intel)" \ --cpu=x86_64 --os=darwin --ws=cocoa "$HERE/nlve.lpi"; then mv -f "$HERE/nlve" "$HERE/nlve_intel" echo "готово: $HERE/nlve_intel" file "$HERE/nlve_intel" 2>/dev/null | cut -d: -f2- | sed 's/^/ /' else echo "не собралось" >&2 status=1 fi if run_lazbuild "Редактор под macOS (Apple Silicon)" \ --cpu=aarch64 --os=darwin --ws=cocoa "$HERE/nlve.lpi"; then mv -f "$HERE/nlve" "$HERE/nlve_arm" echo "готово: $HERE/nlve_arm" file "$HERE/nlve_arm" 2>/dev/null | cut -d: -f2- | sed 's/^/ /' else echo "не собралось" >&2 status=1 fi # Обёртку .app делает lazbuild, и внутри неё ссылка на файл с именем # nlve, которого после переименования уже нет. Обманчивая пустышка не # нужна. rm -rf "$HERE/nlve.app" # Модули под darwin лежат отдельно, но сборку под Linux мы затёрли — # возвращаем её на место. note "Возвращаю сборку под эту систему" build_current echo echo "ВНИМАНИЕ: под macOS предпросмотра не будет — встраивание mpv" echo "написано под X11 и Windows. Подробности в BACKLOG.md." } build_tool() { note "Консольный инструмент проверок" if "$HERE/tests/build.sh"; then : else echo "не собралось" >&2 status=1 fi } run_tests() { build_tool [ "$status" -eq 0 ] || return note "Проверки уплощения монтажа" if "$HERE/tests/nlvetool" flattest; then echo "проверки пройдены" else echo "проверки не пройдены" >&2 status=1 fi # Свойства, записанные в файлах форм, проверяются по сведениям о типах. # Файл формы разбирается при запуске, а не при сборке: опечатка в имени # свойства даёт не ошибку компиляции, а падение окна на старте. note "Проверка свойств из файлов форм" if "$LAZBUILD" --primary-config-path="$LAZCONF" \ "$HERE/tests/lfmcheck/lfmcheck.lpi" >/dev/null 2>&1; then if "$HERE/tests/lfmcheck/lfmcheck"; then : else status=1 fi # Окно зависимостей при создании записывает рядом с собой список # пакетов по умолчанию. Проверке это не мешает, а в дереве исходников # такому файлу не место. rm -f "$HERE/tests/lfmcheck/deps-linux.json" else echo "не собралось" >&2 status=1 fi # Ход полоски выполнения проверяется отдельной программой: расчёт вынесен # в uAppTypes именно затем, чтобы его можно было прогнать числами. note "Проверка хода полоски выполнения" if "$FPC" -Fu"$HERE/src" -FE"$HERE/tests/progress" \ -o"$HERE/tests/progress/progtest" \ "$HERE/tests/progress/progtest.lpr" >/dev/null 2>&1; then if "$HERE/tests/progress/progtest"; then : else status=1 fi else echo "не собралось" >&2 status=1 fi } do_clean() { note "Уборка" rm -rf "$HERE/lib" "$HERE/tests/lib" rm -f "$HERE/nlve.dbg" echo "убраны промежуточные файлы сборки" echo "готовые двоичные файлы (nlve, nlve.exe, tests/nlvetool) оставлены" } case "${1:-current}" in current|linux|"") build_current ;; windows|win|win64) build_windows ;; macos|mac|darwin) build_macos ;; tool) build_tool ;; test|tests) run_tests ;; all) build_current build_windows run_tests ;; run) build_current [ "$status" -eq 0 ] || exit 1 note "Запуск" exec "$HERE/nlve" ;; clean) do_clean ;; -h|--help|help) # Печатаем шапку файла до первой строки, которая уже не комментарий. awk 'NR>2 { if ($0 !~ /^#/) exit; sub(/^# ?/, ""); print }' "$0" ;; *) fail "неизвестная цель: $1 Доступны: current, windows, macos, tool, test, all, run, clean" ;; esac echo if [ "$status" -eq 0 ]; then echo "ИТОГ: без ошибок" else echo "ИТОГ: были ошибки" fi exit "$status"