Meson よくある質問

また、MesonでXを行う方法も参照してください。

なぜMesonという名前なのですか?

名前が最初に選ばれたとき、2つの主要な制限がありました。指定された名前のDebianパッケージまたはSourceforgeプロジェクトが存在してはならないということです。これは、数十の潜在的なプロジェクト名を排除しました。ある時点で、Gluonという名前が検討されました。グルーオンは、陽子と中性子を結合する素粒子であり、ビルドシステムの仕事はソースコードとコンパイラを取得して完全な全体に結合することとよく似ています。

残念ながら、この名前も取得されていました。そこで、他の素粒子が調べられ、Mesonが利用可能であることがわかりました。

スレッド(pthreadなど)を使用する正しい方法は何ですか?

thread_dep = dependency('threads')

これは、すべてを自動的に設定します。AutotoolsやCMakeから来た人は、手動でlibpthread.soを探してこれを行いたいと思うでしょう。そうしないでください。特にクロスコンパイルを行う場合、トリッキーなコーナーケースがあります。

システムパッケージで利用できないホストでMesonを使用するにはどうすればよいですか?

バージョン0.29.0以降、MesonはPython Package Indexから入手できるため、インストールするには次のコマンドを実行するだけです。

$ pip3 install <your options here> meson

PyPIにアクセスできない場合でも、問題ありません。Mesonは、抽出されたソースのtarballまたはgit checkoutから簡単に実行できるように設計されています。最初にMesonをダウンロードする必要があります。次に、プレーンなmesonの代わりに、次のコマンドを使用してビルドを設定します。

$ /path/to/meson.py <options>

この後、Mesonの呼び出しについて気にする必要はありません。Mesonは、最初にどこから呼び出されたかを記憶し、適切に自身を呼び出します。ユーザーとして行う必要があるのは、ビルドディレクトリにcdしてmeson compileを呼び出すことだけです。

なぜワイルドカードでターゲットファイルを指定できないのですか?

ファイルを明示的に指定する代わりに、人々は次のようにしたいようです。

executable('myprog', sources : '*.cpp') # This does NOT work!

Mesonはこの構文をサポートしていません。その理由は単純です。これは、信頼性と速度の両方を兼ね備えることができないためです。信頼性とは、ユーザーがサブディレクトリに新しいソースファイルを追加した場合、Mesonがそれを検出して自動的にビルドの一部にする必要があることを意味します。

Mesonの主要な要件の1つは、高速であることです。これは、10,000個のソースファイルのツリーでno-opビルドが1秒のほんの一部しかかからないことを意味します。これは、Mesonがチェックするファイルの正確なリストを知っているためだけに可能です。ワイルドカードグロブとしてターゲットが指定されている場合、これは不可能になります。Mesonは、毎回グロブを再評価し、生成されたファイルのリストを前のリストと比較する必要があります。これは、ソースツリー全体を検査することを意味します(グロブパターンはsrc/\*/\*/\*/\*.cppのようなものになる可能性があるため)。これは効率的に行うことは不可能です。

MesonのメインバックエンドはNinjaですが、同じ理由でワイルドカードマッチもサポートしていません。

このため、すべてのソースファイルは明示的に指定する必要があります。

でも、どうしてもワイルドカードを使いたい!

信頼性と利便性のトレードオフが許容できる場合は、Mesonはワイルドカードグロビングを行うために必要なすべてのツールを提供します。設定中に任意のコマンドを実行できます。最初に、コンパイルするファイルを見つけるスクリプトを作成する必要があります。現在のディレクトリにあるすべての.cファイルを1行ずつ書き込む簡単なシェルスクリプトを次に示します。

#!/bin/sh

for i in *.c; do
  echo $i
done

次に、Mesonファイルでこのスクリプトを実行し、出力を文字列配列に変換して、ターゲットで使用します。

c = run_command('grabber.sh', check: true)
sources = c.stdout().strip().split('\n')
e = executable('prog', sources)

スクリプトは任意の実行可能ファイルであるため、シェル、Python、Lua、Perlなど、好きな言語で記述できます。

