構成

<ph type="x-smartling-placeholder"></ph> 問題を報告する ソースを表示 夜間 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

このページでは、Starlark 構成の利点と基本的な使用方法について説明します。 プロジェクトのビルド方法をカスタマイズするための Bazel の API。また、Kubernetes の ビルド設定について説明し、サンプルを示します。

これにより、次のことが可能になります。

  • プロジェクトのカスタムフラグを定義できます。これにより、 --define
  • 書き込み Transitions で依存関係を設定します。 構成が異なる場合があります。 (--compilation_mode=opt--cpu=arm など)
  • より適切なデフォルトをルールに埋め込む(//my:android_app を自動的にビルドするなど) 使用)

など、すべて .bzl ファイルから作成できます(Bazel リリースは必要ありません)。詳しくは、 bazelbuild/examples リポジトリ をご覧ください。

ユーザー定義のビルド設定

ビルド設定は 構成 情報です。構成は Key-Value マップのようなものです。--cpu=ppc の設定 --copt="-DFoo" は、次のような構成を生成します。 {cpu: ppc, copt: "-DFoo"}。各エントリはビルド設定です。

cpucopt などの従来のフラグはネイティブ設定です。 キーが定義され、値がネイティブの bazel Java コード内で設定されます。 Bazel ユーザーは、コマンドラインでのみ読み取りと書き込みを行える などの API がネイティブに維持されます。ネイティブ フラグと API の変更 公開するには bazel リリースが必要です。ユーザー定義ビルド 設定は .bzl ファイルで定義されるため、設定に bazel リリースは必要ありません 変更を登録します)。コマンドラインでも設定できます。 (flags として指定されている場合、詳細は下記を参照)が、 ユーザー定義の遷移で設定できます。

ビルド設定の定義

エンドツーエンドの例

build_setting rule() パラメータ

ビルド設定は他のルールと同様のルールであり、 Starlark の rule() 関数の build_setting 属性

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

build_setting 属性は、変数の型を指定する関数を ビルド設定を指定します。このタイプは、次のような基本的な Starlark のタイプに限定されます。 boolstringconfig モジュールを確認する ドキュメントをご覧ください。より複雑な入力は 指定することもできます。詳しくは以下をご覧ください。

config モジュールの関数は、オプションのブール値パラメータ flag を受け取ります。 デフォルトで false に設定されています。flag が true に設定されている場合、ビルド設定は ユーザーがコマンドラインで設定することも、内部でルール作成者が設定することも可能 デフォルト値と遷移を介して使用できます。 すべての設定をユーザーが設定できるようにする必要はありません。たとえば ライターには、テストルール内で有効にしたいデバッグモードがあります。 この機能を無差別に有効にしたり 使用できます。

gsuite.build_setting_value の使用

すべてのルールと同様に、ビルド設定ルールにも実装関数があります。 ビルド設定の基本的な Starlark 型の値は、 ctx.build_setting_value メソッドを使用します。この方法は、 ビルド設定ルールの ctx オブジェクト。この実装は メソッドはビルド設定の値を直接転送したり、ファイルに対して 型チェックや、より複雑な構造体の作成などです。これを enum 型のビルド設定を実装します。

# example/buildsettings/build_settings.bzl
TemperatureProvider = provider(fields = ['type'])

temperatures = ["HOT", "LUKEWARM", "ICED"]

def _impl(ctx):
    raw_temperature = ctx.build_setting_value
    if raw_temperature not in temperatures:
        fail(str(ctx.label) + " build setting allowed to take values {"
             + ", ".join(temperatures) + "} but was set to unallowed value "
             + raw_temperature)
    return TemperatureProvider(type = raw_temperature)

temperature = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

複数セットの文字列フラグの定義

文字列の設定には、allow_multiple パラメータが追加されており、 コマンドラインまたは bazelrcs でフラグを複数回設定することもできます。デフォルトの 値は文字列型属性を使用して設定されます。

# example/buildsettings/build_settings.bzl
allow_multiple_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/buildsettings/BUILD
load("//example/buildsettings:build_settings.bzl", "allow_multiple_flag")
allow_multiple_flag(
    name = "roasts",
    build_setting_default = "medium"
)

フラグの各設定は、1 つの値として扱われます。

