「Qtの設定 - CMake」の版間の差分

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動
167行目: 167行目:
  endif()
  endif()
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
== ライブラリの構築 (add_libraryコマンド) ==
CMakeは様々な種類のライブラリのビルドをサポートしている。<br>
ライブラリを作成して使用する場合、<code>add_library</code>コマンドを使用する。<br>
<syntaxhighlight lang="cmake">
add_library(
    <ターゲット名>
    [<STATIC または SHARED または MODULE>]
    [EXCLUDE_FROM_ALL]
    <ソースコードファイル名 1>
    <ソースコードファイル名 2>
    # ...略
)
</syntaxhighlight>
<br>
<code><ターゲット名></code>は、CMakeLists.txtファイル内でライブラリを参照するために使用される。<br>
ビルドされたライブラリ名は、<code><ターゲット名></code>となる。<br>
<br>
<code>EXCLUDE_FROM_ALL</code>オプションは、<code>add_executable</code>コマンドと同様、ライブラリがデフォルトのALLターゲットに含まれないようにする。<br>
構築するライブラリの種類は、<code>STATIC</code>、<code>SHARED</code>、<code>MODULE</code>のうちの1つを指定する。<br>
<br>
* STATICオプション
*: 静的ライブラリまたはアーカイブを指定する。
*: Windowsでは、デフォルトのライブラリ名は、<u><ライブラリファイル名>.lib</u>となる。
*: Linuxでは、デフォルトのライブラリ名は、<u>lib<ライブラリファイル名>.a</u>となる。
* SHARED
*: 共有ライブラリまたは動的ライブラリを指定する。
*: Windowsでは、デフォルトのライブラリ名は、<u><ライブラリファイル名>.dll</u>となる。
*: Linuxでは、デフォルトのライブラリ名は、<u>lib<ライブラリファイル名>.so</u>となる。
* MODULE
*: 共有ライブラリに似ているが、ライブラリや実行ファイルに直接リンクされるのではなく、実行時に動的にロードされることを意図しているライブラリを指定する。
*: これらは、ユーザがロードするかどうかを選択できるプラグイン、または、オプションのコンポーネントである。
*: Windowsでは、DLL向けのインポートライブラリは作成されない。
<br>
よほどのことがない限り、<code>STATIC</code>または<code>SHARED</code>オプションは、それが必要であることが分かるまで付加しないことを推奨する。<br>
これにより、プロジェクト全体を通して、スタティックライブラリかダイナミックライブラリかをより柔軟に選択することができる。<br>
<br>
ビルドするライブラリの種類を定義するオプションを省略することも可能である。<br>
特定のライブラリが必要でない限り、プロジェクトファイルには指定せずに、プロジェクトの構築時に開発者が選択できるようにすることが望ましい。<br>
そのような場合、ライブラリは<code>STATIC</code>か<code>SHARED</code>のどちらかになり、変数<code>BUILD_SHARED_LIBS</code>の値により選択される。<br>
<br>
変数<code>BUILD_SHARED_LIBS</code>が<code>true</code>を代入する場合はライブラリのターゲットはダイナミックライブラリ、それ以外の場合はスタティックライブラリとなる。<br>
<code>add_library</code>コマンドを呼び出すたびに変更する必要がなく、1ヶ所に記述するだけで設定を変更することができる。<br>
ただし、<code>add_library</code>コマンドを呼び出す前に、変数<code>BUILD_SHARED_LIBS</code>を記述する必要がある。<br>
<syntaxhighlight lang="cmake">
set(BUILD_SHARED_LIBS YES)
</syntaxhighlight>
<br>
変数<code>BUILD_SHARED_LIBS</code>を設定する方法として、<code>cmake</code>コマンドに<code>-DBUILD_SHARED_LIBS</code>オプションを付加する方法がある。<br>
cmake -DBUILD_SHARED_LIBS=YES /path/to/source
<br><br>
<br><br>



2024年4月4日 (木) 07:17時点における版

概要

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_FLAGStarget_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の方が有力である。


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)