Bazel は、プラットフォームとツールチェーンのモデリングを高度にサポートしています。これを実際のプロジェクトと統合するには、コードオーナー、ルール メンテナンス担当者、Bazel のコア デベロッパーとの慎重な連携が必要です。
このページでは、プラットフォームの目的と、プラットフォームを使用してビルドする方法について説明します。
要約: Bazel のプラットフォーム API と toolchain API は使用できますが、すべての言語ルール、select()
、その他のレガシー参照が更新されるまで、すべての環境で動作するわけではありません。これは継続的な取り組みです。最終的には、すべてのビルドがプラットフォーム ベースになります。ビルドがどのカテゴリに該当するかについては、以下をご覧ください。
より正式なドキュメントについては、以下をご覧ください。
背景
プラットフォームとツールチェーンは、ソフトウェア プロジェクトがさまざまなマシンをターゲットにし、適切な言語ツールでビルドする方法を標準化するために導入されました。
これは Bazel に比較的最近追加されたものです。これは、言語メンテナンス担当者が、互換性のないアドホックな方法ですでにこの作業を行っているという観察に基づいています。たとえば、C++ ルールでは --cpu
と --crosstool_top
を使用して、ビルドのターゲット CPU と C++ ツールチェーンを設定します。どちらも「プラットフォーム」を正しくモデル化しません。これまで、そうした試みは、不自然で不正確なビルドを招いていました。また、これらのフラグは Java コンパイルを制御しません。Java コンパイルは、--java_toolchain
で独自の独立したインターフェースを進化させています。
Bazel は、大規模なマルチ言語マルチプラットフォーム プロジェクトを対象としています。そのためには、言語とプロジェクトの相互運用性を促進する明確な API など、これらのコンセプトをより原則的にサポートする必要があります。そのために、これらの新しい API が用意されています。
移行
プラットフォーム API と toolchain API は、プロジェクトで実際に使用されている場合にのみ機能します。これは、プロジェクトのルールロジック、ツールチェーン、依存関係、select()
がそれらをサポートする必要があるため、簡単ではありません。そのためには、すべてのプロジェクトとその依存関係が正しく機能するように、慎重な移行順序が必要です。
たとえば、Bazel の C++ ルールはプラットフォームをサポートしています。ただし、Apple のルールは適用されません。お客様の C++ プロジェクトでは Apple を気にしない場合があります。ただし、他のプラットフォームでは問題が発生する可能性があります。そのため、すべての C++ ビルドでプラットフォームをグローバルに有効にすることはまだ安全ではありません。
このページの後半では、この移行シーケンスと、プロジェクトを移行する方法とタイミングについて説明します。
目標
すべてのプロジェクトが次の形式でビルドされると、Bazel のプラットフォーム移行は完了です。
bazel build //:myproject --platforms=//:myplatform
これは以下を意味します。
- プロジェクトで使用するルールは、
//:myplatform
から正しいツールチェーンを推測できます。 - プロジェクトの依存関係で使用されるルールは、
//:myplatform
から正しいツールチェーンを推測できます。 - プロジェクトが
//:myplatform
をサポートしているか、プロジェクトが以前の API(--crosstool_top
など)をサポートしているか。 //:myplatform
は、CPU
、OS
、およびプロジェクト間の自動互換性をサポートするその他の一般的なコンセプトの [共通宣言][共通プラットフォーム宣言]{: .external} を参照します。- 関連するすべてのプロジェクトの
select()
は、//:myplatform
によって暗黙的に指定されるマシン プロパティを認識します。 //:myplatform
は、明確で再利用可能な場所に定義します。プラットフォームがプロジェクトに固有の場合はプロジェクトのリポジトリに、そうでない場合は、このプラットフォームを使用する可能性のあるすべてのプロジェクトが見つけられる場所に定義します。
この目標が達成されると、古い API は直ちに削除されます。これが、プロジェクトがプラットフォームとツールチェーンを選択する標準的な方法になります。
プラットフォームを使用するべきですか?
プロジェクトのビルドまたはクロスコンパイルのみを行う場合は、プロジェクトの公式ドキュメントに沿って操作してください。
プロジェクト、言語、ツールチェーンのメンテナンス担当者は、最終的には新しい API をサポートする必要があります。グローバル マイグレーションの完了を待つか、早期にオプトインするかは、特定の価値と費用のニーズによって異なります。
値
--cpu
などのハードコードされたフラグではなく、select()
を使用するか、重要なプロパティに基づいてツールチェーンを選択できます。たとえば、複数の CPU が同じ命令セットをサポートできます。- より正確なビルド。上記の例で
select()
を--cpu
に置き換え、同じ命令セットをサポートする新しい CPU を追加すると、select()
は新しい CPU を認識できません。ただし、プラットフォーム上のselect()
は正確なままです。 - シンプルなユーザー エクスペリエンス。すべてのプロジェクトは
--platforms=//:myplatform
を認識します。コマンドラインで複数の言語固有のフラグを使用する必要はありません。 - 言語設計を簡素化。すべての言語は、ツールチェーンの定義、ツールチェーンの使用、プラットフォームに適したツールチェーンの選択に共通の API を共有します。
- ターゲットがターゲット プラットフォームと互換性がない場合、ビルドフェーズとテストフェーズでターゲットをスキップできます。
料金
- プラットフォームをまだサポートしていない依存プロジェクトは、自動的に連携しない場合があります。
- 機能させるには、追加の一時的なメンテナンスが必要になる場合があります。
- 新しい API と従来の API が共存する場合は、混乱を避けるためにユーザー ガイダンスを慎重に行う必要があります。
OS
やCPU
などの一般的なプロパティの正規定義はまだ進化中であり、追加の初期コントリビューションが必要になる場合があります。- 言語固有のツールチェーンの標準定義はまだ進化中であり、追加の初期コントリビューションが必要な場合があります。
API による審査
platform
は、constraint_value
ターゲットのコレクションです。
platform(
name = "myplatform",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:arm",
],
)
constraint_value
はマシンのプロパティです。同じ「種類」の値は、共通の constraint_setting
の下にグループ化されます。
constraint_setting(name = "os")
constraint_value(
name = "linux",
constraint_setting = ":os",
)
constraint_value(
name = "mac",
constraint_setting = ":os",
)
toolchain
は Starlark ルールです。属性は、言語のツール(compiler =
"//mytoolchain:custom_gcc"
など)を宣言します。プロバイダは、これらのツールでビルドする必要があるルールにこの情報を渡します。
ツールチェーンは、ターゲットにできるマシンの constraint_value
(target_compatible_with = ["@platforms//os:linux"]
)と、ツールを実行できるマシンの constraint_value
(exec_compatible_with = ["@platforms//os:mac"]
)を宣言します。
$ bazel build //:myproject --platforms=//:myplatform
をビルドすると、Bazel はビルドマシンで実行できるツールチェーンを選択し、//:myplatform
のバイナリをビルドします。これはツールチェーンの解決と呼ばれます。
使用可能な toolchain のセットは、WORKSPACE
で register_toolchains
を使用して登録するか、コマンドラインで --extra_toolchains
を使用して登録できます。
詳しくは、こちらをご覧ください。
ステータス
現在のプラットフォームのサポートは言語によって異なります。Bazel の主要なルールはすべてプラットフォームに移行されます。ただし、このプロセスには時間がかかります。これは主に次の 3 つの理由によるものです。
新しい toolchain API(
ctx.toolchains
)からツール情報を取得し、--cpu
や--crosstool_top
などの以前の設定の読み取りを停止するように、ルールロジックを更新する必要があります。これは比較的簡単です。ツールチェーン メンテナンス担当者は、ツールチェーンを定義し、ユーザーがアクセスできるようにする必要があります(GitHub リポジトリと
WORKSPACE
エントリで)。技術的には簡単ですが、ユーザー エクスペリエンスを維持するために、インテリジェントに整理する必要があります。プラットフォームの定義も必要です(Bazel が実行されているマシン用にビルドする場合を除きます)。通常、プロジェクトは独自のプラットフォームを定義する必要があります。
既存のプロジェクトは移行する必要があります。
select()
と遷移も移行する必要があります。これが最大の課題です。特に、多言語プロジェクトでは困難です(すべての言語で--platforms
を読み取れない場合は失敗する可能性があります)。
新しいルールセットを設計する場合は、最初からプラットフォームをサポートする必要があります。これにより、ルールが他のルールやプロジェクトと自動的に互換性を持つようになり、プラットフォーム API が普及するにつれて価値が高まります。
共通のプラットフォーム プロパティ
プロジェクト間で共通するプラットフォーム プロパティ(OS
や CPU
など)は、標準の一元化された場所で宣言する必要があります。これにより、プロジェクト間および言語間の互換性が促進されます。
たとえば、MyApp に constraint_value
@myapp//cpus:arm
に select()
があり、SomeCommonLib に @commonlib//constraints:arm
に select()
がある場合、互換性のない条件で「arm」モードがトリガーされます。
世界的に共通のプロパティは @platforms
リポジトリで宣言されます(上記の例のカノニカル ラベルは @platforms//cpu:arm
です)。言語に共通のプロパティは、それぞれの言語のリポジトリで宣言する必要があります。
デフォルトのプラットフォーム
通常、プロジェクト オーナーは明示的なプラットフォームを定義して、ビルドするマシンの種類を記述する必要があります。これらは --platforms
でトリガーされます。
--platforms
が設定されていない場合、Bazel はデフォルトでローカルビルドマシンを表す platform
になります。これは @local_config_platform//:host
で自動生成されるため、明示的に定義する必要はありません。ローカルマシンの OS
と CPU
を、@platforms
で宣言された constraint_value
にマッピングします。
C++
Bazel の C++ ルールは、--incompatible_enable_cc_toolchain_resolution
を設定するときにプラットフォームを使用して toolchain を選択します(#7260)。
つまり、C++ プロジェクトは次のように構成できます。
bazel build //:my_cpp_project --platforms=//:myplatform
に置き換えます。
bazel build //:my_cpp_project` --cpu=... --crosstool_top=... --compiler=...
プロジェクトが純粋な C++ で、C++ 以外のプロジェクトに依存していない場合は、select
と遷移が互換性がある限り、プラットフォームを安全に使用できます。詳細なガイダンスについては、#7260 と C++ ツールチェーンの構成をご覧ください。
このモードはデフォルトでは有効になっていません。これは、Apple プロジェクトで --cpu
と --crosstool_top
を使用して C++ 依存関係が構成されているためです(例)。そのため、これはプラットフォームに移行される Apple のルールによって異なります。
Java
Bazel の Java ルールはプラットフォームを使用します。
これは、従来のフラグ --java_toolchain
、--host_java_toolchain
、--javabase
、--host_javabase
に代わるものです。
構成フラグの使用方法については、Bazel と Java のマニュアルをご覧ください。詳細については、設計ドキュメントをご覧ください。
以前のフラグを使用している場合は、Issue #7849 の移行プロセスに沿って対応してください。
Android
Bazel の Android ルールは、--incompatible_enable_android_toolchain_resolution
を設定するときにプラットフォームを使用して toolchain を選択します。
これはデフォルトでは有効になっていません。移行は順調に進んでいます。
Apple
Bazel の Apple ルールでは、Apple ツールチェーンを選択するプラットフォームはまだサポートされていません。
また、従来の --crosstool_top
を使用して C++ ツールチェーンを設定するため、プラットフォーム対応の C++ 依存関係もサポートしていません。移行されるまでは、プラットフォーム マッピングを使用して、Apple プロジェクトとプラットフォーム対応の C++ を組み合わせることができます(例)。
その他の言語
新しい言語のルールを設計する場合は、プラットフォームを使用して言語のツールチェーンを選択します。詳細なチュートリアルについては、ツールチェーンに関するドキュメントをご覧ください。
select()
プロジェクトは constraint_value
ターゲットで select()
できますが、完全なプラットフォームでは行えません。これは、select()
が可能な限り幅広いマシンをサポートできるように意図されています。ARM
固有のソースを含むライブラリは、より具体的な理由がない限り、ARM
を搭載したすべてのマシンをサポートする必要があります。
1 つ以上の constraint_value
を選択するには、次を使用します。
config_setting(
name = "is_arm",
constraint_values = [
"@platforms//cpu:arm",
],
)
これは、従来どおり --cpu
で選択するのと同じです。
config_setting(
name = "is_arm",
values = {
"cpu": "arm",
},
)
詳しくはこちらをご覧ください。
--cpu
や --crosstool_top
の select
は --platforms
を認識しません。プロジェクトをプラットフォームに移行する場合は、プロジェクトを constraint_values
に変換するか、プラットフォーム マッピングを使用して、移行期間中に両方のスタイルをサポートする必要があります。
遷移
Starlark 遷移は、ビルドグラフの一部でフラグを変更します。プロジェクトで --cpu
、--crossstool_top
、またはその他の以前のフラグを設定する遷移を使用している場合、--platforms
を読み取るルールではこれらの変更は検出されません。
プロジェクトをプラットフォームに移行する場合は、return { "//command_line_option:cpu": "arm" }
などの変更を return {
"//command_line_option:platforms": "//:my_arm_platform" }
に変換するか、プラットフォーム マッピングを使用して、移行期間中に両方のスタイルをサポートする必要があります。
プラットフォームの現在の使用方法
プロジェクトのビルドまたはクロスコンパイルのみを行う場合は、プロジェクトの公式ドキュメントに沿って操作する必要があります。プラットフォームとの統合方法とタイミング、およびその価値は、言語とプロジェクトのメンテナンス担当者が決定します。
プロジェクト、言語、ツールチェーンのメンテナーであり、ビルドでプラットフォームがデフォルトで使用されていない場合は、(グローバル マイグレーションの待機以外に)次の 3 つのオプションがあります。
プロジェクトの言語の「プラットフォームの使用」フラグをオンにして(言語にプラットフォームがある場合)、必要なテストを行い、対象のプロジェクトが機能するかどうかを確認します。
対象のプロジェクトが
--cpu
や--crosstool_top
などの以前のフラグに依存している場合は、--platforms
とともに使用します。bazel build //:my_mixed_project --platforms==//:myplatform --cpu=... --crosstool_top=...
これにはメンテナンス費用がかかります(設定が一致していることを手動で確認する必要があります)。ただし、反逆的な遷移がない場合、これは機能するはずです。
--cpu
スタイルの設定を対応するプラットフォームにマッピングし、その逆もマッピングすることで、両方のスタイルをサポートするプラットフォーム マッピングを記述します。
プラットフォームのマッピング
プラットフォーム マッピングは、プラットフォーム ベースとレガシー ベースのロジックを、後者の非推奨期間を通じて同じビルドに共存させる一時的な API です。
プラットフォーム マッピングは、platform()
と対応するレガシー フラグのセットのマッピング、またはその逆のマッピングです。次に例を示します。
platforms:
# Maps "--platforms=//platforms:ios" to "--cpu=ios_x86_64 --apple_platform_type=ios".
//platforms:ios
--cpu=ios_x86_64
--apple_platform_type=ios
flags:
# Maps "--cpu=ios_x86_64 --apple_platform_type=ios" to "--platforms=//platforms:ios".
--cpu=ios_x86_64
--apple_platform_type=ios
//platforms:ios
# Maps "--cpu=darwin --apple_platform_type=macos" to "//platform:macos".
--cpu=darwin
--apple_platform_type=macos
//platforms:macos
Bazel は、これを使用して、プラットフォームベースとレガシーの両方のすべての設定が、移行を含むビルド全体で一貫して適用されるようにします。
デフォルトでは、Bazel はワークスペースのルートにある platform_mappings
ファイルからマッピングを読み取ります。--platform_mappings=//:my_custom_mapping
を設定することもできます。
詳しくは、こちらをご覧ください。
質問
移行のタイムラインに関する一般的なサポートや質問については、bazel-discuss@googlegroups.com または適切なルールのオーナーにお問い合わせください。
プラットフォーム/ツールチェーン API の設計と進化については、bazel-dev@googlegroups.com までお問い合わせください。