組み込み Linux デバイスの設定

Qt を特定のデバイス用にクロスコンパイルするには、ツールチェーンと sysroot が必要です。ツールチェーンには、gcc または他のコンパイラ、およびクロスコンパイル用に構築された関連ツールが含まれます。つまり、これらのツールはホスト・システム(通常はx64)上で動作し、ターゲット・アーキテクチャ(例えば32ビットまたは64ビットのARM)用のバイナリを生成する。sysrootには、ターゲット・システム用のヘッダーとライブラリーが含まれており、ホスト上でライブラリーやアプリケーションのコンパイルとリンクができます。

この概要ページでは、YoctoやBuildrootのようなディストリビューションのビルドシステムを使用しない、一般的なアプローチについて説明します。適切なツールチェーンと sysroot が利用可能であれば、Qt をクロスコンパイルしてデバイスにデプロイすることは常に可能です。

警告 このページは、一般的でハイレベルな概要しか提供できません。ビルド環境、ターゲットデバイス、ツールチェインによって、細部は大きく異なります。不明な点があれば、システム・インテグレーターにお問い合わせください。ビルド済みのリファレンス・イメージや SDK については、Boot to Qtを参照してください。

X11 や Wayland のようなウィンドウシステムなしで Qt ベースのアプリケーションを実行する場合、デバイスによっては EGL や OpenGL ES をサポートするためにベンダー固有のアダプテーションコードが必要になります。これはEGLFSプラットフォーム・プラグインのバックエンドという形で提供されます。これは、ソフトウェアベースのレンダリング専用である LinuxFB プラットフォームプラグインを使用するような、非アクセラレーションプラットフォームには関係ありません。Qt 6の時点で、多くの組み込みシステムはdrmを使用してビデオモードを設定し、ディスプレイコネクタとグラフィカルサーフェスを管理しています。例えば、NXP i.MX8ベースのデバイスやRaspberry Pi 4はこのアプローチを使用するため、EGLFSのバックエンドとして最もよく使用されるのはeglfs_kmsです。このバックエンドは、drm 、サーフェスとバッファの管理にgbm を使用して、EGLとOpenGL ESベースのレンダリングを可能にします。NXP i.MX6のような古いデバイスでは、eglfs_viv のような専用のeglfsバックエンドを使用して、EGLウィンドウサーフェスをフレームバッファに接続するレガシーなGPUベンダー固有のアプローチを使用し続けます。

注意: Qt は、組み込みデバイスのソフトウェアスタックの中の 1 つのコンポーネントに過ぎないことに注意してください。特にアクセラレーテッドグラフィックスが関係する場合、Qt はユーザ空間とカーネルコンポーネント、例えばディスプレイドライバのための適切な設定を持った、機能的なグラフィックススタックを期待します。これらのコンポーネントは Qt の領域外であり、アクセラレーテッドグラフィックスを含むベースシステムが完全に機能し、最適であることを保証するのはシステムインテグレータの責任です。

Embedded Linux システムのグラフィックスと入力設定に関する詳細は、Qt for Embedded Linux を参照してください。

ツールチェインファイルとデバイスマークスペック

Qt 5 では、qtbase/mkspecs/devicesディレクトリにあるデバイススペックを使用します。これらのファイルには、特定のデバイスのための適切なコンパイラとリンカのフラグが含まれており、また、正しいEGLとOpenGL ESライブラリがsysrootの標準的でない場所にある場合に、ピックアップされるようにします。

例えば、次のような configure コマンドで Raspberry Pi 2 用に Qt 5 のビルドを設定することができます:

./configure -release -opengl es2 -device linux-rasp-pi2-g++ -device-option CROSS_COMPILE=$TOOLCHAIN/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf- -sysroot $ROOTFS -prefix /usr/local/qt5

注意: ninja の実行ファイルがある場合、configure は常にNinjaジェネレーターとビルドツールを使用します。Ninjaはクロスプラットフォームで、機能が豊富で、パフォーマンスが高く、すべてのプラットフォームで推奨されています。他のジェネレータを使用しても動作するかもしれませんが、公式にはサポートされていません。

