プラットフォームを使った構築

7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

これは以下を意味します。

  1. プロジェクトで使用するルールは、//:myplatform から正しいツールチェーンを推測できます。
  2. プロジェクトの依存関係で使用されるルールは、//:myplatform から正しいツールチェーンを推測できます。
  3. プロジェクトが //:myplatform をサポートしている、プロジェクトが以前の API(--crosstool_top など)をサポートしている
  4. //:myplatform は、CPUOS、および自動プロジェクト間の互換性をサポートするその他の一般的なコンセプトの [共通宣言][共通プラットフォーム宣言]{: .external} を参照します。
  5. 関連するすべてのプロジェクトの select() は、//:myplatform によって暗黙的に示唆されるマシン プロパティを理解します。
  6. //:myplatform は、明確で再利用可能な場所に定義します。プラットフォームがプロジェクトに固有の場合はプロジェクトのリポジトリに、そうでない場合は、このプラットフォームを使用する可能性のあるすべてのプロジェクトが見つけられる場所に定義します。

この目標が達成されると、古い API は直ちに削除されます。これは、プロジェクトでプラットフォームとツールチェーンを選択する標準的な方法です。

プラットフォームを使用するべきですか?

プロジェクトのビルドまたはクロスコンパイルのみを行う場合は、プロジェクトの公式ドキュメントに沿って操作してください。

プロジェクト、言語、ツールチェーンのメンテナーは、最終的には新しい API をサポートする必要があります。グローバル マイグレーションの完了を待つか、早期にオプトインするかは、特定の価値と費用のニーズによって異なります。

  • --cpu などのハードコードされたフラグの代わりに、select() を使用するか、または、目的のプロパティに対してツールチェーンを選択します。たとえば、複数の CPU が同じ命令セットをサポートできます。
  • ビルドの精度が向上。上記の例で --cpu を指定して select() を実行し、同じ命令セットをサポートする新しい CPU を追加すると、select() は新しい CPU を認識できません。ただし、プラットフォーム上の select() は正確なままです。
  • シンプルなユーザー エクスペリエンス。すべてのプロジェクトが --platforms=//:myplatform を認識します。コマンドラインで複数の言語固有のフラグを使用する必要はありません。
  • 言語設計を簡素化。すべての言語は、ツールチェーンの定義、ツールチェーンの使用、プラットフォームに適したツールチェーンの選択に共通の API を共有します。
  • ターゲットがターゲット プラットフォームと互換性がない場合は、ビルドとテストのフェーズでスキップできます。

料金

  • プラットフォームをまだサポートしていない依存プロジェクトは、自動的に連携しない場合があります。
  • 機能させるには、追加の一時的なメンテナンスが必要になる場合があります。
  • 新しい API と従来の API が共存する場合は、混乱を避けるためにユーザー ガイダンスを慎重に行う必要があります。
  • OSCPU などの一般的なプロパティの正規定義は現在も進化しており、追加の初期コントリビューションが必要になる場合があります。
  • 言語固有のツールチェーンの正規の定義はまだ発展途上であり、追加の初期コントリビューションが必要になる場合があります。

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",
)

toolchainStarlark ルールです。属性は、言語のツール(compiler = "//mytoolchain:custom_gcc" など)を宣言します。プロバイダは、これらのツールでビルドする必要があるルールにこの情報を渡します。

ツールチェーンは、ターゲットにできるマシンの constraint_valuetarget_compatible_with = ["@platforms//os:linux"])と、ツールを実行できるマシンの constraint_valueexec_compatible_with = ["@platforms//os:mac"])を宣言します。

$ bazel build //:myproject --platforms=//:myplatform をビルドする際、Bazel はビルドマシンで実行可能なツールチェーンと //:myplatform のビルドバイナリを自動的に選択します。これをツールチェーンの解決と呼びます。

使用可能な toolchain のセットは、WORKSPACEregister_toolchains を使用して登録するか、コマンドラインで --extra_toolchains を使用して登録できます。

詳しくは、こちらをご覧ください。

ステータス

現在のプラットフォームのサポートは言語によって異なります。Bazel の主要なルールはすべてプラットフォームに移行しています。ただし、このプロセスには時間がかかります。これには、主に次の 3 つの理由があります。

  1. 新しい toolchain APIctx.toolchains)からツール情報を取得し、--cpu--crosstool_top などの以前の設定の読み取りを停止するように、ルールロジックを更新する必要があります。これは比較的簡単です。

  2. ツールチェーンのメンテナンス担当者は、ツールチェーンを定義し、ユーザーが(GitHub リポジトリと WORKSPACE エントリで)アクセスできるようにする必要があります。これは技術的には単純ですが、簡単なユーザー エクスペリエンスを維持するには、インテリジェントに整理する必要があります。

    プラットフォームの定義も必要です(Bazel が実行されているマシン用にビルドする場合を除きます)。通常、プロジェクトは独自のプラットフォームを定義する必要があります。

  3. 既存のプロジェクトは移行する必要があります。select()移行も移行する必要があります。これが最大の課題です。これは多言語プロジェクトでは特に困難です(すべての言語で --platforms を読み取れない場合に失敗する可能性があります)。