上記のように、トレードオフは、ソースディレクトリに新しいファイルを追加するだけでは、自動的にビルドに追加されないことです。追加するには、Mesonに自身を再初期化するように指示する必要があります。最も簡単な方法は、ソースルートのmeson.buildファイルに触れることです。次に、ビルドコマンドが次回実行されると、Mesonは自身を再設定します。

subdirsubprojectのどちらを使うべきですか?

答えは、ほとんどの場合subdirです。 subprojectは、非常に具体的なユースケース、つまり外部依存関係をビルドプロセスに埋め込むために存在します。例として、ゲームを作成していてSDLを使用したいとします。さらに、SDLにはMesonビルド定義が付属していると仮定しましょう。さらに、事前にビルドされたバイナリを使用するのではなく、SDLを自分でコンパイルしたいと仮定しましょう。

この場合、subprojectを使用します。その方法は、SDLのソースコードを取得して、独自のソースツリー内に配置することです。次に、sdl = subproject('sdl')を実行します。これにより、Mesonはビルドの一部としてSDLをビルドし、それにリンクしたり、その他の必要な操作を実行したりできます。

他のすべての用途では、subdirを使用します。例として、あるディレクトリに共有ライブラリをビルドし、別のディレクトリでテストをリンクしたい場合は、次のようにします。

project('simple', 'c')
subdir('src')   # library is built here
subdir('tests') # test binaries would link against the library here

なぜMakeバックエンドがないのですか?

Makeは遅いからです。これは実装の問題ではなく、Makeを高速化することはできません。詳細については、Ninjaの作者であるEvan Martinによるこの記事を読むことをお勧めします。 Makefileには、記述するのが非常に不快な構文もあり、メンテナンスの負担が大きくなります。

Ninjaの代わりにMakeを使用する唯一の理由は、Ninjaポートがないプラットフォームで作業している場合です。この場合でも、Ninjaを移植する方が、MesonのMakeバックエンドを作成するよりもはるかに少ない作業量です。

Ninjaを使用するだけで、あなたはより幸せになるでしょう。保証します。

MesonがPythonモジュールではないのはなぜですか?そうすれば、ビルド設定をPythonでコーディングできるのに。

これに関する質問は、「Mesonの設定言語はチューリング完全ではないのはなぜですか?」です。

これには多くの正当な理由があり、そのほとんどはこのWebページにまとめられています。設定ファイルでのプログラミング言語の使用に反対する

これらの理由に加えて、Pythonやその他の「実際の」プログラミング言語を公開しないことで、Mesonの実装を別の言語に移植することができます。たとえば、Pythonがパフォーマンスのボトルネックになる場合、これは必要になる可能性があります。これは、GNU AutotoolsとSConsで合併症を引き起こした実際の問題です。

Libtoolsのexport-symbolとexport-regexに相当するものはどうすればよいですか?

GCCシンボル可視性を使用するか、リンカースクリプトを記述することによります。これには、シンボル定義がビルド定義内に埋め込まれるのではなく、スタンドアロンファイルにあるという追加の利点があります。例はこちらにあります。

GCCでは、特に指定しない限り、共有ライブラリのすべてのシンボルが自動的にエクスポートされます。 MSVCでは、デフォルトではシンボルはエクスポートされません。共有ライブラリがシンボルをエクスポートしない場合、MSVCはインポートライブラリファイルを生成しないため、エラーが発生します。解決策は、GCC wikiで指定されているようにシンボル可視性定義を追加することです。

コンパイラフラグを追加したら、ビルドが奇妙なエラーで失敗しました。何が起こっているのですか?

おそらく、これと同等のことをしました。

executable('foobar', ...
           c_args : '-some_arg -other_arg')

Mesonは*明示的*です。この特定のケースでは、文字列を空白で自動的に分割するのではなく、そのまま受け取り、シェルの呼び出しで適切に引用符で囲むなど、コンパイラーに変更せずに渡すために特別な努力をします。これは、たとえば、スペースを含むファイルが正常に機能するために必須です。複数のコマンドライン引数を渡すには、次のように配列に明示的に配置する必要があります。