Qt 6とCMakeでは、この方法ではもはや十分ではありません。むしろ、設定を行う前にCMakeツールチェインファイルを提供する必要があります。このファイルで、コンパイラやリンカのフラグ、ツールチェインやシスルート特有の癖をカスタマイズします。

以下のセクションでは、最小限のカスタマイズで多くの場合に使用できるツールチェーンファイルを紹介します。これは、このブログ記事で紹介したアプローチに基づいている。

注: 以下に紹介するツールチェーン・ファイルは一例であり、特定のデバイス用にさらなるカスタマイズが必要になることがよくあります。また、ユーザーやシステム・インテグレーターは、適切と思われる方法で独自のツールチェーン・ファイルを自由に作成することができます。

Qt 6.0 では、CMake が Qt 自体をビルドするための唯一のビルドシステムとしてサポートされていますが、qmake を使用してアプリケーションをビルドすることもできます。クロスコンパイルで機能するqmake のセットアップを行うには、CMake や configure にレガシーな引数を指定する必要があります。

ホストツール

Qt のクロスコンパイルには、Qt のホストビルドが必要です。ビルド中に、mocrccqmlcachegenqsb などのツールが呼び出されます。例えば、x64マシンでARM用にクロスコンパイルする場合、同じQtバージョンのローカルx64ビルドを最初に利用可能にする必要があります。このQtビルドへのパスは、configureやcmakeに渡されます。

Qtの設定

以下が利用可能であると仮定します:

  • $HOME/rpi-sdk 以下のツールチェインと sysroot、
  • $HOME/qt-cross にある Qt のホストビルド、
  • $HOME/qt-host にある Qt のホストビルド。

さらに、設定する前に以下のことを決めておく必要があります:

  • Qt のビルドが完了したら、ローカルシステムのどこにインストールするか?この例では$HOME/qt6-rpi を使います。
  • Qt のビルドはデバイスのどこに配置されますか?この例では/usr/local/qt6 を使います。

この例では、Yocto 経由で生成された Raspberry Pi 4 SDK (toolchain+sysroot) を使用しますが、ここでの説明は完全に一般的なものであり、Yocto に依存するものではありません。ツールチェイン・ファイルを正しいクロス・コンパイラやその他のパスで更新すれば、他のツールチェインやsysrootでも手順は同じです。

build

$HOME/qt-cross/qtbase/configure -release -opengl es2 -nomake examples -nomake tests \
  -qt-host-path $HOME/qt-host                              \
  -extprefix $HOME/qt6-rpi                                 \
  -prefix /usr/local/qt6                                   \
  -- -DCMAKE_TOOLCHAIN_FILE=$HOME/qt-cross/toolchain.cmake

実際には、このconfigureコマンドは、以下のCMakeの直接呼び出しと同等です:

cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DINPUT_opengl=es2 -DQT_BUILD_EXAMPLES=OFF -DQT_BUILD_TESTS=OFF \
  -DQT_HOST_PATH=$HOME/qt-host                           \
  -DCMAKE_STAGING_PREFIX=$HOME/qt6-rpi                   \
  -DCMAKE_INSTALL_PREFIX=/usr/local/qt6                  \
  -DCMAKE_TOOLCHAIN_FILE=$HOME/qt-cross/toolchain.cmake  \
  $HOME/qt-cross/qtbase

適切なツールチェーンファイルがあれば、これだけでQtビルドが生成され、CMakeを使ってアプリケーションをビルドできるようになります。アプリケーションをqmake でもビルドできるようにするには、上記のすべての引数に加え、Qt 5 スタイルのデバイス仕様とデバイス・オプションを指定する必要があります:

$HOME/qt-cross/qtbase/configure ...
  ...
  -device linux-rasp-pi4-v3d-g++ \
  -device-option CROSS_COMPILE=$HOME/rpi_sdk/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi- \
  -device-option DISTRO_OPTS="hard-float" \
  ...

デフォルトでは、クロスコンパイル時に、ターゲットデバイス上で動作する予定の Qt ライブラリとツールだけがビルドされます。mocuic のようなビルド関連ツールはビルドされません。このようなツールのビルドは、QT_FORCE_BUILD_TOOLSON に設定することで有効にできます。

