みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

meta-qt6を試す

はじめに

Qt 6 in OpenEmbedded and Yoctoが気になったので試してみる。

ここを見る限りまだdevっぽい。

meta-qt6を覗いてみる

layer.conf

...(snip)...

LAYERDEPENDS_qt6-layer = "core"

LAYERSERIES_COMPAT_qt6-layer = "zeus dunfell gatesgarth"
...(snip)...

依存はcoreのみ。

互換性はzeusdunfellgatesgarth。まぁ妥当なところか。

recipes-qt

treeコマンドの結果(patchは除外)

.
├── meta
│   └── meta-toolchain-qt6.bb
├── packagegroups
│   ├── nativesdk-packagegroup-qt6-toolchain-host.bb
│   ├── packagegroup-qt6-modules.bb
│   └── packagegroup-qt6-toolchain-target.bb
└── qt6
    ├── qt3d_git.bb
    ├── qt5compat_git.bb
    ├── qt6-git.inc
    ├── qt6.inc
    ├── qtbase
    ├── qtbase_git.bb
    ├── qtcoap_git.bb
    ├── qtdeclarative_git.bb
    ├── qtgraphicaleffects_git.bb
    ├── qtimageformats_git.bb
    ├── qtmqtt_git.bb
    ├── qtnetworkauth_git.bb
    ├── qtopcua_git.bb
    ├── qtquick3d
    ├── qtquick3d_git.bb
    ├── qtquickcontrols2_git.bb
    ├── qtquicktimeline_git.bb
    ├── qtserialbus_git.bb
    ├── qtserialport_git.bb
    ├── qtshadertools_git.bb
    ├── qtspeech_git.bb
    ├── qtsvg_git.bb
    ├── qttools_git.bb
    ├── qttranslations_git.bb
    ├── qtvirtualkeyboard_git.bb
    ├── qtwayland
    ├── qtwayland_git.bb
    └── qtwebsockets_git.bb

meta-qt5にはあったqtsmarthomeなどのexamplesは今のところ無い。これから生えてくるのだろうか。

QPAプラットフォームの設定

QtをYoctoで使用するといつもついてくるQPAプラットフォームの指定。結構分かりづらいのでいつも何かしら手を入れることになる。

qtbase_git.bbを覗いてみる。

# Default platform plugin
QT_QPA_DEFAULT_PLATFORM ?= "${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'xcb', \
    bb.utils.contains('PACKAGECONFIG', 'gles2', 'eglfs', 'linuxfb', d), d)}"

...(snip)...

EXTRA_OECMAKE_append_class-target = "\
    -DFEATURE_rpath=OFF \
    -DQT_QPA_DEFAULT_PLATFORM=${QT_QPA_DEFAULT_PLATFORM} \
    -DQT_AVOID_CMAKE_ARCHIVING_API=ON \
"

今回ここが秀逸になっていて、DISTRO_FEATURESにx11が含まれている場合がデフォルトがxcbになっていて、 含まれない場合はqtbaseのPACKAGECONFIGにgles2があればeglfs、なければlinuxfbが設定されるようになっている。

meta-qt5までの環境ではデフォルトがxcbから変更できなかった(はず)ので、実行環境で環境変数を下記のように設定するかアプリケーション実行時に-platform=eglfsとかする必要があった。

export QT_QPA_PLATFORM=eglfs
export QT_QPA_EGLFS_INTEGRATION=eglfs_kms_egldevice 

今回はレシピかlocal.confで適切に設定すれば、実行時にQPA_PLATFORMをいちいち気にしないで良いようになっている。

構築手順

ソース取得

下記のコマンドでソースを取得する。

$ mkdir -p rpi-gatesgarth/layers
$ cd rpi-gatesgarth/layers
$ git clone git://git.yoctoproject.org/poky.git -b gatesgarth
$ git clone git://git.yoctoproject.org/meta-raspberrypi -b gatesgarth

meta-qt6の取得

$ git clone git://code.qt.io/yocto/meta-qt6.git

今回構築した時のハッシュは下記の通り。

meta
meta-poky
meta-yocto-bsp       = "gatesgarth:943ef2fad8428f002850e3655a3312e13d0dcb2c"
meta-raspberrypi     = "gatesgarth:09a3c11696c75593f8e475da5dfb401016c6aaca"
meta-qt6             = "dev:aaa3b77573f448c14a9526e85813b2e8c8ca6956"

