構成可能なビルド属性

問題を報告する ソースを表示 ナイトリー · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

構成可能な属性(一般に select() と呼ばれます)は、ユーザーがコマンドラインでビルドルール属性の値を切り替えることができる Bazel の機能です。

これは、アーキテクチャに適した実装を自動的に選択するマルチプラットフォーム ライブラリや、ビルド時にカスタマイズできる機能構成可能なバイナリなどに使用できます。

# myapp/BUILD

cc_binary(
    name = "mybinary",
    srcs = ["main.cc"],
    deps = select({
        ":arm_build": [":arm_lib"],
        ":x86_debug_build": [":x86_dev_lib"],
        "//conditions:default": [":generic_lib"],
    }),
)

config_setting(
    name = "arm_build",
    values = {"cpu": "arm"},
)

config_setting(
    name = "x86_debug_build",
    values = {
        "cpu": "x86",
        "compilation_mode": "dbg",
    },
)

これは、コマンドラインのフラグに基づいて依存関係を「選択」する cc_binary を宣言します。具体的には、deps は次のようになります。

コマンド deps =
bazel build //myapp:mybinary --cpu=arm [":arm_lib"]
bazel build //myapp:mybinary -c dbg --cpu=x86 [":x86_dev_lib"]
bazel build //myapp:mybinary --cpu=ppc [":generic_lib"]
bazel build //myapp:mybinary -c dbg --cpu=ppc [":generic_lib"]

select() は、config_setting ターゲットを参照するラベルである構成条件に基づいて選択される値のプレースホルダとして機能します。構成可能な属性で select() を使用すると、異なる条件が満たされたときに、属性が効果的に異なる値を採用します。

一致は明確である必要があります。複数の条件が一致する場合は、* すべて同じ値に解決されるか、たとえば、linux x86 で実行する場合、両方のブランチが「hello」に解決されるため、これは明確な {"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"} です。* 1 つの values は、他のすべての values の厳密なスーパーセットです。たとえば、values = {"cpu": "x86", "compilation_mode": "dbg"}values = {"cpu": "x86"} の明確な特殊化です。

他の条件が一致しない場合、組み込み条件 //conditions:default が自動的に一致します。

この例では deps を使用していますが、select()srcsresourcescmd、その他のほとんどの属性でも同様に機能します。構成不可の属性はごく少数であり、明確にアノテーションが付けられています。たとえば、config_setting 独自の values 属性は構成できません。

select() と依存関係

特定の属性は、ターゲット内のすべての伝播依存関係のビルド パラメータを変更します。たとえば、genruletools は、--cpu を Bazel を実行しているマシンの CPU に変更します(これは、クロスコンパイルにより、ターゲットがビルドされている CPU とは異なる場合があります)。これは構成の移行と呼ばれます。

指定

#myapp/BUILD

config_setting(
    name = "arm_cpu",
    values = {"cpu": "arm"},
)

config_setting(
    name = "x86_cpu",
    values = {"cpu": "x86"},
)

genrule(
    name = "my_genrule",
    srcs = select({
        ":arm_cpu": ["g_arm.src"],
        ":x86_cpu": ["g_x86.src"],
    }),
    tools = select({
        ":arm_cpu": [":tool1"],
        ":x86_cpu": [":tool2"],
    }),
)

cc_binary(
    name = "tool1",
    srcs = select({
        ":arm_cpu": ["armtool.cc"],
        ":x86_cpu": ["x86tool.cc"],
    }),
)

実行中

$ bazel build //myapp:my_genrule --cpu=arm

x86 デベロッパー マシンで、ビルドを g_arm.srctool1x86tool.cc にバインドします。my_genrule に接続されている select の両方が、my_genrule のビルドパラメータ(--cpu=arm など)を使用します。tools 属性は、tool1 とその推移的依存関係の --cpux86 に変更します。tool1select は、--cpu=x86 を含む tool1 のビルドパラメータを使用します。

構成条件

構成可能な属性の各キーは、config_setting または constraint_value を参照するラベルです。

config_setting は、想定されるコマンドライン フラグの設定の集合です。これらをターゲットにカプセル化することで、ユーザーが複数の場所から参照できる「標準」条件を簡単に維持できます。

constraint_value は、マルチプラットフォームの動作をサポートしています。

組み込みフラグ

--cpu などのフラグは Bazel に組み込まれています。ビルドツールは、すべてのプロジェクトのすべてのビルドでフラグをネイティブに認識します。これらは、config_settingvalues 属性で指定します。