$ bazel build //my/target --//example:roasts=blonde \
    --//example:roasts=medium,dark

上記は {"//example:roasts": ["blonde", "medium,dark"]} に解析され、 ctx.build_setting_value はリスト ["blonde", "medium,dark"] を返します。

ビルド設定をインスタンス化する

build_setting パラメータで定義されたルールには暗黙的な必須要素があります。 build_setting_default 属性。この属性は build_setting パラメータで宣言されます。

# example/buildsettings/build_settings.bzl
FlavorProvider = provider(fields = ['type'])

def _impl(ctx):
    return FlavorProvider(type = ctx.build_setting_value)

flavor = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)
# example/buildsettings/BUILD
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)

事前定義の設定

エンドツーエンドの例

Skylib ライブラリには事前定義された設定のセットが用意されており、何も設定しなくてもインスタンス化できる カスタム Starlark を作成します。

たとえば、一部の文字列値を受け入れる設定を定義するには、次のようにします。

# example/BUILD
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
    name = "myflag",
    values = ["a", "b", "c"],
    build_setting_default = "a",
)

完全なリストについては、 一般的なビルド設定のルール

ビルド設定の使用

ビルド設定によって異なる

ターゲットが構成情報を読み取る場合は、 通常の属性依存関係を介してビルド設定に直接依存しています。

# example/rules.bzl
load("//example/buildsettings:build_settings.bzl", "FlavorProvider")
def _rule_impl(ctx):
    if ctx.attr.flavor[FlavorProvider].type == "ORANGE":
        ...

drink_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "flavor": attr.label()
    }
)
# example/BUILD
load("//example:rules.bzl", "drink_rule")
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)
drink_rule(
    name = "my_drink",
    flavor = ":favorite_flavor",
)

言語によっては、ビルド設定の正規のセットを作成することをおすすめします。 言語に依存しますfragments のネイティブ コンセプトはもはや、 Starlark の構成にハードコードされたオブジェクトとして存在します。 共通の暗黙属性のセットを使用するという考え方です次に例を示します。

# kotlin/rules.bzl
_KOTLIN_CONFIG = {
    "_compiler": attr.label(default = "//kotlin/config:compiler-flag"),
    "_mode": attr.label(default = "//kotlin/config:mode-flag"),
    ...
}

...

kotlin_library = rule(
    implementation = _rule_impl,
    attrs = dicts.add({
        "library-attr": attr.string()
    }, _KOTLIN_CONFIG)
)