環境変数設定

$ source layers/poky/oe-init-build-env build

自動的にビルドディレクトリに移動される。 これで、bitbake関連のツールが使用可能になる。

レイヤ追加

下記のコマンドでビルド対象にmeta-raspberrypiを追加する。

$ bitbake-layers add-layer ../layers/meta-raspberrypi
$ bitbake-layers add-layer ../layers/meta-qt6

local.confの修正

MACHINEをraspberrypi4-64に設定する。

MACHINE = "raspberrypi4-64"
DL_DIR ?= "${TOPDIR}/../downloads"

# systemd
DISTRO_FEATURES_append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# qt6 modules
IMAGE_INSTALL_append = " packagegroup-qt6-modules"

# Default QPA platform is eglfs-kms-integration
PACKAGECONFIG_append_pn-qtbase = " kms"
DISTRO_FEATURES_remove = "x11"

IMAGE_INSTALL_append = " ttf-vlgothic"

今回はQt6を動かすためマウスやキーボード、ディスプレイは接続するので、 ネットワークやUARTなどヘッドレスに便利なものは特に追加していない。

ビルド

core-image-baseをビルドする。

$ bitbake core-image-base

ビルド結果

core-image-base-raspberrypi4-64.manifestを確認する。

...(snip)...
libqt6coap-plugins cortexa72 6.0.0
libqt6coap-qmlplugins cortexa72 6.0.0
libqt6coap6 cortexa72 6.0.0
libqt6core5compat-plugins cortexa72 6.0.0
libqt6core5compat-qmlplugins cortexa72 6.0.0
libqt6core5compat6 cortexa72 6.0.0
libqt6mqtt-plugins cortexa72 6.0.0
libqt6mqtt-qmlplugins cortexa72 6.0.0
libqt6mqtt6 cortexa72 6.0.0
libqt6networkauth-plugins cortexa72 6.0.0
libqt6networkauth-qmlplugins cortexa72 6.0.0
libqt6networkauth6 cortexa72 6.0.0
libqt6opcua-plugins cortexa72 6.0.0
libqt6opcua-qmlplugins cortexa72 6.0.0
libqt6opcua6 cortexa72 6.0.0
libqt6serialbus-plugins cortexa72 6.0.0
libqt6serialbus-qmlplugins cortexa72 6.0.0
libqt6serialbus6 cortexa72 6.0.0
libqt6serialport-plugins cortexa72 6.0.0
libqt6serialport-qmlplugins cortexa72 6.0.0
libqt6serialport6 cortexa72 6.0.0
libqt6shadertools-plugins cortexa72 6.0.0
libqt6shadertools-qmlplugins cortexa72 6.0.0
libqt6shadertools6 cortexa72 6.0.0
libqt6texttospeech-plugins cortexa72 6.0.0
libqt6texttospeech-qmlplugins cortexa72 6.0.0
libqt6texttospeech6 cortexa72 6.0.0
libqt6virtualkeyboard-plugins cortexa72 6.0.0
libqt6virtualkeyboard-qmlplugins cortexa72 6.0.0
libqt6virtualkeyboard6 cortexa72 6.0.0
libqt6websockets-plugins cortexa72 6.0.0
libqt6websockets-qmlplugins cortexa72 6.0.0
libqt6websockets6 cortexa72 6.0.0
...(snip)...
packagegroup-qt6-modules raspberrypi4_64 1.0
...(snip)...
qt3d cortexa72 6.0.0
qt3d-plugins cortexa72 6.0.0
qt3d-qmlplugins cortexa72 6.0.0
qtbase cortexa72 6.0.0
qtbase-plugins cortexa72 6.0.0
qtbase-qmlplugins cortexa72 6.0.0
qtdeclarative cortexa72 6.0.0
qtdeclarative-plugins cortexa72 6.0.0
qtdeclarative-qmlplugins cortexa72 6.0.0
qtgraphicaleffects cortexa72 6.0.0
qtgraphicaleffects-plugins cortexa72 6.0.0
qtgraphicaleffects-qmlplugins cortexa72 6.0.0
qtimageformats cortexa72 6.0.0
qtimageformats-plugins cortexa72 6.0.0
qtimageformats-qmlplugins cortexa72 6.0.0
qtquick3d cortexa72 6.0.0
qtquick3d-plugins cortexa72 6.0.0
qtquick3d-qmlplugins cortexa72 6.0.0
qtquickcontrols2 cortexa72 6.0.0
qtquickcontrols2-plugins cortexa72 6.0.0
qtquickcontrols2-qmlplugins cortexa72 6.0.0
qtquicktimeline cortexa72 6.0.0
qtquicktimeline-plugins cortexa72 6.0.0
qtquicktimeline-qmlplugins cortexa72 6.0.0
qtsvg cortexa72 6.0.0
qtsvg-plugins cortexa72 6.0.0
qtsvg-qmlplugins cortexa72 6.0.0
qttools cortexa72 6.0.0
qttools-plugins cortexa72 6.0.0
qttools-qmlplugins cortexa72 6.0.0
qttranslations cortexa72 6.0.0
qttranslations-plugins cortexa72 6.0.0
qttranslations-qmlplugins cortexa72 6.0.0
qtwayland cortexa72 6.0.0
qtwayland-plugins cortexa72 6.0.0
qtwayland-qmlplugins cortexa72 6.0.0

