Files
BiLauncher/doc/build-and-release.md
galeon 47d30b1594
tests / windows (push) Failing after 8m58s
tests / linux (push) Successful in 1m58s
tests / macos (push) Successful in 1m18s
tests / package-smoke-linux (push) Skipped
tests / package-smoke-windows (push) Skipped
tests / package-smoke-macos (push) Skipped
releases fixes
Signed-off-by: galeon <dertiellis@gmail.com>
2026-10-24 23:16:35 +03:00

221 lines
16 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Сборка, упаковка и релизы
## Что нужно
- CMake 3.20+, компилятор C++17 и C (C нужен для zlib на Linux).
- Qt 6.8 или новее (`qt_standard_project_setup(REQUIRES 6.8)`). CI собирает на Qt 6.11.1.
- Обязательные модули: `Quick`, `QuickControls2`, `Qml`, `Svg`, `Core`, `CorePrivate`, `Gui`,
`Network`.
- Необязательный: `WebEngineQuick`, для входа через Microsoft.
`CorePrivate` нужен ради `QZipReader` и `QZipWriter`: ими распаковываются нативные библиотеки
LWJGL, архивы Temurin и архивы сборок. Приватные модули Qt не гарантируют совместимость между
версиями, поэтому проект привязан к конкретной версии Qt. Предупреждение об этом отключено
(`QT_NO_PRIVATE_MODULE_WARNING`).
### Qt WebEngine
Модуль ставится в MaintenanceTool отдельной галочкой и тянет за собой Qt WebChannel и Qt
Positioning. Чтобы он работал, нужны все три.
Если сделать WebEngine обязательным, у любого, кто его не поставил, проект вообще не соберётся,
хотя офлайн-вход и Ely.by без него работают. Поэтому:
- модуль найден — определяется `LAUNCHER_HAS_WEBENGINE`, `MicrosoftLoginDialog.qml` попадает в
модуль, `backend.microsoftAvailable` равно `true`;
- не найден — CMake выдаёт предупреждение со списком компонентов, которые надо доставить, а
лаунчер собирается без входа через Microsoft.
Релизные сборки в CI всегда с WebEngine: скрипты подготовки раннеров проверяют, что он есть.
## Локальная сборка
```bash
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=$HOME/Qt/6.11.1/macos
```
```bash
cmake --build build
```
Из Qt Creator проект открывается как обычный CMake-проект.
### Версия и канал сборки
В репозитории хранится только число: `project(BiLauncher VERSION x.y.z)` в `CMakeLists.txt`. Оно
одинаковое во всех ветках, поэтому merge `dev` → `rc` → `master` версию не перетирает и не даёт
конфликтов. `PROJECT_VERSION` идёт в ресурс версии `.exe`, в `Info.plist` и в установщик: все три
принимают только числовую версию.
Канал (dev / rc / релиз) в коде не записан — его на каждой сборке вычисляет
`cmake/LauncherVersion.cmake` и пишет в сгенерированный `<build>/generated/launcherversion.h`
(`LAUNCHER_VERSION`, `LAUNCHER_CHANNEL`). Порядок определения:
1. `-DLAUNCHER_BUILD_VERSION=1.0.1-rc2` — полная версия от CI; база обязана совпадать с
`project()`, иначе configure падает;
2. тег на HEAD: `vx.y.z` — релиз, `vx.y.z-rcN` — rc;
3. ветка (из `GITHUB_HEAD_REF`/`GITHUB_REF_NAME` или git): `master` — релиз, `rc` и `beta` — rc;
4. любая другая ветка или сборка без git — dev.
| Сборка | `LAUNCHER_VERSION` | В окне |
|---------------------------|----------------------|-----------------|
| релиз (master, `vx.y.z`) | `1.0.1` | `Версия: 1.0.1` |
| rc из CI (`vx.y.z-rcN`) | `1.0.1-rc2` | + бейдж RC |
| rc локально | `1.0.1-rc` | + бейдж RC |
| dev | `1.0.1-dev+a1b2c3d` | + бейдж DEV |
У dev-сборки после `+` — короткий хэш коммита, `.dirty` — есть незакоммиченные правки в
отслеживаемых файлах. Генерация идёт на каждой сборке, так что после `git checkout` другой
ветки reconfigure не нужен.
Полная строка уходит в `QCoreApplication::applicationVersion`, в аргументы запуска игры и в
подпись «Версия: …» в левом верхнем углу окна; бейдж канала QML берёт из её суффикса. Почему так,
см. [ADR-0002](adr/0002-launcher-version-display.md).
**Когда поднимать версию.** Номер поднимается в `dev` в начале цикла (сразу после релиза) и
дальше приходит в `rc` и `master` через merge. Хотфикс прямо в `rc` или `master` — правка и bump
patch там же, затем обратный merge `master` → `rc` → `dev`.
## Что собирается
**`BiLauncher`** — исполняемый файл и QML-модуль с URI `BiLauncher`. В модуль входят все `.cpp`,
`.qml`, картинки из `images/`, `i18n/translations.json`, а также `CHANGELOG.md`, `LICENSE` и
`README.md`. Последние три сейчас никто из кода не читает, они просто лежат в ресурсах.
QML-модуль собирается в `<build>/qml/BiLauncher` (`OUTPUT_DIRECTORY`). Если оставить по
умолчанию, на Linux папка `BiLauncher` совпадёт по имени с исполняемым файлом (у него нет
расширения), и линковка упадёт с «Is a directory».
**`launcher_zlib_reference`** — только на Linux. Это обычный zlib 1.3.1 из каталога `zlib/`,
выходной файл `libz.so.1` в `<build>/zlib/`. С ним лаунчер не линкуется. Библиотека нужна только
установщикам Forge и NeoForge на системах с zlib-ng, см. [zlibreference.h](cpp/zlibreference.md).
Исходники zlib — чужой код из upstream, документацией он не покрыт.
## Иконки
Все размеры собираются из одного файла `icons/master/icon_master.png` (1024×1024, рисунок до краёв
холста) скриптом `icons/generate_icons.sh`. Для него нужны ImageMagick и `iconutil`, то есть
запускается он на macOS. Правки вносятся в мастер, после чего скрипт перезапускается. Отдельные
размеры руками не правятся.
Системы по-разному добавляют поля вокруг иконки, поэтому один и тот же рисунок кладётся
по-разному:
- **macOS** сама поля не добавляет. По сетке Apple рисунок занимает 824 из 1024 точек, углы
скруглены радиусом 185.4. Результат — `icon.icns`, кладётся в `Contents/Resources` бандла.
- **Windows** ждёт картинку на весь холст. `icon.ico` содержит кадры 16–256, включая 20, 40 и 96
для масштабов 125/150/200%. Без явного списка ImageMagick положил бы в `.ico` только 1024×1024,
и система размывала бы иконку при уменьшении. Вкомпилирована через `icon.rc.in`, где заодно
ресурс версии.
- **Linux**: PNG 16–512 ставятся в тему `hicolor` под именем `bilauncher.png`, плюс
`bilauncher.desktop`. Окружения рабочего стола ищут иконку по имени из `Icon=`, а не по имени
файла.
Иконка окна задаётся в `main.cpp` из ресурса `:/icons/` (на всех системах, кроме macOS).
## Установка (`cmake --install`)
- исполняемый файл в `bin/` (на macOS — `BiLauncher.app`);
- `qt_generate_deploy_qml_app_script` раскладывает рядом Qt, плагины и QML-модули
(windeployqt/macdeployqt под капотом; на macOS с `-hardened-runtime`);
- `LICENSE`, `CHANGELOG.md`, `packaging/THIRD_PARTY_LICENSES.txt` в `share/doc/BiLauncher/` (кроме
macOS);
- на Linux ещё `libz.so.1` в `lib/BiLauncher/`, иконки и `.desktop`.
На Linux ставьте с `-DCMAKE_INSTALL_LIBDIR=lib`. Лаунчер ищет эталонный zlib в
`<bin>/../lib/BiLauncher`, а на Ubuntu по умолчанию `LIBDIR` был бы `lib/x86_64-linux-gnu`.
## Релизы
Релизы собирает Gitea Actions, `.gitea/workflows/release.yml`.
### Как выпустить версию
0. Запустить workflow `tests` вручную (Run workflow) и дождаться зелёного прогона на всех трёх
системах, включая дымовую проверку установленного дерева. `release.yml` от тестов не зависит,
поэтому этот шаг на совести выпускающего. См. [testing.md](testing.md).
1. Поднять версию в `project(BiLauncher VERSION ...)` в `CMakeLists.txt`.
2. Добавить в `CHANGELOG.md` раздел `## [x.y.z] — дата`. Его текст станет описанием релиза.
Для пре-релиза можно завести отдельный раздел `## [x.y.z-rcN]`: он берётся в первую очередь,
а если его нет — используется `## [x.y.z]`.
3. Запустить релиз одним из способов:
- **Пуш в `master`** — полноценный релиз `vx.y.z`. Если релиз или тег с этой версией уже есть,
прогон ничего не собирает: сначала поднимите версию.
- **Пуш в `rc`** — пре-релиз `vx.y.z-rcN`, где `N` — следующий свободный номер для этой версии
(`rc1`, `rc2`, ...).
- **Тег `vx.y.z`** — полноценный релиз, **тег `vx.y.z-rcN`** — пре-релиз. Пре-релизом
становится только тег с суффиксом `-rc`, любой другой суффикс даёт обычный релиз.
Если тег не совпадает с версией в `CMakeLists.txt` (без учёта суффикса), прогон сразу падает.
Для веток тег создаёт сам Gitea при публикации релиза, на коммите прогона. Этот тег снова
запускает `release.yml`, но прогон видит, что релиз уже есть, и ничего не собирает.
### Что происходит
1. **create-release** (Linux) — определяет тег (из пуша тега или по ветке), сверяет его с версией, вырезает раздел из `CHANGELOG.md` и
создаёт **черновик** релиза.
2. Параллельно три сборки, каждая прикладывает свои файлы к черновику:
- **Linux**: `BiLauncher-<v>-x86_64.AppImage` и `BiLauncher-<v>-linux-x86_64.tar.gz`. Сборка
идёт с `-j 8`: на ВМ 6 ГБ памяти, и без ограничения компиляторы съедают её всю.
- **Windows**: `BiLauncher-<v>-win64-setup.exe` (Inno Setup) и
`BiLauncher-<v>-win64-portable.zip`. В portable нет `vc_redist`, среда выполнения MSVC должна
уже стоять в системе. Сборка идёт в `C:\r\...`, потому что дерево WebEngine легко выходит за
`MAX_PATH`. Zip делается системным `tar.exe` по полному пути: GNU tar из Git, который стоит в
`PATH` раньше, zip не умеет и принимает `C:` за имя удалённого хоста.
- **macOS**: `BiLauncher-<v>-macOS-universal.dmg` (arm64 + x86_64). Подпись ad-hoc: без неё
приложение вообще не запустится на Apple Silicon. Developer ID нет, поэтому Gatekeeper при
первом запуске всё равно спросит подтверждение.
3. **publish** собирает `SHA256SUMS.txt` из хешей всех трёх сборок, прикладывает его и снимает с
релиза флаг черновика.
Если хоть одна сборка упала, релиз остаётся черновиком и пользователи его не видят.
Ручной запуск (`workflow_dispatch`) делает те же сборки, но релиз не создаёт: файлы остаются
артефактами прогона.
Секрет `RELEASE_TOKEN` — персональный токен Gitea с правом `repository: write`.
### Установщик Windows
`packaging/windows/BiLauncher.iss` (Inno Setup 6). Ставит в `Program Files\BiLauncher`, разрешает
выбрать установку только для текущего пользователя, создаёт ярлык в меню «Пуск» и, по желанию, на
рабочем столе, тихо ставит `vc_redist`, если он есть в дереве. Языки установщика — русский и
английский.
`AppId` менять нельзя: по нему новая версия находит и обновляет старую установку.
## Раннеры
Раннеры работают в режиме host, то есть прямо на машине, без Docker. Метки: `linux`, `windows`,
`macos`.
Пути к Qt раннер передаёт сборке через переменные окружения в своём `config.yaml`:
- `QT_ROOT` — kit Qt (например, `~/Qt/6.11.1/gcc_64`);
- `QT_TOOLS` — папка `Tools` из Qt Online Installer, оттуда CMake и Ninja;
- `ISCC_DIR` — только Windows, папка Inno Setup.
Qt с WebEngine, CMake и Ninja ставятся заранее через Qt Online Installer. Скрипты подготовки
докачивают остальное и регистрируют раннер. Повторный запуск безопасен.
**Linux** (Ubuntu 22.04), `ci/setup-runner-linux.sh [токен]`. Запускать от пользователя, которому
принадлежит Qt, нужен sudo без пароля. Ставит компилятор, библиотеки для сборки и деплоя (xcb,
OpenGL, NSS и т. д.), `libfuse2` для appimagetool, Node.js (нужен `actions/checkout`), appimagetool,
gitea-runner и systemd-сервис `gitea-runner`.
**Windows**, `ci/setup-runner-windows.ps1 [-Token ...]` из PowerShell от администратора. Ставит
VS 2022 Build Tools (это 20–40 минут), Git, Node.js, Inno Setup, включает длинные пути в системе и
в git, регистрирует gitea-runner. Раннер запускается задачей планировщика при входе пользователя,
поэтому пароль учётной записи не нужен, но без входа в систему раннер не поднимется. Чтобы он
стартовал при загрузке машины, задачу нужно пересоздать с `/sc onstart /rp *`.
**macOS** — скрипта подготовки нет, раннер настроен вручную.
Те же раннеры гоняют автотесты (`.gitea/workflows/tests.yml`): Linux — на каждый push, все три
системы — ночью и по кнопке. Подробности — [testing.md](testing.md).
---
При создании этого документа использовался ИИ.