注: QT_FORCE_BUILD_TOOLS を有効にすると、qmake などのツールのターゲット・バイナリがステージング・ロケーションにインストールされます。したがって、アプリケーションのビルドにqmake を使用する場合は、代わりにhost-qmake スクリプトを呼び出してください。

コンフィギュレーションがエラーなしで完了したら、cmake --build . --parallel を実行してビルドする。ビルドが完了したら、cmake --install . を実行して、結果を$HOME/qt6-rpi にインストールします。そこから、rsync、scp、または他の方法を使用して、Qt ビルドをデバイスにデプロイできます。

$HOME/qt6-rpi 個別の Qt モジュールをビルドする場合、ステージングロケーションのbin ディレクトリからqt-configure-module スクリプトを使用して、qtdeclarative や qtquick3d などの追加モジュールを設定できます。これらのモジュールはcmake --build . を使ってビルドし、次のように実行してステージングロケーションにインストールします。cmake --install .

注意: ビルドを開始する前に、設定ステップの出力を常に注意深く調べてください。コンフィギュレーション時に必須機能が有効になっていなければ、ビルドしてデバイスにデプロイしても無駄です。

例えば、OpenGLによるグラフィックスの高速化が必要な場合は、以下の機能に特に注意してください:

EGL .................................... yes
OpenGL:
  Desktop OpenGL ....................... no
  OpenGL ES 2.0 ........................ yes
  OpenGL ES 3.0 ........................ yes
...
evdev .................................. yes
libinput ............................... yes
...
EGLFS .................................. yes
EGLFS details:
  EGLFS OpenWFD ........................ no
  EGLFS i.Mx6 .......................... no
  EGLFS i.Mx6 Wayland .................. no
  EGLFS RCAR ........................... no
  EGLFS EGLDevice ...................... yes
  EGLFS GBM ............................ yes
  EGLFS VSP2 ........................... no
  EGLFS Mali ........................... no
  EGLFS Raspberry Pi ................... no
  EGLFS X11 ............................ no
LinuxFB ................................ yes

Raspberry Pi 4 の例では、EGL、OpenGL ES、EGLFS GBM がすべてyes として報告されることを期待します。そうでなければ、EGLFS プラットフォーム・プラグインとそのeglfs_kmsバックエンドはデバイス上で機能しません。マウス、キーボード、およびタッチ入力を機能させるには、evdev またはlibinput のいずれかを有効にする必要があります。

同様に、X11 をデバイスのウィンドウ・システム(またはその 1 つ)として使用する場合は、xcb と X11 関連の機能がyes としてマークされていることを確認してください。

ツールチェーン・ファイルの例

$HOME/rpi-sdk の下に利用可能なsysrootとツールチェーンがあると仮定します。TARGET_SYSROOTCROSS_COMPILER は、使用するツールチェーンとsysrootに合わせて調整する必要があります。ここでの例は、ある特定の、Yoctoが生成したSDKにのみ適しています。CMAKE_C_COMPILERCMAKE_CXX_COMPILER についても同様である。

PKG_CONFIG_*のような環境変数を提供するラッパースクリプトには依存しない。むしろ、.pcファイルへのパスはツールチェーンファイルで指定される。別のsysrootでは、PKG_CONFIG_LIBDIR の調整が必要になる可能性が高い。例えば、Raspberry Pi OS(旧Raspbian)イメージから生成されたsysrootでは、代わりに/usr/lib/arm-gnueabihf/pkgconfig

コンパイラーとリンカーのフラグは、この例では最適である必要はありません。ターゲット・デバイスに合わせて調整してください。

サンプルのツールチェーンファイルにおけるCMakeの詳細については、このブログ記事と CMakeのドキュメントを参照してください。

cmake_minimum_required(VERSION 3.18)
include_guard(GLOBAL)

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(TARGET_SYSROOT /home/user/rpi-sdk/sysroots/cortexa7t2hf-neon-vfpv4-poky-linux-gnueabi)
set(CROSS_COMPILER /home/user/rpi-sdk/sysroots/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi)

set(CMAKE_SYSROOT ${TARGET_SYSROOT})