config_setting(
    name = "meaningful_condition_name",
    values = {
        "flag1": "value1",
        "flag2": "value2",
        ...
    },
)

flagN はフラグ名です(-- なし。"--cpu" ではなく "cpu")。valueN はそのフラグの想定値です。valuesすべてのエントリが一致する場合、:meaningful_condition_name は一致します。順序は無関係です。

valueN は、コマンドラインで設定された場合と同様に解析されます。具体的には、次のようになります。

  • bazel build -c opt に一致する values = { "compilation_mode": "opt" }
  • bazel build --force_pic=1 に一致する values = { "force_pic": "true" }
  • bazel build --noforce_pic に一致する values = { "force_pic": "0" }

config_setting は、ターゲットの動作に影響するフラグのみをサポートします。たとえば、--show_progress は、Bazel がユーザーに進捗状況を報告する方法にのみ影響するため、許可されません。ターゲットは、そのフラグを使用して結果を構築できません。サポートされているフラグの正確なセットは文書化されていません。実際には、「意味のある」ほとんどのフラグが機能します。

カスタムフラグ

独自のプロジェクト固有のフラグは、Starlark ビルド設定でモデル化できます。組み込みフラグとは異なり、これらはビルド ターゲットとして定義されるため、Bazel はターゲットラベルで参照します。

これらは、config_settingflag_values 属性でトリガーされます。

config_setting(
    name = "meaningful_condition_name",
    flag_values = {
        "//myflags:flag1": "value1",
        "//myflags:flag2": "value2",
        ...
    },
)

動作は組み込みフラグの場合と同じです。動作例については、こちらをご覧ください。

--define は、カスタム フラグ(--define foo=bar など)の代替の従来構文です。これは、values 属性(values = {"define": "foo=bar"})または define_values 属性(define_values = {"foo": "bar"})で表現できます。--define は下位互換性のためにのみサポートされています。可能な限り Starlark ビルド設定を使用する。

valuesflag_valuesdefine_values は個別に評価されます。すべての値が一致する場合、config_setting は一致します。

デフォルトの条件

組み込み条件 //conditions:default は、他の条件が一致しない場合に一致します。

「1 つ以上の一致」ルールにより、一致がなく、デフォルト条件もない構成可能な属性は、"no matching conditions" エラーを出力します。これにより、予期しない設定によるサイレント障害を防ぐことができます。

# myapp/BUILD

config_setting(
    name = "x86_cpu",
    values = {"cpu": "x86"},
)

cc_library(
    name = "x86_only_lib",
    srcs = select({
        ":x86_cpu": ["lib.cc"],
    }),
)
$ bazel build //myapp:x86_only_lib --cpu=arm
ERROR: Configurable attribute "srcs" doesn't match this configuration (would
a default condition help?).
Conditions checked:
  //myapp:x86_cpu

エラーをより明確にするには、select()no_match_error 属性を使用してカスタム メッセージを設定します。

プラットフォーム

コマンドラインで複数のフラグを指定できると柔軟性が向上しますが、ターゲットをビルドするたびにフラグを個別に設定するのは手間がかかります。プラットフォームを使用すると、これらをシンプルなバンドルに統合できます。

# myapp/BUILD

sh_binary(
    name = "my_rocks",
    srcs = select({
        ":basalt": ["pyroxene.sh"],
        ":marble": ["calcite.sh"],
        "//conditions:default": ["feldspar.sh"],
    }),
)

config_setting(
    name = "basalt",
    constraint_values = [
        ":black",
        ":igneous",
    ],
)

config_setting(
    name = "marble",
    constraint_values = [
        ":white",
        ":metamorphic",
    ],
)

# constraint_setting acts as an enum type, and constraint_value as an enum value.
constraint_setting(name = "color")
constraint_value(name = "black", constraint_setting = "color")
constraint_value(name = "white", constraint_setting = "color")
constraint_setting(name = "texture")
constraint_value(name = "smooth", constraint_setting = "texture")
constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")

platform(
    name = "basalt_platform",
    constraint_values = [
        ":black",
        ":igneous",
    ],
)

platform(
    name = "marble_platform",
    constraint_values = [
        ":white",
        ":smooth",
        ":metamorphic",
    ],
)

プラットフォームはコマンドラインで指定できます。プラットフォームの constraint_values のサブセットを含む config_setting が有効になり、これらの config_settingselect() 式で一致するようになります。