executable('foobar', ...
           c_args : ['-some_arg', '-other_arg'])

デフォルトのプロジェクトオプションの変更が無視されるのはなぜですか?

おそらく、次のようなプロジェクトがありました。

project('foobar', 'cpp')

これは、GCCコンパイラではデフォルトでc++11になります。代わりにc++14を使用したいとします。そのため、定義を次のように変更します。

project('foobar', 'cpp', default_options : ['cpp_std=c++14'])

しかし、再コンパイルすると、まだc++11が使用されます。これは、デフォルトのオプションは、ビルドディレクトリを初めて設定するときにのみ参照されるためです。その後、設定には値があると見なされるため、デフォルト値は無視されます。既存のビルドディレクトリをc++14に変更するには、meson configureでビルドディレクトリを再設定するか、ビルドディレクトリを削除して最初から再作成します。

デフォルトが変更されたときにオプション値を自動的に変更しない理由は、それを確実に実行する方法を知ることができないためです。解決する必要がある実際の質問は、「オプションの値がfooでデフォルト値がbarの場合、オプション値もbarに変更する必要がありますか」です。多くの選択肢があります。

  • ユーザーがデフォルトから値を自分で変更した場合、値を元に戻してはなりません。

  • ユーザーが値を変更しておらず、デフォルト値を変更した場合、このセクションの前提は、値も変更する必要があることを示しているようです。

  • ユーザーが値をデフォルトからfooに変更し、barに戻してからデフォルト値をbarに変更したとします。取るべき正しい手順は、それだけではあいまいです。

後者の質問を解決するには、現在値と古い値だけでなく、ユーザーが値を変更したすべての回数と、どの値からどの値に変更したかを記憶する必要があります。人々はそれほど昔のことまで自分の行動を覚えていないため、長い履歴に基づいて状態を切り替えると混乱を招きます。

このため、シンプルで理解しやすいことを行います。デフォルト値はデフォルト値にすぎず、設定されたオプションの値に影響を与えることはありません。

wrapは背後でソースをダウンロードしますか?

いいえ、違います。Mesonがビルド中にネットから何かをダウンロードするには、2つの条件を満たす必要があります。

まず、subprojectsディレクトリにダウンロードURLが記載された.wrapファイルが必要です。存在しない場合、Mesonは何もしません。

2つ目の要件は、meson.buildファイルに明示的なサブプロジェクト呼び出しが必要なことです。 subproject('foobar')またはdependency('foobar', fallback : ['foobar', 'foo_dep'])のいずれかです。これらの宣言がビルドファイルにない場合、または(例えばif/elseのために)呼び出されない場合、何もダウンロードされません。

これだけでは不十分な場合、リリース0.40.0以降、Mesonにはwrap-modeというオプションがあり、--wrap-mode=nodownloadでwrapのダウンロードを完全に無効にすることができます。また、--wrap-mode=nofallbackで依存関係のフォールバックを完全に無効にすることもできます。これはnodownloadオプションも意味します。

逆に、外部依存関係が存在し、バージョン要件を満たすことができる場合でも、Mesonに常に依存関係のフォールバックを使用させたい場合(例えば、フォールバックが使用されている場合にプロジェクトが確実にビルドされるようにするため)、0.46.0以降では--wrap-mode=forcefallbackを使用できます。

なぜMesonは[プログラミング言語X]ではなくPythonで実装されているのですか?

ビルドシステムは、通常のアプリケーションとは異なる特殊な点があるからです。

おそらく最大の制限は、MesonはOSの最下層でソフトウェアをビルドするために使用されるため、新しいシステムのコアブートストラップの一部であるということです。新しいCPUアーキテクチャのサポートが追加されるたびに、Mesonを使用してコンパイルされたソフトウェアをネイティブにコンパイルする前に、システム上でMesonを実行する必要があります。この要件により、2つの厳しい制限が追加されます。

