Qtの設定 - CMake

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
2022年12月14日 (水) 13:26時点におけるWiki (トーク | 投稿記録)による版 (→‎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)



CMakeのバージョン管理 (cmake_minimum_requiredコマンド)

CMakeは、新しいツールやプラットフォーム、機能のサポートを追加するために継続的に更新および拡張されている。
開発者は、新しいリリースごとに後方互換性を維持することに非常に注意を払うことになる。
そのため、ユーザがCMakeの新しいバージョンに更新した時、プロジェクトは以前と同じようにビルドし続けることができる。

時には、CMakeの特定の動作を変更する必要があったり、より厳しいチェックや警告が新しいバージョンで導入されたりすることがある。
全てのプロジェクトに直ちにこのような対応を要求するのではなく、CMakeは、プロジェクトが"CMakeのバージョン X.Y.Zのように振る舞う"というようなポリシー機構を提供する。

CMakeのバージョン動作の詳細を指定する主な方法は、cmake_minimum_requiredコマンドを使用することである。
これは、CMakeLists.txtファイルの最初の行で記述するべきであり、プロジェクトの要件が他の何よりも先にチェックされ、確立されるようにするものである。
cmake_minimum_requiredコマンドは、以下に示す2つのことを実行する。

  • プロジェクトが必要とするCMakeの最小バージョンを指定する。
    CMakeLists.txtファイルが指定されたバージョンより古いCMakeのバージョンで処理された場合、エラーが発生して直ちに停止する。
    これにより、処理を進める前に、CMakeの機能の特定の最小セットが利用可能であることが保証される。
  • CMakeの動作を指定されたバージョンに一致させるためのポリシー設定を強制するものである。


もし、cmake_minimum_requiredコマンドを記述しなかった場合は警告を出力する。
ほとんどのプロジェクトでは、cmake_minimum_requiredコマンドは、単に必要最小限のCMakeのバージョンを指定するものとして扱えば十分である。

cmake_minimum_required(VERSION <メジャー番号>.<マイナー番号>[.<バグフィックス番号>.<ビルド番号>])


VERSION</cod>オプションは常に必要であり、<メジャー番号>および<マイナー番号>も記述する必要がある。
ほとんどのCMakeプロジェクトでは、<バグフィックス番号>および<ビルド番号>を指定する必要はない。(CMakeの新しい機能はマイナー番号のアップデートでのみ現れるため)
特定のバグフィックスが必要な場合のみ、<バグフィックス番号>を指定すべきである。
さらに、CMake 3.0以降では、<ビルド番号>を使用していないため、指定する必要はない。

詳細を知りたい場合は、Qtの設定 - CMake#CMakeのポリシー設定において、cmake_minimum_requiredコマンドの挙動を調整する方法を参照すること。
これにより、CMakeは内部でバグを修正し、新しい機能を導入しながらも、過去の特定のリリースの期待される振る舞いを維持することができる。


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コマンドを使用して、変数を宣言および代入することができる。

 set(value 1)  # 値が1の変数valueを宣言


既存の変数への代入もsetコマンドを使用する。
変数の値の参照は、入れ子にすることもできる。

 set(value 1)  # 値が1の変数valueを生成
 set(value 2)  # 既存の変数valueに値1を代入
 set(value_name value)  # 変数value_nameに変数valueの値を代入
 
 message(${${value_name}}) # ${value_name}が展開されて、${${value_name}}が${value}になり、これが展開されて2になる


 set(USE_CCACHE OFF CACHE BOOL "")


変数の削除

変数の削除する場合は、unsetコマンドを使用する。

 set(value 1)  # 変数valueを宣言
 unset(value)  # 変数valueを削除


定義された全ての変数を出力

 get_cmake_property(variableNames VARIABLES)
 
 foreach(variableName ${variableNames})
    message(STATUS "${variableName}=${${variableName}}")
 endforeach()



ログメッセージの出力

messageコマンドとは

 message([<mode>] "message to display" ...)


下表に、<mode>に指定できる項目を示す。(一部)

modeの種類 説明 処理の継続 出力先
省略する場合 重要な情報 CMakeの処理を継続する STDERR
STATUS 情報 CMakeの処理を継続する STDOUT
WARNING 警告 CMakeの処理を継続する STDERR
SEND_ERROR エラー CMakeの処理を継続する STDERR
FATAL_ERROR 致命的なエラー CMakeの処理を終了する STDERR


以下の例では、messageコマンドにおいて、第1引数にFATAL_ERRORを指定することにより、エラーメッセージを出力して、CMakeコマンドを終了している。

 message(FATAL_ERROR "cmake to terminate.")


また、messageコマンドにおいて、第1引数にSEND_ERRORを指定することにより、エラーメッセージを出力して動作を継続する。

 message(SEND_ERROR "Continue cmake.")


以下の例では、Linux以外のOSの場合は、エラーメッセージを出力して、cmakeコマンドを終了している。

 if(NOT (UNIX AND NOT APPLE))
    message(FATAL_ERROR "ERROR! Only Linux can build this software.")
 else()
    set(LINUX TRUE)
 endif()


以下の例では、CMakeの特殊変数であるCMAKE_COMMANDCMAKE_CTEST_COMMANDを出力している。

 message("${CMAKE_COMMAND}")        # /usr/bin/cmake
 message("${CMAKE_CTEST_COMMAND}")  # /usr/bin/ctest



インクルードパスの指定

インクルードパスを指定する場合、include_directoriesコマンドを使用する。

 include_directories(/path/to/include)


include_directoriesコマンドを複数使用する場合、デフォルトでは、指定したパスは最後尾となる。
ただし、include_directoriesコマンドにBEFOREオプションを付加した場合は最前となる。

以下の例では、"-I/path1/to/include -I/path2/to/include"となる。

 include_directories(/path1/to/include)
 include_directories(/path2/to/include)


以下の例では、"-I/path2/to/include -I/path1/to/include" となる。

 include_directories(/path1/to/include)
 include_directories(BEFORE /path2/to/include)



ライブラリパスの指定

ライブラリパスを指定する場合、link_directoriesコマンドを使用する。

 link_directories(/path/to/lib)


link_directoriesコマンドを複数使用する場合、デフォルトでは、指定したパスは最後尾となる。
ただし、link_directoriesコマンドにBEFOREオプションを付加した場合は最前となる。

以下の例では、"-I/path1/to/lib -I/path2/to/lib"となる。

 link_directories(/path1/to/lib)
 link_directories(/path2/to/lib)


以下の例では、"-I/path2/to/lib -I/path1/to/lib" となる。

 link_directories(/path1/to/lib)
 link_directories(BEFORE /path2/to/lib)



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)