たとえば、my_rockssrcs 属性を calcite.sh に設定するには、次のコマンドを実行します。

bazel build //my_app:my_rocks --platforms=//myapp:marble_platform

プラットフォームがない場合、これは次のようになります。

bazel build //my_app:my_rocks --define color=white --define texture=smooth --define type=metamorphic

select()constraint_value を直接読み取ることもできます。

constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")
sh_binary(
    name = "my_rocks",
    srcs = select({
        ":igneous": ["igneous.sh"],
        ":metamorphic" ["metamorphic.sh"],
    }),
)

これにより、単一の値のみをチェックする必要がある場合に、ボイラープレートの config_setting を必要としません。

プラットフォームは現在開発中です。詳しくは、ドキュメントをご覧ください。

select() の組み合わせ

select は同じ属性に複数回出現できます。

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"] +
           select({
               ":armeabi_mode": ["armeabi_src.sh"],
               ":x86_mode": ["x86_src.sh"],
           }) +
           select({
               ":opt_mode": ["opt_extras.sh"],
               ":dbg_mode": ["dbg_extras.sh"],
           }),
)

select は別の select 内に指定することはできません。selects をネストする必要がある場合、属性が他のターゲットを値として取る場合は、中間ターゲットを使用します。

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":armeabi_mode": [":armeabi_lib"],
        ...
    }),
)

sh_library(
    name = "armeabi_lib",
    srcs = select({
        ":opt_mode": ["armeabi_with_opt.sh"],
        ...
    }),
)

複数の条件が一致したときに select が一致する必要がある場合は、AND チェーンを検討してください。

OR チェーン

次の点を考慮してください。

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1": [":standard_lib"],
        ":config2": [":standard_lib"],
        ":config3": [":standard_lib"],
        ":config4": [":special_lib"],
    }),
)

ほとんどの条件は同じ dep に評価されますが、この構文は読みやすく、メンテナンスも容易ではありません。[":standard_lib"] を複数回繰り返さなくて済むと便利です。

1 つの方法は、値を BUILD 変数として事前定義することです。

STANDARD_DEP = [":standard_lib"]

sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1": STANDARD_DEP,
        ":config2": STANDARD_DEP,
        ":config3": STANDARD_DEP,
        ":config4": [":special_lib"],
    }),
)

これにより、依存関係を簡単に管理できます。ただし、それでも不要な重複が発生します。

より直接的なサポートが必要な場合は、次のいずれかを使用します。

selects.with_or

Skylibselects モジュールの with_or マクロは、select 内で直接条件を OR できます。

load("@bazel_skylib//lib:selects.bzl", "selects")
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = selects.with_or({
        (":config1", ":config2", ":config3"): [":standard_lib"],
        ":config4": [":special_lib"],
    }),
)

selects.config_setting_group

Skylibselects モジュールの config_setting_group マクロは、複数の config_settingOR をサポートしています。

load("@bazel_skylib//lib:selects.bzl", "selects")
config_setting(
    name = "config1",
    values = {"cpu": "arm"},
)
config_setting(
    name = "config2",
    values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
    name = "config1_or_2",
    match_any = [":config1", ":config2"],
)
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1_or_2": [":standard_lib"],
        "//conditions:default": [":other_lib"],
    }),
)

selects.with_or とは異なり、異なるターゲットが異なる属性間で :config1_or_2 を共有できます。

1 つが他の条件の明確な「特殊化」であるか、すべてが同じ値に解決されない限り、複数の条件が一致することはエラーです。詳しくはこちらをご覧ください。

AND チェーン

複数の条件が一致したときに一致する select ブランチが必要な場合は、Skylib マクロ config_setting_group を使用します。

config_setting(
    name = "config1",
    values = {"cpu": "arm"},
)
config_setting(
    name = "config2",
    values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
    name = "config1_and_2",
    match_all = [":config1", ":config2"],
)
sh_binary(
    name = "my_target",
    srcs = ["always_include.sh"],
    deps = select({
        ":config1_and_2": [":standard_lib"],
        "//conditions:default": [":other_lib"],
    }),
)

OR チェーンとは異なり、既存の config_settingselect 内で直接 AND することはできません。明示的に config_setting_group でラップする必要があります。

カスタムエラー メッセージ

デフォルトでは、条件が一致しない場合、select() が適用されているターゲットは失敗し、次のエラーが返されます。