1つ目は、Mesonを動作させるためには、ブートストラップ中にすべての依存関係をビルドする必要があるため、Mesonの依存関係を最小限に抑える必要があることです。

2つ目は、Mesonは既存および将来のすべてのCPUアーキテクチャをサポートする必要があるということです。例として、多くの新しいプログラミング言語はLLVMベースのコンパイラしか利用できません。LLVMは、GCCなどに比べてCPUのサポートが限られているため、このようなプラットフォームでMesonをブートストラップするには、まずLLVMに新しいプロセッサのサポートを追加する必要があります。これはほとんどの場合、実現不可能です。

さらに、できるだけ多くのプラットフォームの開発者が、オペレーティングシステムが提供するデフォルトのツールを使用してMesonの開発に貢献できるようにしたいと考えています。実際には、これはWindowsの開発者がVisual Studioだけを使用して貢献できる必要があることを意味します。

これを書いている時点(2018年4月)では、これらの要件を満たすことができる言語は3つだけです。

  • C
  • C++
  • Python

これらのうち、私たちはPythonを選びました。なぜなら、それは私たちのニーズに最も合っているからです。

でも、Pythonを使わないMesonが欲しいんです!

エコシステムの多様性は良いことです。興味のあるユーザーには、Mesonの競合実装を自分で書いてみることをお勧めします。2021年9月現在、まさにこれを実現しようとしているプロジェクトが3つあります。

Mesonで動作しない独自のコンパイラツールチェーンXを持っています。どうすれば動作させることができますか?

Mesonは、コードをコンパイルするために、各コンパイラについていくつかの詳細を知る必要があります。これには、各オプションに使用するコンパイラフラグや、出力からコンパイラを検出する方法などが含まれます。この情報は設定ファイルから入力することはできず、Mesonのソースコードに変更を加えてMesonマスターリポジトリに送信する必要があります。理論的には、カスタムパッチを適用した独自のフォークバージョンを実行することもできますが、それは時間の無駄です。誰もがツールチェーンを使用できるように、コードをアップストリームに送信してください。

既存の言語に新しいコンパイラを追加する手順は、おおよそ以下のとおりです。簡単にするために、Cコンパイラを想定します。

  • mesonbuild/compilers/c.pyに適切な名前の新しいクラスを作成します。同じ言語の他のコンパイラが持っているメソッドを見て、それらを複製します。

  • コンパイラがクロスコンパイルにのみ使用できる場合は、必ずそのようにフラグを立ててください(例については、既存のコンパイラクラスを参照してください)。

  • mesonbuild/environment.pyに検出ロジックを追加し、detect_c_compilerというメソッドを探します。

  • テストスイートを実行し、テストに合格するまで問題を修正します。

  • プルリクエストを送信し、テストスイートの結果をMRに追加します(既存のページへのリンクで問題ありません)。

  • コンパイラが自由に利用できる場合は、CIシステムに追加することを検討してください。

MSVCでプロジェクトをビルドすると、なぜlibfoo.aという静的ライブラリが出力されるのですか?

Windowsにおける静的ライブラリの命名規則は、通常foo.libです。残念ながら、インポートライブラリもfoo.libと呼ばれています。

これは、共有ライブラリと静的ライブラリの両方をビルドするデフォルトのライブラリタイプでファイル名の衝突を引き起こし、また、デフォルトですべてのライブラリが同じディレクトリにインストールされるため、インストール中に衝突を引き起こします。

