Qt 5 と Qt 6 の互換性

Qt 5 と Qt 6 の CMake API のセマンティクスは、ほぼ互換性があります。しかし、Qt 5.14 までは、インポートされたすべての Qt ライブラリのターゲットとコマンドは、名前の一部としてバージョン番号を含んでいました。このため、Qt 5 と Qt 6 の両方で動作する CMake コードを書くのはやや面倒でした。そのため、Qt 5.15ではバージョンレスのターゲットとコマンドを導入し、異なるQtのバージョンにほとんど依存しないCMakeコードを記述できるようにしました。

バージョンレスターゲット

既存のインポートターゲットに加えて、Qt 5.15ではバージョンレスターゲットが導入されました。つまり、Qt Coreとリンクするために、Qt6::Core 、またはQt::Core の両方を参照することができます:

find_package(Qt6 COMPONENTS Core)
if (NOT Qt6_FOUND)
    find_package(Qt5 5.15 REQUIRED COMPONENTS Core)
endif()

add_executable(helloworld
    ...
)

target_link_libraries(helloworld PRIVATE Qt::Core)

上記のスニペットは、まず Qt 6 のインストールを探します。失敗した場合は、Qt 5.15 パッケージを探します。Qt 6 か Qt 5 かは関係なく、インポートされたQt::Core ターゲットを使うことができます。

バージョンレスターゲットはデフォルトで定義されています。無効にするには、最初のfind_package() 呼び出しの前にQT_NO_CREATE_VERSIONLESS_TARGETS を設定してください。

注意: インポートされた Qt::Core ターゲットには、Qt6::Core ターゲットで利用可能なターゲットプロパティはありません。

バージョンレスコマンド

Qt 5.15以降、Qtモジュールはバージョンレスのコマンドを提供します。例えば、Qt 5 と Qt 6 のどちらを使用していても、qt_add_translation を使用して翻訳ファイルをコンパイルすることができます。

QT_NO_CREATE_VERSIONLESS_FUNCTIONS を最初のfind_package() 呼び出しの前に設定することで、バージョンレスコマンドの作成を防ぐことができます。

Qt 5 と Qt 6 の混在

Qt 5 と Qt 6 の両方を 1 つの CMake コンテキストでロードする必要があるプロジェクトがあるかもしれません(ただし、1 つのライブラリや実行ファイルで Qt のバージョンを混在させることはサポートされていませんので、注意が必要です)。

このようなセットアップでは、バージョンレスのターゲットやコマンドは、find_package を介して最初に見つかった Qt のバージョンを暗黙的に参照することになります。バージョンを明示的にするには、最初のfind_package 呼び出しの前に CMake 変数QT_DEFAULT_MAJOR_VERSIONを設定してください。

古い Qt 5 バージョンのサポート

Qt 5.15より古いQt 5のバージョンもサポートする必要がある場合、CMake変数に現在のバージョンを格納することで対応できます:

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)

add_executable(helloworld
    ...
)

target_link_libraries(helloworld PRIVATE Qt${QT_VERSION_MAJOR}::Core)

ここでは、QT という名前で、find_package(<PackageName>...) に Qt 6 の検索を試みさせ、失敗した場合は Qt 5 の検索を試みます。どちらかが見つかればfind_package は成功し、CMake 変数QT_VERSION_MAJOR56 のどちらかに定義されます。

その後、Qt${QT_VERSION_MAJOR} という名前をオンザフライで作成することで、決定された Qt バージョンのパッケージを再度ロードします。これは、CMAKE_AUTOMOC はパッケージ名がQt5Qt6 のどちらかであることを期待し、そうでない場合はエラーを表示するためです。

同じパターンを使って、インポートするライブラリの名前も指定できます。target_link_libraries を呼び出す前に、CMake はQt${QT_VERSION_MAJOR}::WidgetsQt5::Widgets またはQt6::Widgets に解決します。

可能であれば、CMakeコマンドのバージョンレス・バリアントを使用してください。

同じプロジェクトで Qt 5 と Qt 6 をサポートする必要がない限り、バージョン付きターゲットを使用してください。

バージョンレスターゲットを使用する必要がある場合は、バージョンレスターゲットを使用する際の落とし穴に注意してください。

Qt 5.15より古いバージョンのQt 5をサポートする必要がある場合や、QT_NO_CREATE_VERSIONLESS_FUNCTIONSや QT_NO_CREATE_VERSIONLESS_TARGETSが定義されているコンテキストでCMakeコードがロードされるかどうかを制御できない場合は、バージョン管理されたバージョンのCMakeコマンドやターゲットを使用してください。この場合でも、変数を通して実際のコマンドやターゲット名を決定することで、コードを簡素化することができます。

バージョンレスターゲット使用時の落とし穴

バージョンレスターゲットを使うと、いくつかの欠点がある。

バージョンレス・ターゲットはALIAS ターゲットであり、バージョン付きターゲットのターゲット・プロパティがありません。

プロジェクトは、バージョンレスターゲットを公開するターゲットをエクスポートしてはいけません。例えば、他のプロジェクトによって消費されるライブラリーは、バージョンレスターゲットに対して公にリンクするターゲットをエクスポートしてはいけません。そうしないと、推移的依存関係が壊れたり、そのライブラリーのユーザーが Qt5 と Qt6 のターゲットを不本意に混在させたりする可能性があります。

Windows での Unicode サポート

Qt 6 では、Qt モジュールに対してリンクするターゲットに対して、UNICODE_UNICODE のコンパイラ定義がデフォルトで設定されます。これは qmake の動作と同じですが、Qt 5 の CMake API の動作と比べると変更されています。

ターゲット上でqt_disable_unicode_defines()を呼び、定義を設定しないようにします。

find_package(Qt6 COMPONENTS Core)

add_executable(helloworld
    ...
)

qt_disable_unicode_defines(helloworld)

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