Приложение на Qt5#

Пример собирает Qt5-приложение из исходников и доводит его до установленного и работающего Flatpak. Программа написана здесь же, поэтому пример повторяется целиком, без скачивания чего-либо со стороны.

Qt5-приложения работают на среде org.astra.Qt. Она несёт весь Qt5: libqt5core5a, libqt5gui5, libqt5widgets5, libqt5network5, libqt5svg5, мультимедиа и плагины платформ. Приложение не тащит Qt с собой, поэтому сборка получается небольшой.

Подготовка#

Понадобятся среда выполнения и SDK одной версии:

sudo flatpak install astra-main org.astra.Qt//1.8.6
sudo flatpak install astra-extended org.astra.qtSdk//1.8.6

Дерево примера#

Всё лежит в одном каталоге:

qt5-hello/
|-- qt5-hello.yaml
`-- src/
    |-- CMakeLists.txt
    |-- main.cpp
    |-- ru.example.Qt5Hello.desktop
    |-- ru.example.Qt5Hello.metainfo.xml
    `-- icons/
        `-- 128x128/
            `-- app.png

Имя файла иконки роли не играет: при сборке иконки переименовываются в идентификатор приложения. Достаточно положить любой PNG размером 128 на 128 в каталог icons/128x128.

Исходный код#

src/main.cpp:

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QLabel label("Qt5 внутри Flatpak");
    label.setAlignment(Qt::AlignCenter);
    label.resize(360, 120);
    label.setWindowTitle("Qt5 Hello");
    label.show();
    return app.exec();
}

src/CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(qt5-hello LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)

find_package(Qt5 REQUIRED COMPONENTS Widgets)

add_executable(qt5-hello main.cpp)
target_link_libraries(qt5-hello PRIVATE Qt5::Widgets)

install(TARGETS qt5-hello RUNTIME DESTINATION bin)

src/ru.example.Qt5Hello.desktop:

[Desktop Entry]
Type=Application
Name=Qt5 Hello
Name[ru]=Пример на Qt5
Comment=Минимальное приложение на Qt5
Exec=qt5-hello
Icon=qt5-hello
Terminal=false
Categories=Utility;

Значение Icon при сборке заменяется на идентификатор приложения, а абсолютный путь в Exec сокращается до имени команды, поэтому подгонять их вручную не нужно.

src/ru.example.Qt5Hello.metainfo.xml:

<?xml version="1.0" encoding="UTF-8"?>
<component type="desktop-application">
  <id>ru.example.Qt5Hello</id>
  <metadata_license>CC0-1.0</metadata_license>
  <project_license>MIT</project_license>
  <name>Qt5 Hello</name>
  <summary>Минимальное приложение на Qt5</summary>
  <description>
    <p>Пример приложения на Qt5 для проверки сборки во Flatpak.</p>
  </description>
  <launchable type="desktop-id">ru.example.Qt5Hello.desktop</launchable>
</component>

Манифест#

qt5-hello.yaml:

version: "1.0"

metadata:
  id: ru.example.Qt5Hello
  name: "Qt5 Hello"
  version: "1.0"
  arch: amd64
  branch: stable

runtime:
  id: org.astra.Qt
  version: "1.8.6"
  sdk: org.astra.qtSdk

source:
  type: sourcedir
  sourcedir:
    path: ./src
    buildDeps:
      packages:
        - qtbase5-dev
        - cmake
    buildCommands:
      - cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/app -DCMAKE_BUILD_TYPE=Release
      - cmake --build build -j
      - cmake --install build

files:
  command: qt5-hello
  desktop: ./src/ru.example.Qt5Hello.desktop
  metainfo: ./src/ru.example.Qt5Hello.metainfo.xml
  icons-dir: ./src/icons

permissions:
  sockets: [wayland, fallback-x11]
  devices: [dri]
  shares: [ipc]
  persist: [.config]

export:
  repository: ./repo

Команды сборки выполняются внутри песочницы SDK, в каталоге, куда примонтирован source.sourcedir.path. Рабочим каталогом становится он же, поэтому пути в командах относительные. Сборочные зависимости из buildDeps подкладываются отдельным сысрутом, а пути к ним прописываются в CMAKE_PREFIX_PATH, PKG_CONFIG_PATH, CPATH и LIBRARY_PATH автоматически.

Сборка и установка#

cd qt5-hello
aft-app validate qt5-hello.yaml
sudo aft-app build qt5-hello.yaml

Готовое лежит в ./repo. Установка на этой же машине:

sudo flatpak remote-add --if-not-exists --no-gpg-verify local-repo ./repo
sudo flatpak install -y local-repo ru.example.Qt5Hello
flatpak run ru.example.Qt5Hello

Ключ --no-gpg-verify уместен только для проверки у себя. Для раздачи пользователям репозиторий подписывается, как описано в разделе Репозиторий вендора.

Проверка:

aft-analyzer ru.example.Qt5Hello

Если поставка приходит пакетом#

Готовый deb от поставщика собирается тем же способом, меняется только секция источника. Зависимости разбираются по составу самого пакета, поэтому его не обязано быть в подключённых репозиториях:

source:
  type: local
  local:
    path: ./vendor-qt-app_2.4.0_amd64.deb
    additionalPaths:
      - ./vendor-qt-libs_2.4.0_amd64.deb

dependencies:
  additional: [libqt5sql5-sqlite]

Команду запуска в этом случае берут из desktop-файла внутри пакета, а поля files.desktop, files.metainfo и files.icons-dir можно не указывать: если они есть в пакете, aft-app найдёт их сам.

Для пакета из репозитория Astra секция ещё короче:

source:
  type: repository
  repository:
    package: kcalc

Тонкости Qt5#

Плагин платформы Qt выбирает сам. Для Wayland нужны и сокет wayland, и fallback-x11: часть программ не умеет Wayland и завершается без запасного варианта.

Настройки Qt пишет в ~/.config, поэтому каталог перечисляется в permissions.persist. Без этого настройки теряются между запусками.

Приложениям с базой SQLite нужен драйвер libqt5sql5-sqlite: в среду он не входит и попадает в сборку, только если объявлен зависимостью пакета или дописан в dependencies.additional.

Стиль оформления и тема берутся из среды, а не с хоста. Если приложение выглядит непривычно, обычно не хватает пакета стиля, и он докладывается тем же dependencies.additional.