これを解決するために、MSVCでビルドする場合は、libfoo.a形式の静的ライブラリを作成することをデフォルトにしました。これには、次のような利点があります。

  1. ファイル名の衝突が完全に回避されます。
  2. MSVC静的ライブラリの形式はarであり、これはGNU静的ライブラリ形式と同じであるため、この拡張子を使用することは意味的に正しいです。
  3. 静的ライブラリファイル名の形式が、すべてのプラットフォームとすべてのツールチェーンで同じになりました。
  4. ClangとGNUコンパイラの両方が、ライブラリを-lfooとして指定すると、libfoo.aを検索できます。これは、libfoo.libなどの静的ライブラリの代替命名スキームでは機能しません。
  5. -lfooはそのまま動作するため、pkgconfigファイルは、Windows上でMSVC、GCC、およびClangの両方でビルドされたプロジェクトで正しく動作します。
  6. MSVCにはライブラリファイル名を検索する引数がなく、拡張子が何であるかは気にしません。そのため、foo.libの代わりにlibfoo.aを指定してもワークフローは変わりません。また、あいまいさが軽減されるため、改善となります。
  7. MinGWコンパイラでビルドされたプロジェクトは、同じCRT(例:MSYS2のUCRT)を使用している限り、MSVCと完全に互換性があります。これらのプロジェクトも静的ライブラリにlibfoo.aという名前を付けます。

何らかの理由で、MSVCでビルドするときにプロジェクトでfoo.lib形式の静的ライブラリを出力する必要がある場合は、name_prefix:キーワード引数を''に、name_suffix:キーワード引数を'lib'に設定できます。それぞれにデフォルトの動作を取得するには、キーワード引数を指定しないか、[](空の配列)を渡します。

Autotoolsのように、ヘッダーをソースリストに追加する必要がありますか?

Autotoolsでは、make distによって生成されるtarballに含めるファイルを認識させるために、プライベートヘッダーとパブリックヘッダーをソースリストに追加する必要があります。Mesonのdistコマンドは、git/hgリポジトリにコミットされたすべてを収集してtarballに追加するだけなので、ヘッダーをソースリストに追加しても意味がありません。

MesonはNinjaを使用しています。Ninjaはコンパイラの依存関係情報を使用してCソースとヘッダー間の依存関係を自動的に把握するため、ヘッダーが変更されたときに正しく再構築されます。

これの唯一の例外は生成されたヘッダーであり、依存関係を正しく宣言する必要があります。

何らかの理由で、生成されていないヘッダーをターゲットのソースリストに追加した場合、Mesonはそれらを単に無視します。

ソースが生成されたヘッダーを使用していることをMesonに伝えるにはどうすればよいですか?

custom_target()を使用してヘッダーを生成し、Cコードで#includeするとします。ビルドターゲットのソースをコンパイルしようとする前に、Mesonがヘッダーを生成するようにする方法を次に示します。

libfoo_gen_headers = custom_target('gen-headers', ..., output: 'foo-gen.h')
libfoo_sources = files('foo-utils.c', 'foo-lib.c')
# Add generated headers to the list of sources for the build target
libfoo = library('foo', sources: [libfoo_sources + libfoo_gen_headers])

(コード例は省略)

libbar_sources = files('bar-lib.c')
libbar = library('bar', sources: libbar_sources, link_with: libfoo)

これは2つのターゲット間に**リンク時**の依存関係を追加しますが、ターゲットのソースには**コンパイル時**の依存関係がなく、任意の順序でビルドできることに注意してください。これにより、並列処理が向上し、ビルドが高速化されます。

libbarのソースもfoo-gen.hを使用する場合、それは*コンパイル時*の依存関係であり、libbarsources:にもlibfoo_gen_headersを追加する必要があります。

libbar_sources = files('bar-lib.c')
libbar = library('bar', sources: libbar_sources + libfoo_gen_headers, link_with: libfoo)

(コード例は省略)

# Add generated headers to the list of sources for the build target
libfoo = library('foo', sources: libfoo_sources + libfoo_gen_headers)

# Declare a dependency that will add the generated headers to sources
libfoo_dep = declare_dependency(link_with: libfoo, sources: libfoo_gen_headers)

...

libbar = library('bar', sources: libbar_sources, dependencies: libfoo_dep)

**注:**依存関係を宣言するときは、*ヘッダー*のみをsources:に追加する必要があります。カスタムターゲットがソースとヘッダーの両方を出力する場合、添え字表記を使用してヘッダーのみを取得できます。

libfoo_gen_sources = custom_target('gen-headers', ..., output: ['foo-gen.h', 'foo-gen.c'])
libfoo_gen_headers = libfoo_gen_sources[0]

