2019の10日目として、9日目に引き続きCMake入門をお送りします。9日目は、現在のQt6に向けた流れからCMakeを学習する必要性と、qmakeと対比しながらCMakeの大雑把な特徴を紹介しました。本日は、引き続きqmakeではこうしていたことがCMakeではこうなりますという紹介です。こちらの記事はqmakeを使っていた方向けの説明ですので、新たにCMakeから始める人は、正規のドキュメントやCMakeのタグから別の記事を探していただいた方が良いかと思います。TEMPLATE=.*qmakeでは、プロジェクトファイルの挙動を決めるため、ますTEMPLATE変数で何をするプロジェクトなのかを選択していました。app/vcapplib/vclibsubdirsこれは、qmakeのプロジェクトファイルが原則として1ファイル1ターゲットとなっているため、プロジェクトがアプリケーションの作成のものなのか、ライブラリ作成のものなのか、サブディレクトリを制御するものなのか、それ以外の汎用プロジェクトなのかといった選択をするものでした。選択されたテンプレートと対応する変数に値を設定することでMakefileやプロジェクトファイルが生成されていました。それに対し、CMakeは1ファイルに複数ターゲットに対応しており、CMakeLists.txtが何のためのCMakeソースなのかという選択はありません。qmakeとCMakeの最初の大きな違いといえるでしょう。アプリケーションを作成するためのテンプレートで、以下の変数を使いアプリケーションのビルドについて記述していました。SOURCESHEADERSFORMSRESOURCESLEXSOURCESYACCSOURCESTARGETDETSDIRDEFINESINCLUDEPATHDEPENDPATHVPATHこれらの変数相当のコマンドについてCMakeでの記述を見ていきましょう。SOURCES/HEADERSこれは、9日目の記事でも触れましたが、add_executableコマンドに引き渡します。hello.h)なお、QtでQObject系(メタオブジェクトを必要とするクラス)を利用する場合は、もう少し記述を増やす必要があります。Compiler)というプリプロセッサの対象となります。qmakeは指定されたソースコードとヘッダを検証し、対象の場合、mocを使いメタオブジェクトを記述したソースコードを自動生成するビルドルールへと変換します。CMakeでは、CMAKE_AUTOMOC変数にONを指定しておくことで、add_executableに渡したソースコードを精査しmoc周りのルール追加するようになります。*.uiファイルを指定する変数です。指定したuiファイルは、uicプログラムに渡されui_xxxxx.hに変換され、ユーザーがインクルードして利用することになります。mainwindow.uiCMakeでは、CMAKE_AUTOUIC変数にONを指定して、uiファイルもadd_executableコマンドで指定します。ONにしておきましょう。(.qrc)を登録するものです。compiler)を使ってC++ソースコードに変換し、ターゲットのソースコードに追加されます。resource_file.qrcCMakeでは、CMAKE_AUTORCC変数にONを指定して、やはりadd_executableコマンドに引き渡します。resource_file.qrc)LEXSOURCES/YACCSOURCESレキシカルアナライザとパーサージェネレータ用のソースコードを指定するための変数です。FindFLEXを使うことになりますが、試したことが無いので割愛します。興味がある方は、CMakeのドキュメントを参考にしながら試してください。TARGETTARGET変数は、ターゲット名を指定する変数です。デフォルトではプロジェクトファイル名=ディレクトリ名になりますが、都合が悪い場合は、TARGET変数で変更できました。CMakeの場合、add_executableコマンドの第一引数がターゲット名となっています。...])なお、CMakeのプロパティという機構を使ってCMake上のターゲット名と出力ファイル名を制御できます。CMakeのプロパティとqmakeのプロパティとでは大きく意味が異なるので注意が必要です。set_propertyを使い、OUTPUT_NAME系の変数を変更して対応も可能です。hogehoge)DESTDIRDESTDIR変数は生成したターゲットファイルの生成先を指定する変数です。CMakeではCMAKE_RUNTIME_OUTPUT_DIRECTORYで指定します。installなどで置かれる先)ではなく、ビルドした結果のバイナリが置かれる場所になります。DEFINESDEFINES変数はビルド時に追加されるプロプロセッサdefineを格納する変数です。....のようになります。いうコマンドを使う必要があります。複数のターゲットのdefineに影響を与えます。古い方の定義では、"-D"を付けて指定する必要がありました。"-D"が不要になっています。hello.h)target_compile_definitionsは、複数のターゲット向けではなく、特定のターゲットのdefineを制御します。PRIVATE>を指定する必要がありますが、アプリケーションのビルドの時はPRIVATEを指定しておけば問題ありません。BAR")INCLUDEPATHINCLUDEPATHはその名の通り、includeされるヘッダファイルの検索パスリストを指定する変数です。target_include_directoriesコマンドを利用します。inc)include_directoriesが複数のターゲットのプロパティにインクルードパスを設定するのに対し、target_include_directoriesは、指定したターゲットにのみインクルードパスを追加します。pathより前に追加するか、後に追加するかのオプションと、対応しているプラットフォームの場合システムパスであることを示すオプションが用意されています。...])なお、このAPIにも、INTERFACE,PUBLIC,PRIVATEの指定がありますが、アプリケーションの場合はPRIVATEを指定しておけば問題ありません。DEPENDPATHqmakeでは、ヘッダファイルの依存関係を追いかけるべきパスをINCLUDEPATHとは別に設定できていました。これは、変更される可能性の低い外部ライブラリのヘッダファイルまで探索すると時間がかかるためです。CMakeではこの仕組みを見つけられていません。そのような対処がされているのをご存知の方がいれば、ぜひご連絡ください。VPATHqmakeでは、開くことのできないファイルがあった場合、VPATHに指定されたパスに同名のファイルがないかを探しに行く機能が提供されていましたが、CMakeではこのような仕組みは見つけられませんでした。ファイルの存在確認や検索は可能なので、同じようなことをやろうと思えばできますが、自動的に行う仕組みはなさそうです。TEMPLATE=libqmakeでは、ライブラリ用のプロジェクトとして定義するには、TEMPLATE変数にlibを指定し、以下の変数を設定していました。shared(dll)またはstatic_and_sharedを設定すると静的ライブラリや共有ライブラリのビルドを行うことを指定できました。CMakeでは、静的ライブラリか、共有ライブラリかは、add_libraryコマンドの引数で指定します。RESOURCESの代わりにadd_libraryの引数に渡すのは、add_executableと同じです。hello.hCMakeでは以下のようになります。hello.h)ちなみにMODULEは、SHAREDに近い共有ライブラリですが、直接リンクを行わず、プラグインなどのようにdlopenなどで読み込む用途に使われるビルド用です。Linuxの場合ですとSONAMEが設定されないようなオプション構成になります。ところで、staticとsharedを両方同時にビルドしたいという場合には、CMakeでは少し手がかかります。hello)add_libraryを異なるターゲット名で呼び出し、出力ファイル名のプロパティを変更するという記述になります。INCLUDEPATHやDEFINESは、アプリケーションの場合と同じです。INTERFACEやPUBLICの扱いが意味を持ってくるのですが、そのあたりは後述します。TEMPLATE=subdirsqmakeでは、異なる.proは異なるプロジェクトとして扱われ、1ファイル1プロジェクトという考え方です。そのため、ライブラリとそれとリンクする実行ファイルを持つプロジェクトの場合、ライブラリと実行ファイルのソースをそれぞれのディレクトリに分け、複数のサブプロジェクトを持つプロジェクト作成には、TEMPLATE=subdirsを使うということになっていました。CMakeの場合、この辺りの考え方がqmakeとは異なりますが、ディレクトリ分割され、それぞれに用意されたCMakeソースコードを読み込ませていくことが可能です。これには、add_subdirectoryを使います。[EXCLUDE_FROM_ALL])名称から想像がつくかもしれませんが、指定できるのは1コマンドにつき1ディレクトリになります。以下のようなソースツリーがあるとします。exampleappmain.cpplibhello.hhello.cppqmakeの場合は、アプリケーションのインクルード・リンクルールを.priファイルで提供するライブラリプロジェクトにすると、プロジェクトファイルは以下のような構成になります。lib同等のプロジェクトをCMakeで記述すると、以下のようになります。3.15)project(HelloWorld)add_subdirectory(app)add_subdirectory(lib)qmakeの場合、アプリケーションからライブラリをリンクするのはLIBS変数に設定することになっていました。上述の例では、.priを使ってライブラリ側がルールを提供し、app.proでこれをincludeしていました。CMakeの場合は、app側でtarget_link_librariesコマンドを使い、リンクするライブラリのターゲット名を指定します。実際にどんな出力名になっているのかなどは、ターゲット名で解決されるので、余計な努力は不要です。INCLUDEPATHですが、これが説明を保留していたINTERFACEの役割です。以下の1行で、helloターゲットとリンクするアプリケーションは、libディレクトリをインクルードディレクトリとしてパスに追加するようになります。${CMAKE_CURRENT_SOURCE_DIR})この例だと少しわかりにくいので、もう1行追加してみましょう。UGE)INTERFACEは、helloには影響を与えず、helloとリンクするターゲットにのみ伝播します。PUBLICは、helloおよびhelloとリンクするターゲットに伝播します。PRIVATEは、helloにのみ伝播します。以下のようなことになります。app/main.cppこのように、CMakeではターゲット間でリンクする場合のルールを、ライブラリ側に設定することができます。target_link_librariesのINTERFACE,PUBLIC,PRIVATEも同じような挙動を示します。このあたりは、qmakeには不足している大規模プロジェクト向けの機能と言えるでしょう。まとめ今回は、Qtのアドベントカレンダーということで、qmakeをベースにqmakeのTEMPLATEで指定するようなサブディレクトリ指定、アプリケーション作成、ライブラリ作成に関わるコマンドとその挙動を大雑把に解説しました。現在、qmakeを知らない人がCMakeから入門するための薄い本を書こうと鋭意努力中ですので、CMakeから新たに勉強をはじめようという方は、あまり期待せず、お待ちいただければと思います。さんが、Qtの記録代わりにネタを投稿してくださる予定です。今年は私も含め、期日に間に合わない方も多いですが、師も走る12月というわけで、焦らずのんびりお待ちいただければと思います。requestStockLike3@hermit4文系出身のなんちゃってプログラマです。フリーランスで細々と生きてます。C++でお仕事して生きてますが、Lispとwhitespace見たいな目で追うのがつらい言語以外はたいてい好きです。upLoginユーザーは見つかりませんでした。