set(ENV{PKG_CONFIG_PATH} "")
set(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig)
set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})

set(CMAKE_C_COMPILER ${CROSS_COMPILER}/arm-poky-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER ${CROSS_COMPILER}/arm-poky-linux-gnueabi-g++)

set(QT_COMPILER_FLAGS "-march=armv7-a -mfpu=neon -mfloat-abi=hard")
set(QT_COMPILER_FLAGS_RELEASE "-O2 -pipe")
set(QT_LINKER_FLAGS "-Wl,-O1 -Wl,--hash-style=gnu -Wl,--as-needed")

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

include(CMakeInitializeConfigs)

function(cmake_initialize_per_config_variable _PREFIX _DOCSTRING)
  if (_PREFIX MATCHES "CMAKE_(C|CXX|ASM)_FLAGS")
    set(CMAKE_${CMAKE_MATCH_1}_FLAGS_INIT "${QT_COMPILER_FLAGS}")

    foreach (config DEBUG RELEASE MINSIZEREL RELWITHDEBINFO)
      if (DEFINED QT_COMPILER_FLAGS_${config})
        set(CMAKE_${CMAKE_MATCH_1}_FLAGS_${config}_INIT "${QT_COMPILER_FLAGS_${config}}")
      endif()
    endforeach()
  endif()

  if (_PREFIX MATCHES "CMAKE_(SHARED|MODULE|EXE)_LINKER_FLAGS")
    foreach (config SHARED MODULE EXE)
      set(CMAKE_${config}_LINKER_FLAGS_INIT "${QT_LINKER_FLAGS}")
    endforeach()
  endif()

  _cmake_initialize_per_config_variable(${ARGV})
endfunction()

ターゲットデバイス用にアプリケーションをビルドする

Qt のビルドが完了し、ステージングロケーションにインストールされたら、サンプルやアプリケーションをビルドすることができます。

CMakeを使用して、ステージングロケーションのbin ディレクトリ(例では$HOME/qt6-rpi )にある生成されたqt-cmake スクリプトを使用して設定し、ninja を実行します。例えば、次のようになります:

$HOME/qt6-rpi/bin/qt-cmake .
cmake --build .

生成されたアプリケーション・バイナリをデバイスにデプロイできます。qt-cmake ヘルパースクリプトを使用すると便利です。このスクリプトは、Qt のビルドに使用されたツールチェーンファイルが確実にロードされるので、アプリケーションごとに繰り返し指定する必要がありません。

Qt 自身とは異なり、qmake を使ったアプリケーションのビルドは、Qt 6.0 でも、適切なデバイス仕様が利用可能で、Qt を設定する際に CMake や configure に適切なレガシー引数が渡されている限り、サポートされています。これがすべて正しい場合、qmakemake を実行すると、ターゲットデバイス用のアプリケーションバイナリも生成されます。

プラットフォーム・プラグインと EGLFS のデフォルト

いったん設定されると、デフォルトのプラットフォーム・プラグインが選択されます。これは、-platform 引数を指定せず、QT_QPA_PLATFORM 環境変数を設定せずにアプリケーションを起動するときに使用されます。

同様に、EGLFSプラットフォーム・プラグインには複数のバックエンドがある。デフォルトは、利用可能性と事前に定義された優先順位に基づいて選択される。drmとgbmが利用可能な場合、デフォルトはeglfs_kmsバックエンドになる。これは、QT_QPA_EGLFS_INTEGRATION 環境変数を設定することで、常に実行時に上書きすることができます。

実行時に特定の値を強制することなく、ビルド時のデフォルトを変更するには、CMakeを一度実行した後に、以下の2つのCMakeキャッシュ変数を使用します:

  • QT_QPA_DEFAULT_PLATFORM ( ) - デフォルトのプラットフォームプラグインの名前。STRING
  • QT_QPA_DEFAULT_EGLFS_INTEGRATION ( ) - デフォルトのEGLFSバックエンド。STRING

これらの変数は、ツールチェーンファイル内で設定することもできます。

Qt の設定の詳細については、Qt Configure Options を参照してください。

本ドキュメントに含まれる文書の著作権は、それぞれの所有者に帰属します ここで提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。