クロスコンパイル

Mesonは、クロスビルド定義ファイルを使用することで、クロスコンパイルを完全にサポートしています。64ビットWindowsをターゲットとしたGCC/MinGWクロスコンパイラ用のこのようなファイルの最小限の例x86_64-w64-mingw32.txtは次のようになります。

[binaries]
c = 'x86_64-w64-mingw32-gcc'
cpp = 'x86_64-w64-mingw32-g++'
ar = 'x86_64-w64-mingw32-ar'
windres = 'x86_64-w64-mingw32-windres'
strip = 'x86_64-w64-mingw32-strip'
exe_wrapper = 'wine64'

[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'

これは、setupフェーズ中に使用されます。

meson setup --cross-file x86_64-w64-mingw32.txt build-mingw
meson compile -C build-mingw

クロスコンパイルはネイティブビルドよりも複雑であるため、まずいくつかの用語について説明します。最も重要な3つの定義は、従来、*build*、*host*、*target*と呼ばれています。これらの用語は非常に多くの異なることに使用されているため、混乱を招きます。問題を単純化するために、これらを*ビルドマシン*、*ホストマシン*、*ターゲットマシン*と呼ぶことにします。これらの定義は次のとおりです。

  • ビルドマシンは、実際のコンパイルを実行するコンピュータです。
  • ホストマシンは、コンパイルされたバイナリが実行されるマシンです。
  • ターゲットマシンは、コンパイルされたバイナリの出力が実行されるマシンであり、プログラムがマシン固有の出力を生成する場合のみ意味があります

tl/drの要約は次のとおりです。通常のクロスコンパイルを行っている場合は、build_machinehost_machineのみを気にすればよいのです。target_machineは完全に無視すれば、99%の場合で正しいでしょう。コンパイラや同様のツールのみがターゲットマシンを気にします。実際、いわゆる「マルチターゲット」ツールの場合、ターゲットマシンは、他のツールのようにビルド時に固定する必要はなく、実行時に選択されるため、target_machineまだ重要ではありません。より複雑なニーズがある場合や、実際の詳細に興味がある場合は、読み進めてください。

これは、例を通して理解するのがより簡単かもしれません。まず、通常のクロスコンパイルではないケースから始めましょう。これらのケースでは、これら3つのマシンはすべて同じです。今のところは簡単です。

次に、最も一般的なクロスコンパイルの設定を見てみましょう。64ビットのOSXマシンにいて、32ビットのARM Linuxボードで実行されるバイナリをクロスコンパイルしていると仮定します。この場合、ビルドマシンは64ビットOSX、ホストマシンは32ビットARM Linux、ターゲットマシンは無関係(ただし、ホストマシンと同じ値にデフォルト設定されます)です。これもかなり理解できるはずです。

この場合のよくある間違いは、OSXシステムをホスト、ARM Linuxボードをターゲットと呼ぶことです。これは、クロスコンパイラ自体がコンパイルされたときの実際の名前がそうだったからです!クロスコンパイラがOSXでも作成されたと仮定しましょう。その時、*ビルド*マシンと*ホスト*マシンは同じOSXであり、ARM Linuxの*ターゲットマシン*とは異なっていました。

簡単に言うと、典型的な間違いは、*build*、*host*、*target*という用語がいくつかの固定された位置を指すと考えがちですが、実際には現在のコンパイラの実行場所に対して相対的であるということです。hostを現在のコンパイラのtargetをオプションのと考えてください。コンパイラは、別のコンパイラを作成するときに用語を変更しません。少なくともユーザーインターフェースが非常に複雑になるでしょう。

最も複雑なケースは、クロスコンパイラをクロスコンパイルする場合です。例として、Linuxマシンで、Windows上で実行され、MIPS Linuxでバイナリを生成するクロスコンパイラを生成できます。この場合、ビルドマシンはx86 Linux、ホストマシンはx86 Windows、ターゲットマシンはMIPS Linuxです。この設定は、カナディアンクロスとして知られています。余談ですが、Wikipediaやネット上のクロスコンパイルに関する記事を読むときは注意してください。ビルド、ホスト、ターゲットが混同されていることが非常に多く、連続した文章でもそうなるため、理解するまで困惑することがあります。

再度注意すべき点は、何かをクロスコンパイルする場合、クロスコンパイラの構築時に使用した3つのシステム(*build*、*host*、*target*)は、その新しく構築されたクロスコンパイラで何かを構築するときに使用するシステムとは一致しないということです。(完全に一般的にするために)上記のカナディアンクロスのシナリオを取ると、そのホストマシンはx86 Windowsであるため、それで構築するもののビルドマシンx86 Windowsになります。そして、そのターゲットマシンはMIPS Linuxであるため、それで構築するもののホストマシンMIPS Linuxになります。それで構築するもののターゲットマシンのみが、自由に選択できます。たとえば、MIPS Linuxで実行され、Aarch64 iOSをターゲットとする別のクロスコンパイラを構築する場合などです。この例から、マシン名は相対的であり、左に1つシフトされることが明確になるはずです。

すべての詳細を理解できなかったとしても、心配しないでください。ほとんどの人にとって、これらの概念を理解するにはしばらく時間がかかります。慌てないでください。理解するまで時間がかかるかもしれませんが、最終的にはコツをつかむでしょう。

環境の定義

Mesonでは、クロスビルド定義ファイルを記述する必要があります。これは、クロスビルド環境のさまざまなプロパティを定義します。クロスファイルは、さまざまなセクションで構成されています。

クロスファイルとネイティブファイルで共有されるオプションがいくつかあります。詳しくはこちらをご覧ください。このドキュメントではクロスファイルに固有のオプションのみを説明するため、すでにそのセクションを読んでいることを前提としています。

バイナリ

[binaries]
exe_wrapper = 'wine' # A command used to run generated executables.

exe_wrapperオプションは、このホストの実行ファイルを実行するために使用できるラッパーコマンドを定義します。この場合、LinuxでWindowsアプリケーションを実行するWineを使用できます。その他の選択肢としては、qemuまたはハードウェアシミュレータでアプリケーションを実行する方法があります。このようなラッパーがある場合は、これらの行を記述するだけで済みます。Mesonは、ホストバイナリを実行する必要がある場合に、指定されたラッパーを自動的に使用します。これは、たとえば、プロジェクトのテストスイートを実行する場合などに発生します。

プロパティ

すべてのマシンファイルで許可されているプロパティに加えて、クロスファイルには、クロスコンパイラまたはホストマシンに関する特定の情報を含めることができます。次のようになります。

[properties]
sizeof_int = 4
sizeof_wchar_t = 4
sizeof_void* = 4

alignment_char = 1
alignment_void* = 4
alignment_double = 4

has_function_printf = true

sys_root = '/some/path'
pkg_config_libdir = '/some/path/lib/pkgconfig'

ほとんどの場合、サイズとアライメントの設定は必要ありません。Mesonは、いくつかのサンプルプログラムをコンパイルして実行することで、これらをすべて検出します。ビルドにここにリストされていないデータが必要な場合、Mesonは停止し、問題を修正する方法を説明するエラーメッセージを書き込みます。クロスコンパイル中に使用する追加のコンパイラ引数が必要な場合は、[langname]_args = [args]で設定できます。引数は、単一の文字列としてではなく(つまり、'-DCROSS=1 -DSOMETHING=3'のようにではなく)、配列として指定することを忘れないでください。

0.52.0以降sys_rootプロパティは、ホストシステムのパスのルート(コンパイルされたバイナリを実行するシステム)を指す場合があります。これは、pkg-configのPKG_CONFIG_SYSROOT_DIR環境変数を設定するためにMesonによって内部的に使用されます。これが設定されていない場合、ホストシステムはビルドシステムとルートを共有すると想定されます。

0.54.0以降、pkg_config_libdirプロパティは、pkg-configのPKG_CONFIG_LIBDIR環境変数を設定するためにMesonによって内部的に使用されるパスのリストを指す場合があります。これにより、pkg-configがシステムディレクトリでクロス依存関係を検索するのを防ぎます。

前のセクションでexe_wrapperを定義しなかった場合に注意すべき重要なことの1つは、Mesonが生成されたバイナリをビルドマシンで実行できるかどうかを最善を尽くして推測することです。これは、ビルドとホストのsystemcpu_familyを調べることで可能かどうかを判断します。ただし、一致しても、ビルドマシンが実際にはホストマシンと互換性がない場合があります。通常、これは、ビルドマシンとホストマシンで使用されるlibcが互換性がない場合、またはコードがビルドマシンでは利用できないカーネル機能に依存している場合に発生します。具体的な例として、macOSビルドマシンがiOS Simulator x86-64ホスト用のバイナリを生成する場合があります。両方ともdarwinで同じアーキテクチャですが、バイナリは実際には互換性がありません。このような場合は、needs_exe_wrapperプロパティを使用して自動検出を上書きできます。

[properties]
needs_exe_wrapper = true

マシンエントリ

次の部分は、ホストマシンとターゲットマシンの定義です。すべてのクロスビルド定義には、それらのいずれかまたは両方が含まれている必要があります。どちらもない場合、ビルドはクロスビルドではなくネイティブビルドになります。ビルドマシンを定義する必要はありません。必要なすべての情報が自動的に抽出されるためです。ホストマシンとターゲットマシンの定義は同じように見えます。ホストマシンのサンプルを次に示します。

[host_machine]
system = 'windows'
subsystem = 'windows'
kernel = 'nt'
cpu_family = 'x86'
cpu = 'i686'
endian = 'little'

これらの値は、クロスコンパイルの目的でマシンを十分に定義します。対応するターゲット定義は同じように見えますが、ヘッダーにtarget_machineが含まれます。これらの値は、Mesonスクリプトで使用できます。驚くべきことに、build_machinehost_machinetarget_machineという3つの事前定義された変数があります。ホストマシンのオペレーティングシステムを特定するには、単にhost_machine.system()を呼び出すだけです。バージョン1.2.0以降では、.subsystem()メソッドと.kernel()メソッドを使用して、より詳細な情報を取得できます。これらの関数の戻り値は、リファレンステーブルページに記載されています。

CPUには2つの異なる値があります。1つ目はcpu_familyです。これは、CPUの一般的なタイプです。これには、CPUファミリーテーブルの値を含める必要があります。注意:Mesonは、リトルエンディアンシステムのcpu_familyの値の末尾にelを追加しません。ビッグエンディアンとリトルエンディアンのmipsは両方とも単にmipsであり、endianフィールドが適切に設定されています。

2番目の値はcpuで、CPUのより具体的なサブタイプです。x86 CPUファミリの典型的な値にはi386i586があり、armファミリにはarmv5armv7hlがあります。CPUタイプの文字列はシステムに大きく依存することに注意してください。同じマシンでも、異なるオペレーティングシステムで値を確認すると異なる値が得られる可能性があります。

ホストマシンを定義しない場合、ビルドマシンであると見なされます。同様に、ターゲットマシンを指定しない場合、ホストマシンであると見なされます。

クロスビルドの開始

クロスファイルがあれば、ビルドの開始は簡単です。

$ meson setup builddir --cross-file cross_file.txt

構成が完了したら、通常の方法でmeson compileを呼び出すことでコンパイルが開始されます。

イントロスペクションとシステムチェック

メインのmesonオブジェクトは、クロスコンパイルのステータスを判断するための2つの関数を提供します。

meson.is_cross_build()        # returns true when cross compiling
meson.can_run_host_binaries() # returns true if the host binaries can be run, either with a wrapper or natively

システムコンパイラとクロスコンパイラのどちらでもシステムチェックを実行できます。どちらを使用するかを指定するだけです。

build_compiler = meson.get_compiler('c', native : true)
host_compiler = meson.get_compiler('c', native : false)

build_int_size = build_compiler.sizeof('int')
host_int_size  = host_compiler.sizeof('int')

ホストターゲットとビルドターゲットの混合

ソースファイルを生成するために使用されるツールをビルドする必要がある場合があります。これらは、実際のターゲット用にコンパイルされます。この場合、システムのネイティブコンパイラでいくつかのターゲットをビルドする必要があります。これには、追加のキーワード引数が1つだけ必要です。

native_exe = executable('mygen', 'mygen.c', native : true)

その後、native_exeを取得し、ジェネレータールールの一部として、またはその他必要なものとして使用できます。

カスタム標準ライブラリの使用

クロスコンパイルでは、コンパイラが提供するものではなく、独自の標準ライブラリをビルドする必要がある場合があります。Mesonには、標準ライブラリを透過的に切り替えるための組み込みサポートがあります。クロスファイルで使用する呼び出しは次のとおりです。

[properties]
c_stdlib = ['mylibc', 'mylibc_dep'] # Subproject name, variable name

これは、C標準ライブラリがMesonサブプロジェクトmylibcの内部依存変数mylibc_depで提供されていることを指定します。ソースツリー全体(サブプロジェクトを含む)のすべてのクロスビルドされたCターゲットで使用され、標準ライブラリは無効になります。これらのターゲットのビルド定義は変更する必要はありません。

<lang>_stdlibプロパティを使用すると、cだけでなく、すべての言語でサポートされていることに注意してください。

0.56.0以降、サブプロジェクトがmeson.override_dependency('c_stdlib', mylibc_dep)を呼び出す限り、変数名パラメーターは不要になりました。上記の例は次のようになります。

[properties]
c_stdlib = 'mylibc'

クロスファイル設定の変更

クロスファイルの設定は、ビルドディレクトリが最初に設定されたときにのみ読み取られます。後で変更しても無視されます。これは、ビルドツリーを設定した後でコンパイラを変更できない通常のコンパイルと同じです。クロスファイルを編集する必要がある場合は、ビルドツリーを消去して最初から再作成する必要があります。

カスタムデータ

propertiesに任意のデータを保存し、Mesonファイルからアクセスできます。例として、クロスファイルに次のようなものがあるとします。

[properties]
somekey = 'somevalue'

次に、次のようにmesonオブジェクトを使用してアクセスできます。

myvar = meson.get_external_property('somekey')
# myvar now has the value 'somevalue'

クロスファイルの場所

バージョン0.44.0以降、Mesonは(Windowsを除き)システムロケーションからのクロスファイルのロードをサポートしています。これは、$XDG_DATA_DIRS/meson/crossになります。または、XDG_DATA_DIRSが未定義の場合、システム全体のクロスファイルについては、/usr/local/share/meson/crossと/usr/share/meson/crossがこの順序で試行されます。ユーザーローカルファイルは、$XDG_DATA_HOME/meson/cross、またはそれが未定義の場合は~/.local/share/meson/crossに配置できます。

試行される場所の順序は次のとおりです。

  • ローカルディレクトリに対する相対ファイル
  • ユーザーローカルの場所
  • システム全体の場所(順序どおり)

ディストリビューションは、クロスコンパイラツールチェーンパッケージまたはスタンドアロンパッケージでクロスファイルを配布し、上記で参照したシステムパスのいずれかに配置することが推奨されます。

これらのファイルは、クロスファイルへのパスを追加せずに自動的にロードできます。たとえば、~/.local/share/meson/crossにx86-linuxというファイルが含まれている場合、次のコマンドは、そのクロスファイルを使用してクロスビルドを開始します。

meson setup builddir/ --cross-file x86-linux

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