kotlin_binary = rule(
    implementation = _binary_impl,
    attrs = dicts.add({
        "binary-attr": attr.label()
    }, _KOTLIN_CONFIG)

コマンドラインでビルド設定を使用する

ほとんどのネイティブ フラグと同様に、コマンドラインを使用してビルド設定を指定できます。 ビルド 設定名は、name=value 構文を使用したターゲットのフルパスです。

$ bazel build //my/target --//example:string_flag=some-value # allowed
$ bazel build //my/target --//example:string_flag some-value # not allowed

特別なブール構文がサポートされています。

$ bazel build //my/target --//example:boolean_flag
$ bazel build //my/target --no//example:boolean_flag

ビルド設定エイリアスの使用

読みやすくするために、ビルド設定のターゲット パスにエイリアスを設定できます。 指定します。エイリアスはネイティブ フラグと同様に機能し、 オプションの構文を示します。

--flag_alias=ALIAS_NAME=TARGET_PATH を追加してエイリアスを設定する .bazelrc へ。たとえば、エイリアスを coffee に設定するには、次のようにします。

# .bazelrc
build --flag_alias=coffee=//experimental/user/starlark_configurations/basic_build_setting:coffee-temp

ベスト プラクティス: エイリアスを複数回設定すると、最新の どちらかが優先されます意図しない解析結果を避けるため、一意のエイリアス名を使用します。

エイリアスを使用するには、ビルド設定のターゲット パスの代わりにこのエイリアスを入力します。 上記の coffee の例では、ユーザーの .bazelrc で次のように設定しています。

$ bazel build //my/target --coffee=ICED

これは、以下を置き換えるものです。

$ bazel build //my/target --//experimental/user/starlark_configurations/basic_build_setting:coffee-temp=ICED

ベスト プラクティス: コマンドラインでエイリアスを設定することはできますが、エイリアスは残しておきます。 .bazelrc に含めると、コマンドラインがすっきりします。

ラベルタイプのビルド設定

エンドツーエンドの例

他のビルド設定とは異なり、ラベルタイプの設定は、 build_setting ルール パラメータ。代わりに、bazel には 2 つのルールが組み込まれています。 label_flaglabel_setting。これらのルールは、ファイアウォール ルールの ビルド設定が行われる実際のターゲット。label_flaglabel_setting は遷移によって読み書きでき、label_flag を設定可能 他の build_setting ルールと同様に、ユーザーにより制限されます。唯一の違いは、 カスタム定義はできません

ラベルタイプの設定が最終的には遅延バインド機能に置き換わる できます。遅延制限のあるデフォルト属性は、ラベル型の属性で、 最終的な値が構成の影響を受ける場合があります。Starlark では、 configuration_field API

# example/rules.bzl
MyProvider = provider(fields = ["my_field"])

def _dep_impl(ctx):
    return MyProvider(my_field = "yeehaw")

dep_rule = rule(
    implementation = _dep_impl
)

def _parent_impl(ctx):
    if ctx.attr.my_field_provider[MyProvider].my_field == "cowabunga":
        ...

parent_rule = rule(
    implementation = _parent_impl,
    attrs = { "my_field_provider": attr.label() }
)
# example/BUILD
load("//example:rules.bzl", "dep_rule", "parent_rule")

dep_rule(name = "dep")

parent_rule(name = "parent", my_field_provider = ":my_field_provider")

label_flag(
    name = "my_field_provider",
    build_setting_default = ":dep"
)

ビルド設定と select()

エンドツーエンドの例

ユーザーは以下を使用してビルド設定の属性を構成できます。 select()。ビルド設定ターゲットは、次の flag_values 属性に渡すことができます: config_setting。構成に一致する値は 次に、String が照合用のビルド設定のタイプに解析されます。

config_setting(
    name = "my_config",
    flag_values = {
        "//example:favorite_flavor": "MANGO"
    }
)

ユーザー定義の遷移

構成 移行 変換が、構成済みのターゲットから別のターゲット グラフを作成します。

これらを設定するルールには、特別な属性を含める必要があります。

  "_allowlist_function_transition": attr.label(
      default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
  )

切り替え効果を追加すると、動画のサイズを ビルドグラフを作成します。これにより、パッケージに許可リストが設定され、 ルールのターゲットを作成します。上記のコードブロックのデフォルト値 すべてを許可リストに登録します。ルールを使用できるユーザーを制限する場合は その属性を設定して、独自のカスタム許可リストを指定できます。 アドバイスや支援が必要な場合は、bazel-discuss@googlegroups.com にお問い合わせください 遷移がビルドのパフォーマンスに与える影響を理解する

定義

移行では、ルール間の構成の変更を定義します。たとえば リクエストが 「親とは異なる CPU の依存関係をコンパイルする」などによって処理されます。 説明します。

形式的には、遷移とは入力構成から 1 つ以上の構成への関数である 構成できます。「入力をオーバーライドする」など、ほとんどの遷移は 1 対 1 です。 --cpu=ppc で構成」と記述します。1 対 2 以降の移行も可能だが、 特別な制限が適用されます

Starlark では、遷移はルールとよく似ており、 transition() 関数 実装関数が必要です

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//example:favorite_flavor" : "MINT"}

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

transition() 関数は、実装関数を受け取ります。 読み取るビルド設定(inputs)と書き込むビルド設定のセット (outputs)。この実装関数には、settings と 2 つのパラメータがあります。 attrsettings は宣言されたすべての設定の辞書 {String:Object} です inputs パラメータで transition() に設定します。

attr は、ルールを適用する属性と値のディクショナリです。 適用できます。として接続した場合 送信エッジ遷移の場合、これらの値は 属性は、select() の後に解決するように設定されています。次のように接続した場合: 受信エッジへの遷移attr では、 セレクタを使用して値を解決するすべての属性を含めるもし --foo の着信エッジ遷移が属性 bar を読み取り、さらに --foo を選択して属性 bar を設定すると、 入力エッジ遷移で誤った bar 値を読み取る。

実装関数は、ディクショナリ(または 場合は、 複数の出力構成を持つ遷移の場合) 適用する新しいビルド設定値のリストです。返される辞書の鍵セットは、 outputs に渡されたビルド設定のセットのみが含まれる パラメータを使用します。これは、ビルド設定が その元の値は移行の過程で変更されないため、 明示的に渡されます。

1 対 2 以上の遷移の定義

エンドツーエンドの例

出力エッジ遷移は単一の入力をマッピングできる 複数の出力構成に結合できます。これは マルチアーキテクチャコードをバンドルします

1 対 2 以上の遷移は、 します。

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return [
        {"//example:favorite_flavor" : "LATTE"},
        {"//example:favorite_flavor" : "MOCHA"},
    ]

coffee_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

また、ルールの実装機能で使用するカスタムキーも設定できます。 個々の依存関係を読み取るには:

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

遷移を追加する

エンドツーエンドの例

遷移は、受信エッジと送信エッジの 2 か所に接続できます。 これは実質的に、ルールによって独自の構成(受信 依存関係を移行して、それらの依存関係を構成( など)があります。

注: 現在のところ、Starlark の遷移をネイティブ ルールに適用する方法はありません。 この操作を行う必要がある場合は、 bazel-discuss@googlegroups.com をご利用ください。

入力エッジ遷移

入力エッジ遷移をアクティブにするには、transition オブジェクトをアタッチします (transition() によって作成)を rule()cfg パラメータに追加します。

# example/rules.bzl
load("example/transitions:transitions.bzl", "hot_chocolate_transition")
drink_rule = rule(
    implementation = _impl,
    cfg = hot_chocolate_transition,
    ...

受信エッジの遷移は 1 対 1 の遷移である必要があります。

発信エッジ遷移

transition オブジェクトをアタッチして発信エッジ遷移をアクティブにする (transition() によって作成)を属性の cfg パラメータに追加します。

# example/rules.bzl
load("example/transitions:transitions.bzl", "coffee_transition")
drink_rule = rule(
    implementation = _impl,
    attrs = { "dep": attr.label(cfg = coffee_transition)}
    ...

発信エッジ遷移は、1:1 または 1:2 以上です。

遷移による属性へのアクセスをご覧ください。 ご覧ください

ネイティブ オプションの切り替え

エンドツーエンドの例

Starlark 遷移では、ネイティブ ビルドでの読み取りと書き込みの宣言も可能 特別な接頭辞でオプション名に付加します。

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//command_line_option:cpu": "k8"}

cpu_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]

サポートされていないネイティブ オプション

Bazel は、以下を含む --define での遷移をサポートしていません。 "//command_line_option:define"。代わりに、カスタム ビルド設定。一般的に、 ビルド設定を優先して --define を使用することは推奨されません。

Bazel は、--config での移行をサポートしていません。これは、--config が 「拡大」他のフラグに展開されます。

重要な点として、--config にはビルド構成に影響しないフラグが含まれる場合があります。 --spawn_strategy をタップします。Bazel は設計上、このようなフラグを個々のターゲットにバインドできません。つまり 遷移に適用するための一貫した方法がありません。

回避策として、 おすすめします。そのためには、--config の UI の問題として知られています。

複数のビルド設定を許可する場合の遷移

依存関係を設定すると、 複数の値を許可する場合は、 リストを使用して設定する必要があります。

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "string_flag")
string_flag(name = "roasts", build_setting_default = "medium")
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    # Using a value of just "dark" here will throw an error
    return {"//example:roasts" : ["dark"]},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:roasts"]
)

NoOps の遷移

遷移が {}[]、または None を返す場合、これはすべての 元の値のまま維持できますこれは、明示的に宣言するよりも 各出力をそれ自体に設定します。

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (attr)
    if settings["//example:already_chosen"] is True:
      return {}
    return {
      "//example:favorite_flavor": "dark chocolate",
      "//example:include_marshmallows": "yes",
      "//example:desired_temperature": "38C",
    }

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = ["//example:already_chosen"],
    outputs = [
        "//example:favorite_flavor",
        "//example:include_marshmallows",
        "//example:desired_temperature",
    ]
)

