Qmakeの重要なガイド
公開: 2022-03-11序章
qmakeは、Qtライブラリに付属しているビルドシステムツールであり、さまざまなプラットフォーム間でビルドプロセスを簡素化します。 CMakeやQbsとは異なり、qmakeは最初からQtの一部であり、「ネイティブ」ツールと見なされます。 言うまでもなく、QtのデフォルトIDEであるQt Creatorは、箱から出してすぐにqmakeを最大限にサポートします。 はい、そこで新しいプロジェクト用にCMakeとQbsビルドシステムを選択することもできますが、これらはそれほどうまく統合されていません。 Qt CreatorでのCMakeのサポートは時間の経過とともに改善される可能性があります。これは、特にCMakeを対象としたこのガイドの第2版を発行する十分な理由になります。 Qt Creatorを使用する予定がない場合でも、パブリックライブラリまたはプラグインをビルドする場合は、qmakeを2番目のビルドシステムとして検討することをお勧めします。 事実上すべてのサードパーティのQtベースのライブラリまたはプラグインは、qmakeベースのプロジェクトにシームレスに統合するために使用されるqmakeファイルを提供します。 qmakeとCMakeなど、デュアル構成を提供しているのはごくわずかです。 以下が当てはまる場合は、qmakeの使用をお勧めします。
- クロスプラットフォームのQtベースのプロジェクトを構築しています
- QtCreatorIDEとそのほとんどの機能を使用しています
- 他のqmakeプロジェクトで使用するスタンドアロンのライブラリ/プラグインを構築しています
このガイドでは、最も便利なqmake機能について説明し、それぞれの実際の例を示します。 Qtを初めて使用する読者は、このガイドをQtのビルドシステムのチュートリアルとして使用できます。 Qt開発者は、新しいプロジェクトを開始するときにこれをクックブックとして扱うか、影響の少ない既存のプロジェクトのいずれかに一部の機能を選択的に適用できます。
Qmakeの基本的な使用法
qmake仕様は、 .pro
(「プロジェクト」)ファイルに記述されています。 これは、可能な限り最も単純な.pro
ファイルの例です。
SOURCES = hello.cpp
デフォルトでは、これにより、単一のソースコードファイルhello.cpp
から実行可能ファイルをビルドするMakefile
が作成されます。
バイナリ(この場合は実行可能)をビルドするには、最初にqmakeを実行してMakefileを生成し、次にmake
(またはツールチェーンによってはnmake
、またはmingw32-make
)を実行してターゲットをビルドする必要があります。
一言で言えば、qmake仕様は、オプションの制御フローステートメントと混合された変数定義のリストにすぎません。 一般に、各変数は文字列のリストを保持します。 制御フローステートメントを使用すると、他のqmake仕様ファイルを含めたり、条件セクションを制御したり、関数を呼び出したりすることができます。
変数の構文を理解する
既存のqmakeプロジェクトを学習するとき、さまざまな変数を参照する方法に驚かれるかもしれません: \(VAR、\){VAR}または$$(VAR) …
ルールを採用しながら、このミニチートシートを使用してください。
-
VAR = value
を割り当てます VAR += value
valueVARリストに値を追加しますVAR -= value
を削除します$$VAR
または$${VAR}
qmakeの実行時にVARの値を取得します$(VAR)
Makefile(qmakeではない)の実行時の環境VARの内容$$(VAR)
qmake(Makefileではない)の実行時の環境VARの内容
共通のテンプレート
qmake変数の完全なリストは、仕様に記載されています:http://doc.qt.io/qt-5/qmake-variable-reference.html
プロジェクトのいくつかの一般的なテンプレートを確認しましょう。
# Windows application TEMPLATE = app CONFIG += windows # Shared library (.so or .dll) TEMPLATE = lib CONFIG += shared # Static library (.a or .lib) TEMPLATE = lib CONFIG += static # Console application TEMPLATE = app CONFIG += console
SOURCES+=…とHEADERS+=…を追加するだけで、すべてのソースコードファイルが一覧表示されます。これで完了です。
これまで、非常に基本的なテンプレートを確認してきました。 より複雑なプロジェクトには通常、相互に依存関係のあるいくつかのサブプロジェクトが含まれます。 qmakeでこれを管理する方法を見てみましょう。
サブプロジェクト
最も一般的なユースケースは、1つまたは複数のライブラリとテストプロジェクトに付属しているアプリケーションです。 次の構造を検討してください。
/project ../library ..../include ../library-tests ../application
明らかに、次のように、すべてを一度に構築できるようにしたいと考えています。
cd project qmake && make
この目標を達成するには、 /project
フォルダーの下にqmakeプロジェクトファイルが必要です。
TEMPLATE = subdirs SUBDIRS = library library-tests application library-tests.depends = library application.depends = library
注: CONFIG += ordered
を使用することは悪い習慣と見なされます。代わりに.depends
を使用することをお勧めします。
この仕様は、他のターゲットがそれに依存しているため、最初にライブラリサブプロジェクトをビルドするようにqmakeに指示します。 次に、 library-tests
とアプリケーションを任意の順序で構築できます。これは、これら2つが依存しているためです。
ライブラリのリンク
上記の例では、アプリケーションにリンクする必要のあるライブラリがあります。 C / C ++では、これは、さらにいくつかの設定が必要であることを意味します。
-
-I
を指定して、#includeディレクティブの検索パスを指定します。 -
-L
を指定して、リンカーの検索パスを指定します。 -
-l
を指定して、リンクする必要のあるライブラリーを指定します。
すべてのサブプロジェクトを移動可能にする必要があるため、絶対パスまたは相対パスを使用することはできません。 たとえば、これは行いません: INCLUDEPATH + = ../library/includeそしてもちろん、一時ビルドフォルダからライブラリバイナリ(.aファイル)を参照することはできません。 「関心の分離」の原則に従うと、アプリケーションプロジェクトファイルがライブラリの詳細から抽象化されることがすぐにわかります。 代わりに、ヘッダーファイルなどの場所を指定するのはライブラリの責任です。
qmakeのinclude()
ディレクティブを利用して、この問題を解決しましょう。 ライブラリプロジェクトでは、拡張子が.pri
の新しいファイルに別のqmake仕様を追加します(拡張子は何でもかまいませんが、ここではi
を表します)。 したがって、ライブラリには、 library.pro
とlibrary.pri
の2つの仕様があります。 1つ目はライブラリの構築に使用され、2つ目は消費するプロジェクトに必要なすべての詳細を提供するために使用されます。
library.priファイルの内容は次のようになります。
LIBTARGET = library BASEDIR = $${PWD} INCLUDEPATH *= $${BASEDIR}/include LIBS += -L$${DESTDIR} -llibrary
BASEDIR
は、ライブラリプロジェクトのフォルダを指定します(正確には、現在のqmake仕様ファイルの場所(この場合はlibrary.pri
))。 ご想像のとおり、 INCLUDEPATH
は/project/library/include
に対して評価されます。 DESTDIR
は、ビルドシステムが(.o .a .so .dllまたは.exeファイル)などの出力アーティファクトを配置するディレクトリです。 これは通常、IDEで構成されているため、出力ファイルの場所を想定しないでください。
application.pro
ファイルにinclude(../library/library.pri)
を追加するだけで、完了です。
この場合、アプリケーションプロジェクトがどのように構築されているかを確認しましょう。
- 最上位の
project.pro
はsubdirsプロジェクトです。 ライブラリプロジェクトを最初に構築する必要があることがわかります。 したがって、qmakeはライブラリのフォルダに入り、library.pro
を使用してビルドします。 この段階で、library.a
が作成され、DESTDIR
フォルダーに配置されます。 - 次に、qmakeはアプリケーションサブフォルダーに入り、
application.pro
ファイルを解析します。include(../library/library.pri)
ディレクティブを見つけます。これは、qmakeにそれをすぐに読み取って解釈するように指示します。 これにより、LIBS
変数とINCLUDEPATH
変数に新しい定義が追加されるため、コンパイラとリンカは、インクルードファイルの検索場所、ライブラリバイナリ、およびリンクするライブラリを認識します。
ライブラリテストプロジェクトの構築をスキップしましたが、アプリケーションプロジェクトと同じです。 明らかに、私たちのテストプロジェクトは、テストすることになっているライブラリをリンクする必要もあります。