ERROR: Configurable attribute "deps" doesn't match this configuration (would
a default condition help?).
Conditions checked:
  //tools/cc_target_os:darwin
  //tools/cc_target_os:android

これは no_match_error 属性でカスタマイズできます。

cc_library(
    name = "my_lib",
    deps = select(
        {
            "//tools/cc_target_os:android": [":android_deps"],
            "//tools/cc_target_os:windows": [":windows_deps"],
        },
        no_match_error = "Please build with an Android or Windows toolchain",
    ),
)
$ bazel build //myapp:my_lib
ERROR: Configurable attribute "deps" doesn't match this configuration: Please
build with an Android or Windows toolchain

ルールの互換性

ルールの実装は、構成可能な属性の解決済み値を受け取ります。次に例を示します。

# myapp/BUILD

some_rule(
    name = "my_target",
    some_attr = select({
        ":foo_mode": [":foo"],
        ":bar_mode": [":bar"],
    }),
)
$ bazel build //myapp/my_target --define mode=foo

ルールの実装コードでは、ctx.attr.some_attr[":foo"] と見なされます。

マクロは select() 句を受け入れてネイティブ ルールに渡すことができます。ただし、直接操作することはできません。たとえば、マクロで

select({"foo": "val"}, ...)

to

select({"foo": "val_with_suffix"}, ...)

これには 2 つの理由があります。

まず、select が選択するパスを把握する必要があるマクロは機能しません。マクロは Bazel の読み込みフェーズで評価されますが、これはフラグ値が判明する前に行われます。これは Bazel の設計上の制限事項であり、すぐに変更される可能性は低いです。

2 つ目は、select パスをすべて反復処理するだけのマクロは、技術的には実現可能ですが、一貫した UI がありません。これを変更するには、さらに設計する必要があります。

Bazel クエリと cquery

Bazel の query は、Bazel の読み込みフェーズで動作します。つまり、これらのフラグはビルドの後半(分析フェーズ)で評価されるため、ターゲットが使用するコマンドライン フラグはわかりません。そのため、どの select() ブランチが選択されているかを判断できません。

Bazel の cquery は Bazel の分析フェーズ後に動作するため、これらの情報をすべて保持し、select() を正確に解決できます。

検討事項:

load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
# myapp/BUILD

string_flag(
    name = "dog_type",
    build_setting_default = "cat"
)

cc_library(
    name = "my_lib",
    deps = select({
        ":long": [":foo_dep"],
        ":short": [":bar_dep"],
    }),
)

config_setting(
    name = "long",
    flag_values = {":dog_type": "dachshund"},
)

config_setting(
    name = "short",
    flag_values = {":dog_type": "pug"},
)

query:my_lib の依存関係を過剰に近似します。

$ bazel query 'deps(//myapp:my_lib)'
//myapp:my_lib
//myapp:foo_dep
//myapp:bar_dep

cquery は、正確な依存関係を示します。

$ bazel cquery 'deps(//myapp:my_lib)' --//myapp:dog_type=pug
//myapp:my_lib
//myapp:bar_dep

よくある質問

マクロで select() が機能しないのはなぜですか?

select() はルールで機能します。詳しくは、ルールの互換性をご覧ください。

この質問は通常、マクロで select() が機能しないことを意味します。これはルールとは異なります。違いについては、ルールマクロのドキュメントをご覧ください。エンドツーエンドの例を次に示します。

ルールとマクロを定義します。

# myapp/defs.bzl

# Rule implementation: when an attribute is read, all select()s have already
# been resolved. So it looks like a plain old attribute just like any other.
def _impl(ctx):
    name = ctx.attr.name
    allcaps = ctx.attr.my_config_string.upper()  # This works fine on all values.
    print("My name is " + name + " with custom message: " + allcaps)

# Rule declaration:
my_custom_bazel_rule = rule(
    implementation = _impl,
    attrs = {"my_config_string": attr.string()},
)

# Macro declaration:
def my_custom_bazel_macro(name, my_config_string):
    allcaps = my_config_string.upper()  # This line won't work with select(s).
    print("My name is " + name + " with custom message: " + allcaps)

ルールとマクロをインスタンス化します。

# myapp/BUILD

load("//myapp:defs.bzl", "my_custom_bazel_rule")
load("//myapp:defs.bzl", "my_custom_bazel_macro")

my_custom_bazel_rule(
    name = "happy_rule",
    my_config_string = select({
        "//tools/target_cpu:x86": "first string",
        "//third_party/bazel_platforms/cpu:ppc": "second string",
    }),
)