# Add static and generated sources to the target
libfoo = library('foo', sources: libfoo_sources + libfoo_gen_sources)

# Declare a dependency that will add the generated *headers* to sources
libfoo_dep = declare_dependency(link_with: libfoo, sources: libfoo_gen_headers)
...
libbar = library('bar', sources: libbar_sources, dependencies: libfoo_dep)

ソースとヘッダーの両方を出力するジェネレーターの良い例は、gnome.mkenums()です。

C++プロジェクトで例外とRTTIを無効にするにはどうすればよいですか?

cpp_ehcpp_rttiオプションを使用します。典型的な呼び出しは次のようになります。

meson -Dcpp_eh=none -Dcpp_rtti=false <other options>

(コード例は省略)

ビルドファイルでは、buildtypeをチェックする必要がありますか、それともdebugのような個々のオプションをチェックする必要がありますか?

これは、実際に何を実行する必要があるかによって大きく異なります。´buildtype`オプションは、現在のビルドの*意図*を記述するためのものです。つまり、それが何に使用されるかです。個々のオプションは、正確な状態がどうなっているかを判断するためのものです。これは、いくつかの例でより明確になります。

-O3を使用すると誤ってコンパイルされることがわかっており、回避策が必要なソースファイルがあるとします。その場合は、次のように記述します。

if get_option('optimization') == '3'
    add_project_arguments('-DOPTIMIZATION_WORKAROUND', ...)
endif

(コード例は省略)

if get_option('buildtype') == 'debug'
    add_project_arguments('-DENABLE_EXTRA_CHECKS', ...)
endif

(コード例は省略)

ライブラリを宣言する前に使用するにはどうすればよいですか?

これは有効な(そして良い)コードです。

libA = library('libA', 'fileA.cpp', link_with : [])
libB = library('libB', 'fileB.cpp', link_with : [libA])

(コード例は省略)

libB = library('libB', 'fileB.cpp', link_with : [libA])
libA = library('libA', 'fileA.cpp', link_with : [])

(コード例は省略)

なぜmesonにはユーザー定義関数/マクロがないのですか?

簡単な答えは、mesonの設計は、ビルドファイルに複雑なコードソリューションを記述するための汎用言語を提供するのではなく、特定の問題を解決することに焦点を当てているということです。ビルドシステムは、記述が容易で理解しやすいものでなければなりません。関数は、このシンプルさを損ないます。

長い答えは2つあります。

まず、Mesonは、特定の問題を簡単に解決するための豊富なツールセットを提供することを目指しています。これは、Pythonの「バッテリー同梱」の考え方と似ています。Meson *内部* で、一般的な問題を可能な限り簡単な方法で解決するツールを提供することで、すべての人がその問題を何度も繰り返し、しかも多くの場合不適切に解決することを強いられるのではなく、すべての人にとってその問題を解決することになります。この例としては、Mesonのさまざまな設定ツール実行ファイル(sdl-config、llvm-configなど)の依存関係ラッパーがあります。他のビルドシステムでは、その依存関係の各ユーザーがラッパーを作成し、コーナーケースを処理します(多くの場合、処理されませんが)。Mesonでは、それらを内部的に処理し、すべての人が修正を受け取り、コーナーケースは*すべての人* にとって解決されます。ユーザー定義関数やマクロを提供することは、この設計目標に真っ向から反します。

次に、関数とマクロは、ビルドシステムの推論を難しくします。関数呼び出しに遭遇した場合、リファレンスマニュアルを参照して、その関数とそのシグネチャを確認できます。m4の一部を解釈したり、長いインクルードパスをたどって `function1`(`function2` を呼び出し、`function2` は `function3` を呼び出し、無限に続く)が何をしているかを理解しようとするイライラする時間を費やす代わりに、ビルドシステムが何をしているかがわかります。Meson自体を積極的に開発していない限り、ビルドシステムは実際に気にしているものを構築するためのツールにすぎません。ビルドシステムの心配に時間をかけずに、*自分のコード* により多くの時間を費やせるようにしたいと考えています。

多くの場合、ユーザー定義関数は、ループがないため、または言語でループを使用するのが面倒なために使用されます。Mesonは、配列/リストとハッシュ/辞書をネイティブに備えています。次の擬似コードを比較してください。

func(name, sources, extra_args)
  executable(
    name,
    sources,
    c_args : extra_args
  )
endfunc

func(exe1, ['1.c', 'common.c'], [])
func(exe2, ['2.c', 'common.c'], [])
func(exe2_a, ['2.c', 'common.c'], ['-arg'])
foreach e : [['1', '1.c', []],
             ['2', '2.c', []],
             ['2', '2.c', ['-arg']]]
  executable(
    'exe' + e[0],
    e[1],
    c_args : e[2],
  )
endforeach

ループはコードが少なく、関数バージョンよりもはるかに推論しやすいです。特に、他の一般的なビルドシステムでよくあるように、関数が別のファイルにある場合はなおさらです。

ビルドシステムDSLは、汎用プログラミング言語としてよく考えられていない傾向もあります。Mesonは、複雑な問題を処理するために外部スクリプトまたはプログラムを簡単に使用できるようにしようとします。ビルドロジックをスクリプト言語(またはコンパイル言語)に変換できない場合もありますが、変換できる場合は、多くの場合、これがより良い解決策になります。外部言語は、よく考え抜かれ、テストされており、一般的に退行せず、ユーザーはそれらに関するドメイン知識を持っている可能性が高くなります。また、自動補完、リンティング、テストソリューションなどの優れたツールを備えている傾向があり、時間の経過とともにメンテナンスの負担が軽減されます。

このようなコードが与えられた場合

add_project_link_arguments(['-Wl,-foo'], language : ['c'])
executable(
  'main',
  'main.c',
  'helper.cpp',
)

`-Wl,-foo` が `main` 実行可能ファイルのリンクに適用*されない* ことに驚くかもしれません。これはMesonが期待どおりに動作しているためです。mesonは使用する正しいリンカーを自動的に決定しようとするためです。これにより、autotoolsのように、正しいリンケージを取得するためにダミーのC ++ソースを一部のコンパイルターゲットに追加する必要があるという状況を回避できます。したがって、上記のケースでは、`helper.cpp` はCリンカーを使用してリンクできない可能性が高いため、CリンカーではなくC ++リンカーが使用されます。

一般的に、これを解決する最良の方法は、`add_project_link_arguments` 呼び出しに `cpp` 言語を追加することです。

add_project_link_arguments(['-Wl,-foo'], language : ['c', 'cpp'])
executable(
  'main',
  'main.c',
  'helper.cpp',
)

とにかくCリンカーの使用を強制するには、`link_language`キーワード引数を使用できます。Cリンカーが解決できないシンボルがある場合、これによりコンパイルエラーが発生する可能性があることに注意してください。

add_project_link_arguments(['-Wl,-foo'], language : ['c'])
executable(
  'main',
  'main.c',
  'helper.cpp',
  link_language : 'c',
)

VCSでビルドディレクトリを無視するにはどうすればよいですか?

gitまたはmercurialを使用している場合は、必要ありません! Meson> = 0.57.0は、各ビルドディレクトリ内に `。gitignore` および `.hgignore` ファイルを作成します。生成されたすべてのファイルはgitにチェックインされないため、globは `"*"` を無視します。

古いバージョンのMesonのユーザーは、自分で無視ファイルをセットアップする必要がある場合があります。

ターゲットにプリプロセッサ定義を追加するにはどうすればよいですか?

`c_args` または `cpp_args` に `-DFOO` を追加するだけです。これは、既知のすべてのコンパイラで機能します。

mylib = library('mylib', 'mysource.c', c_args: ['-DFOO'])

MSVCドキュメントではプリプロセッサ定義に `/D` を使用していますが、コマンドライン構文では `/` の代わりに `-` を使用できます。 Mesonでプリプロセッサ定義を特別に扱う必要はありません(GH-6269)。

検索結果は次のとおりです。