遷移による属性へのアクセス

エンドツーエンドの例

送信エッジへの移行を接続する場合 (遷移が 1:1 または 1:2+ のいずれであるかにかかわらず)、ctx.attr は強制的にリストになります。 まだ行っていない場合ですこのリストに含まれる要素の順序は指定されていません。

# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    return {"//example:favorite_flavor" : "LATTE"},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

def _rule_impl(ctx):
    # Note: List access even though "dep" is not declared as list
    transitioned_dep = ctx.attr.dep[0]

    # Note: Access doesn't change, other_deps was already a list
    for other dep in ctx.attr.other_deps:
      # ...


coffee_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = coffee_transition)
        "other_deps": attr.label_list(cfg = coffee_transition)
    })

遷移が 1:2+ でカスタムキーを設定した場合は、ctx.split_attr を使用できます。 次のようにして、キーごとに個別の依存関係を読み取ることができます。

# example/transitions/rules.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

def _rule_impl(ctx):
    apple_dep = ctx.split_attr.dep["Apple deps"]
    linux_dep = ctx.split_attr.dep["Linux deps"]
    # ctx.attr has a list of all deps for all keys. Order is not guaranteed.
    all_deps = ctx.attr.dep

multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = multi_arch_transition)
    })

完全な例を見る 見てみましょう。

