구성 가능한 빌드 속성

문제 신고 <ph type="x-smartling-placeholder"></ph> 소스 보기 1박 · 7.2 · 7.1 · 7.0 · 6.5 · 6.4

일반적으로 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에서 실행되는 경우 이는 명확합니다. {"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"}, 두 브랜치가 모두 'hello'로 확인되기 때문입니다. * 어떤 항목의 values은 다른 모든 요소의 엄격한 상위 집합입니다. 예: values = {"cpu": "x86", "compilation_mode": "dbg"} values = {"cpu": "x86"}의 명확한 특화입니다.

기본 제공 조건 //conditions:default은 다음과 같은 경우 자동으로 일치합니다. 아무것도 하지 않습니다.

이 예에서는 deps를 사용하지만 select()srcs에서도 잘 작동합니다. resources, cmd 및 대부분의 기타 속성 소수의 속성만 구성이 불가능하며 명확하게 주석이 추가되어 있습니다. 예를 들어 config_setting님의 소유 values 속성은 구성할 수 없습니다.

select() 및 종속 항목

특정 속성은 모든 전이 종속 항목의 빌드 매개변수를 변경합니다. 설정할 수 있습니다 예를 들어 genruletools--cpu를 다음 CPU의 CPU로 변경합니다. Bazel을 실행하는 머신 (크로스 컴파일 덕분에 더 높은 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.src, tool1, x86tool.cc입니다. my_genrule에 연결된 두 select 모두 my_genrule의 빌드 매개변수(--cpu=arm 포함) tools 속성이 tool1 및 전이 종속 항목의 경우 --cpu에서 x86select 켜짐 tool1--cpu=x86를 포함하는 tool1의 빌드 매개변수를 사용합니다.

구성 조건

구성 가능한 속성의 각 키는 config_setting 또는 constraint_value

config_setting은(는) 다음 컬렉션의 컬렉션일 뿐입니다. 명령줄 플래그 설정을 지정할 수 있습니다. 이를 타겟에 캡슐화하면 유지관리가 쉬운 '표준' 사용자가 여러 위치에서 참조할 수 있는 조건입니다.

constraint_value멀티 플랫폼 동작을 지원합니다.

내장 플래그

--cpu와 같은 플래그는 Bazel에 빌드됩니다. 빌드 도구는 기본적으로 모든 빌드에 적용됩니다 이들은 config_setting님의 values 속성:

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

flagN는 플래그 이름입니다 (--이 없으므로 "--cpu" 대신 "cpu"). valueN 는 해당 플래그에 대한 예상 값입니다. :meaningful_condition_name는 다음 조건과 일치합니다. values모든 항목이 일치합니다. 순서가 관련 없습니다.

valueN는 명령줄에서 설정된 것처럼 파싱됩니다. 이는 다음을 의미합니다.

  • values = { "compilation_mode": "opt" }이(가) bazel build -c opt와(과) 일치
  • values = { "force_pic": "true" }이(가) bazel build --force_pic=1와(과) 일치
  • values = { "force_pic": "0" }이(가) bazel build --noforce_pic와(과) 일치

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 빌드 설정을 사용하는 것이 좋습니다.

values, flag_values, define_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",
    ],
)

플랫폼은 명령줄에서 지정할 수 있습니다. Kubernetes가 플랫폼의 constraint_values 하위 집합을 포함하는 config_setting 이러한 config_settingselect() 표현식에서 일치되도록 합니다.

예를 들어 my_rockssrcs 속성을 calcite.sh로 설정하려면 다음을 실행합니다. kubectl 명령어

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가 필요한 경우 그리고 체이닝.

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"]할 필요가 없으면 좋습니다. 표시됩니다.

한 가지 옵션은 값을 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

with_or 매크로 Skylibselects 모듈은 select 내에서 직접 ORing 조건을 지원합니다.

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

config_setting_group 매크로 Skylibselects 모듈은 여러 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을 공유할 수 있습니다. 특성이 포함될 수 있습니다

하나의 조건이 명확하지 않은 한 여러 조건이 일치하면 오류가 발생함 '전문 분야' 모두 동일한 값으로 확인될 수 있습니다. 자세한 내용은 여기를 참고하세요.

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_setting는 직접 AND할 수 없습니다. select 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"}, ...)

여기에는 두 가지 이유가 있습니다.

첫째, select가 선택하는 경로를 알아야 하는 매크로가 작동할 수 없습니다. 이는 매크로가 Bazel의 로드 단계에서 평가되기 때문입니다. 이는 플래그 값이 알려지기 전에 발생합니다. 이는 곧 변경될 가능성이 거의 없는 핵심 Bazel 설계 제한사항입니다.

둘째, 모든 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

FAQ

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({
        "//third_party/bazel_platforms/cpu:x86_32": "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({
        "//third_party/bazel_platforms/cpu:x86_32": "first string",
        "//third_party/bazel_platforms/cpu:ppc": "other string",
    }),
)

sad_macro에서 select()를 처리할 수 없어 빌드가 실패합니다.

$ 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({
        "//third_party/bazel_platforms/cpu:x86_32": 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 = {
        "//third_party/bazel_platforms/cpu:x86_32": "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()은 실제로 특정 브랜치로 평가됩니다.

대신 다음과 같이 select()가 포함된 alias()을 사용해야 합니다. actual 속성을 사용하여 이러한 유형의 런타임 확인을 실행합니다. 이 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)

빌드 중인 다른 대상 //bar는 //myapp:foo가 하위 그래프의 어딘가에 있으면 다음을 실행합니다.

$ 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이(가) 동일한 빌드에서 다른 구성에 있을 수 있습니다. 자세한 내용은 cquery 문서에서 somepath를 사용하여 올바르게 사용하기 위한 안내를 확인하세요. 있습니다

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 파일에서 select()은 대상 플랫폼에 @platforms//cpu:x86@platforms//os:linux 제약 조건을 사용하지만 이 함수는 아닙니다. :x86_linux_platform이 여기에 정의되어 있나요? 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": [],
    }),
)

이 프로세스는 특정 시맨틱을 정의하여 사용자에게 원하는 조건을 충족하는지 확인할 수 있습니다

YouTube에서 정말로 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팀은 이를 권장하지 않습니다. 빌드가 과도하게 제한되고 는 사용자가 예상한 조건이 일치하지 않을 때 혼란을 야기할 수 있습니다.