大体のところはイメージに追加されている。

書き込み

bmaptoolで書き込む。

$ sudo bmaptool copy core-image-base-raspberrypi4.wic.bz2 /dev/sdX

/dev/sdXは環境に応じて適宜読み替える。

Qtのアプリを作成してみる

今のところサンプルアプリケーションが見当たらないのでQtQuickの簡単なアプリを作成してみる。

SDKの作成

meta-toolchain-qt6SDKを作成する。

$ bitbake meta-toolchain-qt6

出来上がったSDKをインストールする。

$ cd cd tmp/deploy/sdk/
$ ./poky-glibc-x86_64-meta-toolchain-qt6-cortexa72-raspberrypi4-64-toolchain-3.2.1.sh

デフォルトの設定では/opt/poky/3.2.1にインストールされる

プログラムの作成

下記のような配置になるようにファイルを作成する。

$ tree .
.
├── CMakeLists.txt
├── main.cpp
├── main.qml
└── qthello.qrc

QMLファイル

下記の内容でmain.qmlを作成する。

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    font.pointSize: 64
    
    Button {
        id: helloButton
        text: "Hello world"
        anchors.centerIn: parent

        onClicked: {
            Qt.quit()
        }
    }
}

QtQuickアプリケーションではQMLファイルによってGUIのレイアウトを定義する。

フォントサイズは少し大きめにしてみた。

C++ソースコード

下記の内容でmain.cppを作成する。

#include <QGuiApplication>
#include <QtQml/QQmlApplicationEngine>

int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    engine.load("qrc:/main.qml");
    return app.exec();
}

QRCファイル

下記の内容でqthello.qrcを作成する。

<!DOCTYPE RCC>
<RCC version="1.0">
  <qresource prefix="/">
    <file>main.qml</file>
  </qresource>
</RCC>

リソース中のQMLを/main.qmlとして参照できるようにしている。

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(qthello)

find_package(Qt6 COMPONENTS Quick REQUIRED)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
QT6_ADD_RESOURCES(RESOURCES ${PROJECT_NAME}.qrc)

add_executable(${PROJECT_NAME} main.cpp ${RESOURCES})
target_link_libraries(${PROJECT_NAME} Qt6::Quick)

Qtプログラムのビルド

下記のコマンドでアプリケーションをビルドする。

$ source /opt/poky/3.2.1/environment-setup-cortexa72-poky-linux
$ mkdir build && cd build
$ cmake ..
$ make -j $(nproc)

qthelloが生成されるのでこれをLinuxイメージを書き込んだSDカードにコピーする。

SDカードがPCに認識されると/media/${USER}/の下にマウントされる。

$ sudo cp ./qthello /media/${USER}/root/home/root

プログラムの実行

アプリケーションを書き込んだSDでラズパイを起動する。

rootでログインし、下記のコマンドで実行する。

$ ./qthello

f:id:mickey_happygolucky:20201212004933j:plain
ラズパイ4での実行画面

無事、アプリケーションが実行される。ボタンをクリックすると終了する。

写真が汚いのはご愛嬌。

まとめ

まだ開発中のmeta-qt6を試してみた。

足りない部分はまだあるが、QPAプラットフォームの扱いに関しては明らかに向上していると思う。

meta-toolchain-qt6のSDKによるアプリケーション開発などについては、現時点でも十分試せるレベルなので、いろいろ遊べそうだ。

リリースが楽しみ。