my_custom_bazel_macro(
    name = "happy_macro",
    my_config_string = "fixed string",
)

my_custom_bazel_macro(
    name = "sad_macro",
    my_config_string = select({
        "//tools/target_cpu:x86": "first string",
        "//third_party/bazel_platforms/cpu:ppc": "other string",
    }),
)

sad_macroselect() を処理できないため、ビルドが失敗します。

$ bazel build //myapp:all
ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
  (most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
  my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().
ERROR: error loading package 'myapp': Package 'myapp' contains errors.

sad_macro をコメント化すると、ビルドが成功します。

# Comment out sad_macro so it doesn't mess up the build.
$ bazel build //myapp:all
DEBUG: /myworkspace/myapp/defs.bzl:5:3: My name is happy_macro with custom message: FIXED STRING.
DEBUG: /myworkspace/myapp/hi.bzl:15:3: My name is happy_rule with custom message: FIRST STRING.

これは、Bazel がビルドのコマンドライン フラグを読み取る前にマクロが評価されるため、定義上変更できません。つまり、select() を評価するのに十分な情報がないことを意味します。

ただし、マクロは select() を不透明な blob としてルールに渡すことができます。

# myapp/defs.bzl

def my_custom_bazel_macro(name, my_config_string):
    print("Invoking macro " + name)
    my_custom_bazel_rule(
        name = name + "_as_target",
        my_config_string = my_config_string,
    )
$ bazel build //myapp:sad_macro_less_sad
DEBUG: /myworkspace/myapp/defs.bzl:23:3: Invoking macro sad_macro_less_sad.
DEBUG: /myworkspace/myapp/defs.bzl:15:3: My name is sad_macro_less_sad with custom message: FIRST STRING.

select() が常に true を返すのはなぜですか?

マクロ(ルールは除く)は、定義上 select() を評価できないため、評価しようとすると通常はエラーが発生します。

ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
  (most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
  my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().

ブール値は、サイレント エラーになる特殊なケースであるため、特に注意が必要です。

$ cat myapp/defs.bzl
def my_boolean_macro(boolval):
  print("TRUE" if boolval else "FALSE")

$ cat myapp/BUILD
load("//myapp:defs.bzl", "my_boolean_macro")
my_boolean_macro(
    boolval = select({
        "//tools/target_cpu:x86": True,
        "//third_party/bazel_platforms/cpu:ppc": False,
    }),
)

$ bazel build //myapp:all --cpu=x86
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.
$ bazel build //mypro:all --cpu=ppc
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.

これは、マクロが select() の内容を理解していないためです。実際に評価しているのは select() オブジェクト自体です。Pythonic 設計標準に従い、ごく少数の例外を除くすべてのオブジェクトは自動的に true を返します。

select() を辞書のように読み取ることはできますか?

マクロは、Bazel がビルドのコマンドライン パラメータを知る前に評価されるため、選択を評価できません。少なくとも select() の辞書を読み取って、各値に接尾辞を追加することはできますか?

概念的には可能ですが、まだ Bazel の機能ではありません。現在できることは、単純なディクショナリを準備して select() にフィードすることです。

$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
  for key in select_cmd.keys():
    select_cmd[key] += " WITH SUFFIX"
  native.genrule(
      name = name,
      outs = [name + ".out"],
      srcs = [],
      cmd = "echo " + select(select_cmd + {"//conditions:default": "default"})
        + " > $@"
  )

$ cat myapp/BUILD
selecty_genrule(
    name = "selecty",
    select_cmd = {
        "//tools/target_cpu:x86": "x86 mode",
    },
)

$ bazel build //testapp:selecty --cpu=x86 && cat bazel-genfiles/testapp/selecty.out
x86 mode WITH SUFFIX

select() とネイティブ タイプの両方をサポートする場合は、次のようにします。

$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
    cmd_suffix = ""
    if type(select_cmd) == "string":
        cmd_suffix = select_cmd + " WITH SUFFIX"
    elif type(select_cmd) == "dict":
        for key in select_cmd.keys():
            select_cmd[key] += " WITH SUFFIX"
        cmd_suffix = select(select_cmd + {"//conditions:default": "default"})

    native.genrule(
        name = name,
        outs = [name + ".out"],
        srcs = [],
        cmd = "echo " + cmd_suffix + "> $@",
    )

select() が bind() で機能しないのはなぜですか?

まず、bind() は使用しないでください。alias() に置き換えられたため、非推奨になりました。

技術的な回答としては、bind() は BUILD ルールではなくリポジトリ ルールです。

リポジトリ ルールには特定の構成はなく、BUILD ルールと同じ方法で評価されません。したがって、bind()select() は、実際には特定のブランチに評価されません。

代わりに、このタイプのランタイム判定を行うには、actual 属性に select() を指定して alias() を使用する必要があります。これは、alias() が BUILD ルールであり、特定の構成で評価されるため、正しく機能します。

必要に応じて、bind() ターゲットを alias() に設定することもできます。

$ cat WORKSPACE
workspace(name = "myapp")
bind(name = "openssl", actual = "//:ssl")
http_archive(name = "alternative", ...)
http_archive(name = "boringssl", ...)

$ cat BUILD
config_setting(
    name = "alt_ssl",
    define_values = {
        "ssl_library": "alternative",
    },
)

alias(
    name = "ssl",
    actual = select({
        "//:alt_ssl": "@alternative//:ssl",
        "//conditions:default": "@boringssl//:ssl",
    }),
)

この設定では、--define ssl_library=alternative を渡すことができます。//:ssl または //external:ssl に依存するターゲットには、@alternative//:ssl にある代替が示されます。

ただし、bind() の使用は止めてください。

select() が想定どおりに選択されないのはなぜですか?

//myapp:foo に、想定される条件を選択しない select() がある場合は、cquerybazel config を使用してデバッグします。

ビルドする最上位のターゲットが //myapp:foo の場合は、次のコマンドを実行します。

$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)

サブグラフのどこかで //myapp:foo に依存する他のターゲット //bar をビルドする場合は、次のコマンドを実行します。

$ bazel cquery 'somepath(//bar, //myapp:foo)' <desired build flags>
//bar:bar   (3ag3193fee94a2)
//bar:intermediate_dep (12e23b9a2b534a)
//myapp:foo (12e23b9a2b534a)

//myapp:foo の横にある (12e23b9a2b534a) は、//myapp:fooselect() を解決する構成のハッシュです。値は bazel config で確認できます。

$ bazel config 12e23b9a2b534a
BuildConfigurationValue 12e23b9a2b534a
Fragment com.google.devtools.build.lib.analysis.config.CoreOptions {
  cpu: darwin
  compilation_mode: fastbuild
  ...
}
Fragment com.google.devtools.build.lib.rules.cpp.CppOptions {
  linkopt: [-Dfoo=bar]
  ...
}
...

次に、この出力を各 config_setting で想定される設定と比較します。

//myapp:foo は、同じビルド内の異なる構成に存在する場合があります。somepath を使用して適切なものを取得する方法については、cquery のドキュメントをご覧ください。

select() がプラットフォームで機能しないのはなぜですか?

Bazel では、セマンティクスが不明確なため、特定のプラットフォームがターゲット プラットフォームであるかどうかを確認する構成可能な属性はサポートされていません。

次に例を示します。

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

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":x86_linux_platform": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

この BUILD ファイルで、ターゲット プラットフォームに @platforms//cpu:x86 制約と @platforms//os:linux 制約の両方があり、ここで定義されている :x86_linux_platform ではない場合は、どの select() を使用する必要がありますか。BUILD ファイルの作成者と、個別のプラットフォームを定義したユーザーの考えが異なる場合があります。

別の方法があれば教えてください。

代わりに、次の制約で任意のプラットフォームに一致する config_setting を定義します。

config_setting(
    name = "is_x86_linux",
    constraint_values = [
        "@platforms//cpu:x86",
        "@platforms//os:linux",
    ],
)

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":is_x86_linux": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

このプロセスでは、特定のセマンティクスを定義し、目的の条件を満たすプラットフォームをユーザーに明確にします。

プラットフォームで select を本当に本当にしたい場合はどうすればよいですか?

ビルド要件でプラットフォームのチェックが明記されている場合は、config_setting--platforms フラグの値を反転できます。

config_setting(
    name = "is_specific_x86_linux_platform",
    values = {
        "platforms": ["//package:x86_linux_platform"],
    },
)

cc_library(
    name = "lib",
    srcs = [...],
    linkopts = select({
        ":is_specific_x86_linux_platform": ["--enable_x86_optimizations"],
        "//conditions:default": [],
    }),
)

Bazel チームは、この方法を推奨していません。この方法ではビルドが過度に制限され、想定される状態と一致しない場合にユーザーが混乱します。