新しいルールセットを設計する場合は、最初からプラットフォームをサポートする必要があります。これにより、ルールは他のルールやプロジェクトと自動的に互換性を持つようになり、プラットフォーム API が普及するにつれて価値が高まります。

共通のプラットフォーム プロパティ

プロジェクトに共通する OSCPU などのプラットフォーム プロパティは、一元化された標準的な場所で宣言する必要があります。これにより、プロジェクト間および言語間の互換性が促進されます。

たとえば、MyAppconstraint_value @myapp//cpus:armselect() があり、@commonlib//constraints:armSomeCommonLibselect() がある場合、互換性のない基準で「arm」モードがトリガーされます。

世界的に共通のプロパティは @platforms リポジトリで宣言されます(上記の例のカノニカル ラベルは @platforms//cpu:arm です)。言語に共通のプロパティは、それぞれの言語のリポジトリで宣言する必要があります。

デフォルトのプラットフォーム

一般に、プロジェクト オーナーは、ビルド対象のマシンの種類を定義する明示的なプラットフォームを定義する必要があります。その後、これらは --platforms でトリガーされます。

--platforms が設定されていない場合、Bazel はデフォルトでローカルビルドマシンを表す platform になります。これは @local_config_platform//:host に自動生成されるため、明示的に定義する必要はありません。ローカルマシンの OSCPU を、@platforms で宣言された constraint_value にマッピングします。

C++

Bazel の C++ ルールでは、--incompatible_enable_cc_toolchain_resolution を設定する際にプラットフォームを使用してツールチェーンを選択します(#7260)。

つまり、以下を使用して C++ プロジェクトを構成できます。

bazel build //:my_cpp_project --platforms=//:myplatform

に置き換えます。

bazel build //:my_cpp_project` --cpu=... --crosstool_top=...  --compiler=...

プロジェクトが純粋な C++ であり、C++ 以外のプロジェクトに依存しない場合は、select遷移に互換性がある限り、プラットフォームを安全に使用できます。詳細なガイダンスについては、#7260C++ ツールチェーンの構成をご覧ください。

このモードはデフォルトでは有効になっていません。これは、Apple プロジェクトで --cpu--crosstool_top を使用して C++ 依存関係が構成されているためです()。そのため、これはプラットフォームに移行される Apple のルールによって異なります。

Java

Bazel の Java ルールではプラットフォームを使用します。

これは、従来のフラグ --java_toolchain--host_java_toolchain--javabase--host_javabase に代わるものです。

構成フラグの使用方法については、Bazel と Java のマニュアルをご覧ください。 詳細については、設計ドキュメントをご覧ください。

まだ以前のフラグを使用している場合は、問題 #7849 の移行プロセスに沿って対応してください。

Android

Bazel の Android ルールでは、--incompatible_enable_android_toolchain_resolution を設定する際にプラットフォームを使用してツールチェーンを選択します。

これはデフォルトでは有効になっていません。しかし、移行は順調に進んでいます。

Apple

Bazel の Apple ルールは、Apple ツールチェーンを選択するプラットフォームをまだサポートしていません。

また、従来の --crosstool_top を使用して C++ ツールチェーンを設定するため、プラットフォーム対応の C++ 依存関係もサポートしていません。移行が完了するまでは、Apple プロジェクトと、プラットフォームが有効な C++ をプラットフォーム マッピングで混在させることができます()。

その他の言語

  • Bazel の Rust ルールはプラットフォームを完全にサポートしています。
  • Bazel の Go ルールは、プラットフォームを完全にサポートしています(詳細)。

新しい言語のルールを設計する場合は、プラットフォームを使用して言語のツールチェーンを選択します。適切なチュートリアルについては、ツールチェーンのドキュメントをご覧ください。

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 つのオプションがあります。

  1. プロジェクトの言語の「プラットフォームの使用」フラグをオンにして(言語にプラットフォームがある場合)、必要なテストを行い、対象のプロジェクトが動作するかどうかを確認します。

  2. 対象のプロジェクトが --cpu--crosstool_top などの以前のフラグに依存している場合は、--platforms とともに使用します。

    bazel build //:my_mixed_project --platforms==//:myplatform --cpu=... --crosstool_top=...

    これにはメンテナンス費用がかかります(設定の一致を手動で確認する必要があります)。ただし、反逆的な遷移がない場合、これは機能するはずです。

  3. --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 までお問い合わせください。

関連情報