2026-10-11 22:32:13 +03:00
|
|
|
|
# Сборка, упаковка и релизы
|
|
|
|
|
|
|
|
|
|
|
|
## Что нужно
|
|
|
|
|
|
|
|
|
|
|
|
- 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-проект.
|
|
|
|
|
|
|
2026-10-23 09:55:15 +03:00
|
|
|
|
Версия приложения задаётся в начале `CMakeLists.txt` двумя значениями:
|
|
|
|
|
|
|
|
|
|
|
|
- `project(BiLauncher VERSION x.y.z)` — только числа. Отсюда `PROJECT_VERSION` идёт в ресурс версии
|
|
|
|
|
|
`.exe`, в `Info.plist` и в установщик: все три принимают только числовую версию.
|
|
|
|
|
|
- `LAUNCHER_VERSION_SUFFIX` — метка пре-релиза, например `-dev` или `-rc1`. Для релиза пустая.
|
|
|
|
|
|
|
|
|
|
|
|
Полная строка `LAUNCHER_VERSION` = `PROJECT_VERSION` + суффикс (`1.0.1-dev`) уходит дефайном в код:
|
|
|
|
|
|
в `QCoreApplication::applicationVersion`, в аргументы запуска игры и в подпись «Версия: …» в левом
|
|
|
|
|
|
верхнем углу окна. Почему так, см. [ADR-0002](adr/0002-launcher-version-display.md).
|
2026-10-11 22:32:13 +03:00
|
|
|
|
|
|
|
|
|
|
## Что собирается
|
|
|
|
|
|
|
|
|
|
|
|
**`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`.
|
|
|
|
|
|
|
|
|
|
|
|
### Как выпустить версию
|
|
|
|
|
|
|
2026-10-12 13:14:08 +03:00
|
|
|
|
0. Запустить workflow `tests` вручную (Run workflow) и дождаться зелёного прогона на всех трёх
|
|
|
|
|
|
системах, включая дымовую проверку установленного дерева. `release.yml` от тестов не зависит,
|
|
|
|
|
|
поэтому этот шаг на совести выпускающего. См. [testing.md](testing.md).
|
2026-10-11 22:32:13 +03:00
|
|
|
|
1. Поднять версию в `project(BiLauncher VERSION ...)` в `CMakeLists.txt`.
|
|
|
|
|
|
2. Добавить в `CHANGELOG.md` раздел `## [x.y.z] — дата`. Его текст станет описанием релиза.
|
2026-10-23 10:45:27 +03:00
|
|
|
|
3. Запустить релиз одним из способов:
|
|
|
|
|
|
- **Пуш в `master`** — полноценный релиз `vx.y.z`. Если релиз или тег с этой версией уже есть,
|
|
|
|
|
|
прогон ничего не собирает: сначала поднимите версию.
|
|
|
|
|
|
- **Пуш в `rc`** — пре-релиз `vx.y.z-rcN`, где `N` — следующий свободный номер для этой версии
|
|
|
|
|
|
(`rc1`, `rc2`, ...).
|
|
|
|
|
|
- **Тег `vx.y.z`** — полноценный релиз, **тег `vx.y.z-rcN`** — пре-релиз. Пре-релизом
|
|
|
|
|
|
становится только тег с суффиксом `-rc`, любой другой суффикс даёт обычный релиз.
|
2026-10-11 22:32:13 +03:00
|
|
|
|
|
|
|
|
|
|
Если тег не совпадает с версией в `CMakeLists.txt` (без учёта суффикса), прогон сразу падает.
|
|
|
|
|
|
|
2026-10-23 10:45:27 +03:00
|
|
|
|
Для веток тег создаёт сам Gitea при публикации релиза, на коммите прогона. Этот тег снова
|
|
|
|
|
|
запускает `release.yml`, но прогон видит, что релиз уже есть, и ничего не собирает.
|
|
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
### Что происходит
|
|
|
|
|
|
|
2026-10-23 10:45:27 +03:00
|
|
|
|
1. **create-release** (Linux) — определяет тег (из пуша тега или по ветке), сверяет его с версией, вырезает раздел из `CHANGELOG.md` и
|
2026-10-11 22:32:13 +03:00
|
|
|
|
создаёт **черновик** релиза.
|
|
|
|
|
|
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** — скрипта подготовки нет, раннер настроен вручную.
|
|
|
|
|
|
|
2026-10-12 13:14:08 +03:00
|
|
|
|
Те же раннеры гоняют автотесты (`.gitea/workflows/tests.yml`): Linux — на каждый push, все три
|
|
|
|
|
|
системы — ночью и по кнопке. Подробности — [testing.md](testing.md).
|
|
|
|
|
|
|
2026-10-11 22:32:13 +03:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
При создании этого документа использовался ИИ.
|