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

Bazel は、プラットフォームツールチェーンのモデリングの高度なサポートを備えています。これを実際のプロジェクトと統合するには、コードオーナー、ルールの管理者、コア Bazel 開発者の間で慎重に協力する必要があります。

このページでは、プラットフォームの目的の概要と、それらを使用して構築する方法について説明します。

tl;dr: Bazel のプラットフォーム API とツールチェーン API は使用できますが、すべての言語ルール、select()、その他のレガシー リファレンスが更新されるまで、どこでも動作しません。これは継続的な取り組みです。最終的には、すべてのビルドがプラットフォーム ベースになります。ビルドがどこに配置されるかについては、以下をご確認ください。

正式なドキュメントについては、以下をご覧ください。

背景

プラットフォームツールチェーンは、ソフトウェア プロジェクトが異なるマシンをターゲットとして適切な言語ツールでビルドする方法を標準化するために導入されました。

これは Bazel に比較的最近追加されたものです。これは、言語メンテナンス担当者がアドホックで互換性のない方法ですでに行っているという観察から刺激を受けました。たとえば、C++ ルールは --cpu--crosstool_top を使用してビルドのターゲット CPU と C++ ツールチェーンを設定します。どちらも「プラットフォーム」を正しくモデル化していません。長期間にわたってこれを行うと、気まずくて不正確なビルドが発生しました。また、これらのフラグは Java コンパイルを制御しません。Java コンパイルは、--java_toolchain により独自の独立したインターフェースを進化させています。

Bazel は、大規模な多言語マルチプラットフォーム プロジェクトを対象としています。そのためには、言語とプロジェクトの相互運用性を促進する明確な API など、より原則に基づいたサポートが必要です。これが、これらの新しい API の目的です。

移行

プラットフォーム API とツールチェーン 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 レビュー

platformconstraint_value ターゲットのコレクションです。

platform(
    name = "myplatform",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:arm",
    ],
)

constraint_value はマシン プロパティです。同じ「kind」の値は、共通の 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" など)を宣言します。プロバイダはこの情報を、これらのツールで構築する必要があるルールに渡します。

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

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

使用可能なツールチェーンのセットは、register_toolchains を使用して WORKSPACE に登録するか、--extra_toolchains を使用してコマンドラインで登録できます。

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

ステータス

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

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

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

    プラットフォームの定義も必要です(Bazel が実行されているマシンと同じマシンでビルドしていない場合)。一般に、プロジェクトで独自のプラットフォームを定義する必要があります。

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

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

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

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

たとえば、MyAppconstraint_value @myapp//cpus:armselect() があり、SomeCommonLibselect()@commonlib//constraints:arm にある場合、互換性のない条件で「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 の設定時にツールチェーンの選択にプラットフォームを使用します。

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

リンゴ

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

また、以前の --crosstool_top を使用して C++ ツールチェーンを設定するため、プラットフォーム対応の C++ 依存関係もサポートしません。移行されるまで、Apple プロジェクトと、Platform 対応の 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 までお問い合わせください。

関連ドキュメント