Qtの設定 - CMake
概要
CMakeは、アメリカ国立医学図書館の出資により医療系画像解析に利用されるITK(Insight Toolkit)のために開発されたクロスプラットフォーム向けのメタビルドシステムであり、
qmakeと同様、クロスプラットフォーム向けに各種ビルドシステムのためのレシピファイルを生成する。
qmakeがQtのために開発されているのに対して、CMakeはITKのためにと開発されたが、メタビルドシステムとして独立のオープンソースプロジェクトとして単独で提供されている。
このため、KDE、LLVM、OpenCVをはじめ多数のプロジェクトで採用されている。
CMakeは、主に、C/C++等のプログラム言語のビルドに使用される。
CMakeが存在する以前では、C系言語のビルドには多数のビルドシステム(MakefileやNinjaやIDE等)が乱立していた。
これを隠蔽して、包括的に扱える様にしたものがCMakeである。
また、CMakeには、CUI版とGUI版が存在する。
CMakeは、変数、コマンド、マクロ、条件論理、ループ、コメント等の開発者にとって馴染みのある多くのものを備えている。
CMakeで使用されるコマンド名も大文字小文字を区別しないため、以下は全て等価である。
ただし、最近では、コマンド名を全て小文字で記述することが一般的である。(これは、CMakeのドキュメントでビルトインコマンドのために従われている慣習でもある)
add_executable(myExe main.cpp)
ADD_EXECUTABLE(myExe main.cpp)
Add_Executable(myExe main.cpp)
非推奨のコマンドおよび設定
- include_directoriesコマンド
- 指定したディレクトリからヘッダファイルを検索するコマンドである。
- 定義した箇所以降の全てのターゲットが指定したディレクトリをインクルードするため、使用は避けるべきである。
- 代わりに、
target_include_directories
コマンドを使用する必要がある。
- add_definitionsコマンド
- プロジェクト全体に影響を与えてしまう。
- ビルド依存性の管理が難しくなる。
- コンパイラの最適化を阻害する可能性がある。
- 代わりに、
target_compile_definitions
コマンドを使用する必要がある。
- add_compile_definitionsコマンド
- プロジェクト全体への影響
- プロジェクト内の全てのターゲットに対して定義を追加される。
- これにより、意図しないターゲットにまで定義が設定されてしまう可能性がある。
- ビルド依存性の管理が難しくなる
- 特定のターゲットにのみ必要な定義がプロジェクト全体に設定されると、ビルド依存性の管理が複雑になる。
- コンパイラの最適化への影響
- 不要な定義が設定されると、コンパイラの最適化が阻害される可能性がある。
- 代わりに、
target_compile_definitions
コマンドを使用する必要がある。
- プロジェクト全体への影響
- add_compile_optionsコマンド
- プロジェクト全体に対してコンパイルオプションを設定してしまうため、以下に示すような問題が発生する可能性がある。
- 意図しないターゲットへの影響
- プロジェクト内の全てのターゲットに対してコンパイルオプションが設定されるため、意図しないターゲットにも影響を及ぼす。
- ビルド依存性の管理が難しくなる
- 特定のターゲットにのみ必要なコンパイルオプションがプロジェクト全体に設定されると、ビルド依存性の管理が複雑になる。
- コンパイラの最適化への影響
- 不要なコンパイルオプションが設定されると、コンパイラの最適化が阻害される可能性がある。
- 代わりに、
target_compile_options
コマンドを使用する必要がある。
- link_directoriesコマンド
- プロジェクト内の全てのターゲットに対してリンクディレクトリを追加するため、以下に示すような問題が発生する可能性がある。
- プロジェクト全体への影響
- 意図しないターゲットにもリンクディレクトリが設定される可能性がある。
- ビルド依存性の管理が難しくなる
- 特定のターゲットにのみ必要なリンクディレクトリがプロジェクト全体に設定されると、ビルド依存性の管理が複雑になる。
- リンク順序の問題
- このコマンドで追加したディレクトリは、自動的にコマンドラインのリンカ引数の最後に追加される。
- これにより、リンク順序に関する問題が発生する可能性がある。
- 代わりに、
target_link_libraries
コマンドを使用する必要がある。
- link_librariesコマンド
- プロジェクト内の全てのターゲットに対してリンクライブラリを追加するため、以下に示すような問題が発生する可能性がある。
- プロジェクト全体への影響
- 意図しないターゲットにもリンクライブラリが設定される可能性がある。
- ビルド依存性の管理が難しくなる
- 例えば、特定のターゲットにのみ必要なライブラリがプロジェクト全体にリンクされると、ビルド依存性の管理が複雑になる。
- リンク順序の問題
- このコマンドで追加したライブラリは、自動的にコマンドラインのリンカ引数の最後に追加される。
- これにより、リンク順序に関する問題が発生する可能性がある。
- 代わりに、
target_link_libraries
コマンドを使用する必要がある。
- キャッシュ変数には、必ず接頭辞を付加する
- キャッシュ変数はグローバル変数であるため、名前の衝突を避けるために接頭辞を付加する。
- 変数CMAKE_<LANG>_FLAGS
- 代わりに、
target_compile_options
を使用する。 target_compile_options(<ターゲット名> PUBLIC -Wall)
- 代わりに、
- 変数
CMAKE_CXX_FLAGS
やtarget_compile_options
コマンドに、-std=c++17
等を指定しない。- 変数
CMAKE_CXX_STANDARD
を使用する(CMake 3.1以降)、または、target_compile_features
コマンドにcxx_std_17
を指定する。(CMake 3.8以降)
- 変数
- 変数CMAKE_SOURCE_DIRを使用しない
- 変数
CMAKE_SOURCE_DIR
は、トップレベルのディレクトリを指す。 - 異なるプロジェクトがネストしている場合、自身のプロジェクトのルートディレクトリ以外のパスを指すため、使用すべきでない。
- 代わりに、変数
CMAKE_CURRENT_SOURCE_DIR
、変数PROJECT_SOURCE_DIR
、変数<プロジェクト名>_SOURCE_DIR
を使用する。
- 変数
- macroコマンドの代わりにfunctionコマンドを使用する
function
コマンドは、関数を定義するためのコマンドである。macro
コマンドは、呼び出す側のスコープにある変数を上書きするため、自身のスコープを持つfunction
コマンドを使用する。- 親ディレクトリのスコープにある変数を上書きする場合は、
set(<変数名> <値> ... PARENT_SCOPE)
コマンドを使用する。
- file(GLOB)コマンド
file(GLOB)
コマンドは、CMakeを実行するたびに条件に合致するファイルのリストを自動的に作成するコマンドである。- ただし、特定のIDEでは正常に動作しない可能性があるため、コマンドラインから実行するような場合ではない限り使用すべきではない。
- IDEで使用する場合は、CMakeLists.txtファイルに
add_subdirectory
コマンドとtarget_sources
コマンドを使用して、再帰的にファイルを明示して追加する。
# CMakeLists.txtファイル
add_executable(<ターゲット名>)
add_subdirectory(<ディレクトリ名1>)
add_subdirectory(<ディレクトリ名2>)
# 同様に子ディレクトリを追加する
# <ディレクトリ名1>/CMakeLists.txtファイル
# CMake 3.12以前
target_sources(<ターゲット名> PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/file1.cpp
${CMAKE_CURRENT_SOURCE_DIR}/file2.cpp
# 絶対パスで指定しないとエラーになるため注意すること
)
# CMake 3.13以降
cmake_policy(SET CMP0076 NEW) # CMakeが自動的に相対パスを絶対パスへ変換する
target_sources(<ターゲット名> PRIVATE
file1.cpp
file2.cpp
)
# 画像ファイルの取得 (PNG, JPG, SVG)
execute_process(
COMMAND find ${CMAKE_CURRENT_SOURCE_DIR}/Image -iname "*.png" -o -iname "*.jpg" -o -iname "*.svg"
OUTPUT_VARIABLE IMAGES
)
string(REPLACE "\n" ";" IMAGE_FILES "${IMAGES}")
PRIVATE
オプション、PUBLIC
オプション、INTERFACE
オプションを適切に使用する。- これらのオプションは、コマンドのターゲットおよびそのターゲットに依存するターゲットに対する必要性を表す。
- ヘッダファイルのみのライブラリの場合は、
INTERFACE
オプションを使用する。
オプション | ターゲットが必要とする | ターゲットに依存するターゲットが必要とする |
---|---|---|
PRIVATE | ○ | ☓ |
PUBLIC | ○ | ○ |
INTERFACE | ☓ | ○ |
- ライブラリの種類を指定しない
- ビルドするユーザがスタティックライブラリまたはダイナミックライブラリを指定できるようにする。
BUILD_SHARED_LIBS
オプションを付加して選択することもできるが、各ライブラリごとにオプションを設定すべきである。
option(<変数名1> "build library as a shared library" ON)
if(<変数名1>)
add_library(<ターゲット名> SHARED)
else()
add_library(<ターゲット名> STATIC)
endif()
CMakeとqmakeの特徴
qmake | CMake | |
---|---|---|
レシピファイル | <Qtプロジェクト名>.pro | CMakeLists.txt |
レシピの呼び方 | プロジェクトファイル | CMakeソースコード |
特徴 | 変数ベース | コマンドベース |
ターゲット | 1ファイル 1ターゲット | 1ファイル 複数ターゲット |
プロジェクト間の連携 | 不可 | ターゲット名でリンク可能 |
Qtのサポート | ◎ | ○ |
Qt Creatorの対応 | ◎ | ファイルの追加等の対応がイマイチ |
カスタムコンパイラの対応 | △ | ◎ |
Packageの作成 | △ | ○ |
レシピファイルの違い
qmakeとCMakeは、レシピの考え方が異なる。
qmakeは、変数SOURCES
等のような変数に適切な値を設定していくことにより、対応するアーキテクチャの設定ファイル等から取得した値を使用して、
MakefileやVisual Studio / XCode向けのプロジェクトファイルを生成する。
CMakeは、コマンドと呼ばれる関数の引数に、ターゲットの情報、Define情報、インクルードパス等をプログラムして、Makefileや各種プロジェクトファイルを生成する。
# qmakeの場合
TEMPLATE = app
CONFIG -= qt # Qtライブラリを使用しない場合は、変数CONFIGからqtを削除する
SOURCES = main.cpp
# CMakeの場合
cmake_minimum_required(VERSION 3.15)
project(HelloWorld LANGUAGES CXX)
add_executable(helloworld main.cpp)
以下の例は、Qt Coreライブラリのみを使用するQtソフトウェアにおける最低限のレシピファイルである。
CMakeは汎用的なツールのため、Qtライブラリを使用する場合、CMakeのコマンド量が増加する。
find_package
関数を使用してQtライブラリ全体からQt Coreライブラリを要求することにより、
Qt Coreライブラリを変数Qt5::Core(Qt6では、Qt6::Coreとなる)経由で、target_link_libraries
に指定してリンクを指示する。
# qmakeの場合
TEMPLATE = app
QT -= gui # qmakeの初期状態はGUIが有効なため、変数QTからguiを削除することにより、Qt Coreライブラリのみとなる
SOURCES = main.cpp hello.cpp
HEADERS = hello.h
# CMakeの場合
cmake_minimum_required(VERSION 3.15)
project(HelloWorld LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
find_package(Qt5 COMPONENTS Core REQUIRED)
add_executable(helloworld
main.cpp
hello.cpp
hello.h
)
target_link_libraries(helloworld
Qt5::Core
)
共通の機能
- サブディレクトリ(サブプロジェクト)に対応
- ファイルの読み書き
- 独自関数の定義
- 別ファイルに分割したレシピをインクルードできる
- 自動的にmocを呼び出す
- Qtのリソースファイル対応
- インストールの定義
- 繰り返し文や条件分岐文
- プラットフォームの判定
- インストール
- テストの設定および実行
- 追加機能およびモジュール等の提供
CMakeの強みは、カスタムコンパイラ、機能の拡張性、パッケージ作成まで行う機能が提供されていることである。
qmakeでは、QTestによりテストの設定および実行もできるが、ビルドを補助するツールとしての特色が強い。
CMakeでは、CTest、CPack等の機能により、テストやパッケージ作成も可能である。
qmakeもCMakeも制御構文を持ち複雑なプロジェクトの作成も可能であるが、プロジェクトでの採用検討という視点から将来性も含めて考慮した場合、CMakeの方が有力である。
set(CMAKE_AUTORCC ON)コマンド
このコマンドは、CMakeの機能の一部であり、Qtプロジェクトで特によく使用される。
ただし、この機能はQtプロジェクトの開発のために設計されている。
この機能は比較的新しく、CMake 3.9以降で導入された。
変数CMAKE_AUTORCC
を有効にする場合、CMakeは、Qtのqrcファイルを自動的にコンパイルすることができる。
qrcファイルは、アプリケーションにバイナリリソース (画像、アイコン、翻訳ファイル等) を埋め込むために使用される。
- CMakeの機能
- 変数
CMAKE_AUTORCC
は、CMakeに組み込まれた変数である。 - CMakeはQtに限らず、多くのプロジェクトタイプをサポートする汎用的なビルドシステムジェネレータである。
- 変数
- Qtの統合
- CMakeはQtプロジェクトとの統合を強化するために、この機能を提供している。
- Qtのリソースコンパイラ (RCC) と連携して動作する。
- 他のフレームワークでの使用
- RCCと同様のリソース処理システムを持つ他のフレームワークでも使用できる可能性があるが、実際にはQt以外での使用は一般的ではない。
Qtプロジェクトでqrcファイルを使用する場合、変数CMAKE_AUTORCC
を有効にすることが推奨されている。
- 自動リソース処理
- CMakeが自動的にqrcファイルを検出し、必要なリソースコンパイル (rcc) ステップを実行する。
- ビルドプロセスの簡素化
- 手動でリソースファイルの処理を記述する必要がなくなる。
- 依存関係の管理
- リソースファイルが変更された場合、CMakeが自動的に再ビルドを行う。
ただし、以下に示すような場合は、変数CMAKE_AUTORCC
を使用しない場合もある。
これらのケースでは、qt_add_resources()
コマンドを使用して手動で処理を行うことができる。
- より細かな制御が必要な場合
- 特定のqrcファイルのみを処理したい場合
- パフォーマンス上の理由で手動処理を行う場合
したがって、多くの場合はset(CMAKE_AUTORCC ON)
コマンドを実行することにより、qrcファイルの処理が簡単になる。
set(CMAKE_AUTOMOC ON)コマンド
変数CMAKE_AUTOUIC
は、CMakeにおいてQt User Interface Compiler (UIC) の自動実行を制御するための設定である。
変数CMAKE_AUTOUIC
は、Qt開発を効率化するための重要な機能の1つである。
Qt Designerで作成された.uiファイルを自動的にコンパイルして、対応するC++ヘッダファイルを生成する。
これにより、UIファイルの変更が自動的にビルドプロセスに反映される。
多くの場合、この変数を有効にすることで、UIファイルの処理に関する手間を大幅に削減することができる。
Qtコンソールアプリケーションの場合は、GUIを持たないため、.uiファイルを使用しない。
したがって、この変数の設定は不要である。
この機能は、CMake 2.8.11以降で利用可能である。
- 目的
- QtのUIファイル (.ui) を自動的に処理して、対応するヘッダファイルを生成する。
- 動作
- 変数
CMAKE_AUTOUIC
を有効にする時、CMakeはプロジェクト内の.uiファイルを自動的に検出して、UICを実行してヘッダファイルを生成する。 - 生成されたファイルは、一般的に、ビルドディレクトリに配置される。
- 変数
- 利点
- 手動でUICの実行を設定する必要がなくなり、ビルドプロセスが簡素化される。
- UIファイルが変更された場合、自動的に再処理される。
- 対象ファイル
- プロジェクト内の全ての.uiファイルが処理の対象となる。
- 関連する変数
- CMAKE_AUTOUIC_SEARCH_PATHS : UICが.uiファイルを検索するパスを指定する。
- CMAKE_AUTOUIC_OPTIONS : UICに渡す追加オプションを指定する。
- パフォーマンス
- 大規模プロジェクトでは、自動処理が若干のビルド時間の増加をもたらす可能性がある。
変数CMAKE_AUTOUIC
を無効にする場合、qt_wrap_ui()
コマンドを使用して手動で.uiファイルを処理することもできる。
また、Qtプロジェクトによっては、特定のUIファイルのみを処理したい場合がある。
その場合は、この変数CMAKE_AUTOUIC
を無効にして手動で制御することも可能である。
※注意
変数CMAKE_AUTOUIC
は、Qt Widgetベースのアプリケーションで使用される.uiファイル (XML形式) を処理するためのものである。
QMLは独自の宣言的UIフォーマットを使用して、.qmlファイルで定義される。
したがって、QMLを使用したプロジェクトでは、この変数CMAKE_AUTOUIC
の設定は不要である。
set(CMAKE_AUTOMOC ON)コマンド
変数CMAKE_AUTOMOC
は、CMakeにおいてQt Meta-Object Compiler (MOC) の自動実行を制御するための重要な設定である。
この変数は、ほとんどのQtプロジェクトで必須の設定である。
Qtのメタオブジェクトシステムに必要なメタデータを生成するために、MOCを自動的に実行する。
これにより、開発者はQtの高度な機能 (シグナル / スロット、プロパティシステム等) を簡単に利用できるようになり、同時にビルドプロセスも自動化される。
この機能はCMake 2.8.6以降で利用可能である。
- 動作
- 変数
CMAKE_AUTOMOC
を有効にする時、CMakeはプロジェクト内のQtクラス (Q_OBJECT
マクロを使用しているクラス等) を自動的に検出して、 - 必要に応じてMOCを実行する。
- 変数
- 処理対象
- Q_OBJECTマクロを含むヘッダファイル
- シグナルやスロットを使用しているクラス
- プロパティシステムを使用しているクラス
- その他のQt固有の機能をC++で使用する場合
- メリット
- 手動でMOCの実行を設定する必要がなくなり、開発プロセスが簡素化される。
- ソースファイルの変更時に自動的にMOC処理が行われる。
- 生成ファイル
- moc_*.cppファイルがビルドディレクトリに生成される。
- 関連する変数
CMAKE_AUTOMOC_MACRO_NAMES
- 追加のマクロ名を指定して、MOC処理の対象を拡張できる。
CMAKE_AUTOMOC_PATH_PREFIX
- 生成されるmocファイルのパスプレフィックスを設定する。
- パフォーマンスへの影響
- 大規模プロジェクトでは、ビルド時間が若干増加する可能性がある。
- デバッグ
- 変数
CMAKE_AUTOMOC_VERBOSE
を有効にする時、MOC処理の詳細なログが出力され、問題のデバッグに役立つ。
- 変数
- QtとC++の統合
- この変数を有効にすることにより、QtのメタオブジェクトシステムとC++のコードがシームレスに統合される。
また、特定のファイルのみMOCを処理をしたい場合は、変数CMAKE_AUTOMOC
を無効にして、qt_wrap_cpp()
コマンドを使用して手動で制御できる。
※注意
プリコンパイル済みヘッダ (PCH、GCH等) を使用する場合、追加の設定が必要になることがある。
qt5_create_translation
TSファイルやTSファイルがあるディレクトリを指定して、Qt LinguistからTSファイルを生成する。
TSファイルは、ビルドディレクトリに保存される同じベースネームのQMファイルにコンパイルされる。
生成されたQMファイルへのパスは、<変数名>に追加される。
作成または更新する翻訳ファイルの拡張子は.ts
である必要がある。
与えられたTSファイルのパスが相対パスの場合、現在のプロジェクトのトップディレクトリからの相対パスで解決される。
TSファイルが存在しない場合、qt5_create_translation
は何もしない。
lupdate
コマンドは、ソースファイルまたはディレクトリを入力として受け付ける。
<オプション>は、lupdate
コマンドの実行時に使用するオプションを指定することができる。
指定可能なオプションは、Qtの設定 - Qt Linguist#lupdateコマンドを参照すること。
qt5_create_translation(<変数名> <TSファイル 1> <TSファイル 2> <TSファイル 3> ... <オプション>)
# 例.
# まず、プロジェクトのトップディレクトリにあるTSファイルを検索する。(helloworld_en.tsファイルとhelloworld_ja.tsファイル)
# 次に、lupdateコマンドを実行してTSファイルをコンパイルすることにより、helloworld_en.qmファイルとhelloworld.ja.qmファイルを生成または更新する。
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} helloworld_en.ts helloworld_de.ts)