この設定により、ライブラリプロジェクトを別のqmakeプロジェクトに簡単に移動して含めることができ、それによって.pri
ファイルを参照できます。 これはまさに、サードパーティのライブラリがコミュニティによって配布される方法です。
config.pri
複雑なプロジェクトでは、多くのサブプロジェクトで使用されるいくつかの共有構成パラメーターを持つことが非常に一般的です。 重複を避けるために、 include()
ディレクティブを再度利用して、最上位フォルダーにconfig.pri
を作成できます。 このガイドで次に説明するのと同様に、サブプロジェクトに共通のqmake「ユーティリティ」を共有することもできます。
アーティファクトをDESTDIRにコピーする
多くの場合、プロジェクトには、ライブラリまたはアプリケーションと一緒に配布する必要のある「その他の」ファイルがいくつかあります。 ビルドプロセス中に、そのようなすべてのファイルをDESTDIR
にコピーできる必要があります。 次のスニペットについて考えてみます。
defineTest(copyToDestDir) { files = $$1 for(FILE, files) { DDIR = $$DESTDIR FILE = $$absolute_path($$FILE) # Replace slashes in paths with backslashes for Windows win32:FILE ~= s,/,\\,g win32:DDIR ~= s,/,\\,g QMAKE_POST_LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DDIR) $$escape_expand(\\n\\t) } export(QMAKE_POST_LINK) }
注:このパターンを使用すると、ファイルで機能する独自の再利用可能な関数を定義できます。
このコードを/project/copyToDestDir.pri
に配置して、次のように要求の厳しいサブプロジェクトにinclude()
ことができるようにします。
include(../copyToDestDir.pri) MYFILES += \ parameters.conf \ testdata.db ## this is copying all files listed in MYFILES variable copyToDestDir($$MYFILES) ## this is copying a single file, a required DLL in this example copyToDestDir($${3RDPARTY}/openssl/bin/crypto.dll)
注:DISTFILESは同じ目的で導入されましたが、Unixでのみ機能します。
コード生成
事前に構築されたステップとしてのコード生成の良い例は、C++プロジェクトがGoogleprotobufを使用している場合です。 ビルドプロセスにprotoc
実行を注入する方法を見てみましょう。
あなたは簡単に適切な解決策をグーグルすることができます、しかしあなたは1つの重要なコーナーケースに注意する必要があります。 AがBを参照している2つの契約があるとします。
A.proto <= B.proto
最初にA.proto
のコードを生成して( A.pb.h
とA.pb.cxx
を生成するために)、それをコンパイラーにフィードすると、依存関係B.pb.h
がまだ存在しないため、失敗します。 これを解決するには、結果のソースコードをビルドする前に、すべてのプロトコード生成ステージを通過する必要があります。
このタスクの優れたスニペットをここで見つけました:https://github.com/jmesmon/qmake-protobuf-example/blob/master/protobuf.pri
これはかなり大きなスクリプトですが、使用方法をすでに知っている必要があります。
PROTOS = A.proto B.proto include(protobuf.pri)
protobuf.pri
を調べると、カスタムコンパイルやコード生成に簡単に適用できる一般的なパターンに気付くかもしれません。
my_custom_compiler.name = my custom compiler name my_custom_compiler.input = input variable (list) my_custom_compiler.output = output file path + pattern my_custom_compiler.commands = custom compilation command my_custom_compiler.variable_out = output variable (list) QMAKE_EXTRA_COMPILERS += my_custom_compiler
範囲と条件
多くの場合、WindowsやMacOSなどの特定のプラットフォーム専用に宣言を定義する必要があります。 Qmakeは、win32、macx、およびunixの3つの事前定義されたプラットフォームインジケータを提供します。 構文は次のとおりです。
win32 { # add Windows application icon, not applicable to unix/macx platform RC_ICONS += icon.ico }
スコープはネストでき、演算子を使用できます!
、 |
そしてワイルドカードさえ:
macx:debug { # include only on Mac and only for debug build HEADERS += debugging.h } win32|macx { HEADERS += windows_or_macx.h } win32-msvc* { # same as win32-msvc|win32-mscv.net }
注:UnixはMacOSで定義されています。 Mac OS(汎用Unixではない)をテストする場合は、 unix:!macx
条件を使用します。
Qt Creatorでは、スコープ条件のdebug
とrelease
が期待どおりに機能していません。 これらを正しく機能させるには、次のパターンを使用します。
CONFIG(debug, debug|release) { LIBS += ... } CONFIG(release, debug|release) { LIBS += ... }
便利な機能
Qmakeには、自動化を追加する多数の組み込み関数があります。
最初の例はfiles()
関数です。 可変数のソースファイルを生成するコード生成ステップがあると仮定します。 これらすべてをSOURCES
に含める方法は次のとおりです。
SOURCES += $$files(generated/*.c)
これにより、 generated
れたサブフォルダー内の拡張子が.c
のすべてのファイルが検索され、それらがSOURCES
変数に追加されます。
2番目の例は前の例と似ていますが、コード生成により、出力ファイル名(ファイルのリスト)を含むテキストファイルが生成されます。
SOURCES += $$cat(generated/filelist, lines)
これにより、ファイルの内容が読み取られ、各行がSOURCES
のエントリとして扱われます。
注:組み込み関数の完全なリストはここにあります:http://doc.qt.io/qt-5/qmake-function-reference.html
警告をエラーとして扱う
次のスニペットは、前述の条件付きスコープ機能を使用しています。
*g++*: QMAKE_CXXFLAGS += -Werror *msvc*: QMAKE_CXXFLAGS += /WX
この複雑さの理由は、MSVCがこのオプションを有効にするための異なるフラグを持っているためです。
Gitバージョンの生成
次のスニペットは、Gitから取得した現在のSWバージョンを含むプリプロセッサ定義を作成する必要がある場合に役立ちます。
DEFINES += SW_VERSION=\\\"$$system(git describe --always --abbrev=0)\\\"
これは、 git
コマンドが使用可能である限り、どのプラットフォームでも機能します。 Gitタグを使用する場合、ブランチが先に進んだとしても、これにより最新のタグがピークになります。 git describe
コマンドを変更して、選択した出力を取得します。
結論
Qmakeは、クロスプラットフォームのQtベースのプロジェクトの構築に焦点を当てた優れたツールです。 このガイドでは、基本的なツールの使用法と、プロジェクト構造を柔軟に保ち、仕様を読みやすく維持しやすくするために最も一般的に使用されるパターンを確認しました。
Qtアプリの見栄えを良くする方法を学びたいですか? 試してみてください:ベジェ曲線とQPainterを使用してC ++で丸みを帯びたコーナー形状を取得する方法:ステップバイステップガイド