プラットフォームとツールチェーンとの統合

現在、--cpu--crosstool_top など、現在多くのネイティブ フラグは以下に関連しています。 ツールチェーンの解決。将来的には、このような Google Workspace の フラグが置き換えられる可能性があるので、Dataflow からの ターゲット プラットフォーム

メモリとパフォーマンスに関する考慮事項

ビルドに遷移(つまり新しい構成を追加)を追加する場合は、 コスト: ビルドグラフが大きく、ビルドグラフがわかりにくく、低速 説明します。これらの費用を検討する際には ビルドルールで遷移を使用します。以下は、移行プロセスが ビルドグラフが急激に増加することがあります

不正な動作のビルド: ケーススタディ

スケーラビリティ グラフ

図 1. 最上位のターゲットとその依存関係を示すスケーラビリティ グラフ。

このグラフは、2 つのターゲット、つまり //pkg:app に依存するトップレベルのターゲット //pkg:app を示しています。 //pkg:1_0 と //pkg:1_1 です。これらのターゲットはどちらも、//pkg:2_0 と //pkg:2_0 の 2 つのターゲットに依存します。 //pkg:2_1 という形式で指定する必要があります。これらのターゲットはどちらも、//pkg:3_0 と //pkg:3_1 の 2 つのターゲットに依存します。 これは //pkg:n_0 と //pkg:n_1 まで続きますが、どちらも 1 つの target, //pkg:dep.

//pkg:app を構築するには \(2n+2\) ターゲット:

  • //pkg:app
  • //pkg:dep
  • \(i\) \([1..n]\)で //pkg:i_0//pkg:i_1

たとえば、フラグを実装するとします。 --//foo:owner=<STRING>//pkg:i_b が適用されます

depConfig = myConfig + depConfig.owner="$(myConfig.owner)$(b)"

つまり、//pkg:i_b は、すべてのテーブルで --owner の古い値に b を付加します。 依存関係があります。

これにより、次の構成済みターゲットが生成されます。

//pkg:app                              //foo:owner=""
//pkg:1_0                              //foo:owner=""
//pkg:1_1                              //foo:owner=""
//pkg:2_0 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_0 (via //pkg:1_1)              //foo:owner="1"
//pkg:2_1 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_1 (via //pkg:1_1)              //foo:owner="1"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_0)  //foo:owner="00"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_1)  //foo:owner="01"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_0)  //foo:owner="10"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_1)  //foo:owner="11"
...

//pkg:dep が \(2^n\) 構成されたターゲット config.owner= を生成します。 「\(b_0b_1...b_n\)」の \(b_i\) \(\{0,1\}\)

これにより、ビルドグラフがターゲット グラフより指数関数的に大きくなり、 メモリやパフォーマンスにも影響します

TODO: これらの問題の測定と軽減のための戦略を追加する。

関連情報

ビルド構成の変更について詳しくは、以下をご覧ください。