구성 가능한 속성(일반적으로 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",
},
)
이렇게 하면 명령줄의 플래그에 따라 deps를 선택하는 cc_binary
를 선언합니다. 구체적으로 deps
는 다음과 같습니다.
명령어 | ps = |
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()
를 사용하면 서로 다른 조건이 적용될 때 속성이 다른 값을 효과적으로 채택합니다.
일치는 명확해야 합니다. 정확히 1개의 조건만 일치해야 하며, 여러 조건이 일치하는 경우 1은 values
가 다른 모든 요소의 엄격한 상위 집합이어야 합니다. 예를 들어 values = {"cpu": "x86", "compilation_mode": "dbg"}
은 values = {"cpu": "x86"}
의 모호한 특화 과정입니다. 기본 제공 조건 //conditions:default
은 다른 조건이 없을 때 자동으로 일치합니다.
이 예시에서는 deps
를 사용하지만 select()
, srcs
, resources
, cmd
은 대부분의 다른 속성에서도 잘 작동합니다. 소수의 속성만 구성 불가능하며 명확하게 주석이 달립니다. 예를 들어 config_setting
의 자체 values
속성은 구성할 수 없습니다.
select()
및 종속 항목
특정 속성이 타겟 아래의 모든 전이 종속 항목에 관한 빌드 매개변수를 변경합니다. 예를 들어 genrule
의 tools
은 Bazel을 실행하는 머신의 CPU로 --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.src
, tool1
, x86tool.cc
에 바인딩합니다. my_genrule
에 연결된 두 select
모두 my_genrule
및 빌드 매개변수를 사용합니다. 여기에는 --cpu=arm
가 포함되어 있습니다. tools
속성이 tool1
및 전이 종속 항목에 관해 --cpu
를 x86
로 변경합니다. tool1
의 select
는 tool1
의 빌드 매개변수를 사용하며 여기에는 --cpu=x86
가 포함됩니다.
구성 조건
구성 가능한 속성의 각 키는 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
는 플래그의 예상 값입니다. values
의 모든 항목이 일치하면 :meaningful_condition_name
가 일치합니다. 관련 없는 주문입니다.
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_setting
및 flag_values
속성을 사용하여 트리거됩니다.
config_setting(
name = "meaningful_condition_name",
flag_values = {
"//myflags:flag1": "value1",
"//myflags:flag2": "value2",
...
},
)
동작은 기본 제공 플래그와 동일합니다. 실제 예시는 여기를 참조하세요.
--define
는 맞춤 플래그의 대체 기존 구문입니다 (예: --define foo=bar
). 이는 값 속성(values = {"define": "foo=bar"}
) 또는 정의_값 속성(define_values = {"foo": "bar"}
)으로 표현될 수 있습니다. --define
은 이전 버전과의 호환성에만 지원됩니다. 가능하면 Starlark 빌드 설정을 사용하는 것이 좋습니다.
values
, flag_values
, define_values
는 독립적으로 평가됩니다. config_setting
는 모두의 값이 모두 일치하면 일치합니다.
기본 조건
다른 조건이 일치할 때 기본 제공 조건 //conditions:default
는 일치합니다.
'정확히 하나의 일치' 규칙으로 인해 일치 여부와 기본 조건이 없는 구성 가능한 속성은 "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_setting
를 select()
표현식과 일치시킬 수 있습니다.
예를 들어 my_rocks
의 srcs
속성을 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"]
를 여러 번 반복하지 않는 것이 좋습니다.
한 가지 옵션은 값을 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
Skylib'sselects
모듈의 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
Skylib'sselects
모듈의 config_setting_group 매크로에서 여러 config_setting
OR
를 지원합니다.
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
는 select
내에 직접 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"}, ...)
받는 사람
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({
"//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_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를 반환하는 이유는 무엇인가요?
정의에 따라 매크로 (규칙은 아님)sselect()
s를 평가할 수 없기 때문에 일반적으로 다음과 같은 경우 오류가 발생합니다.
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()
객체 자체입니다. Python 디자인 표준에 따르면 극소수의 예외를 제외한 모든 객체가 자동으로 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()
는 BUILD 규칙이 아닌 WORKSPACE 규칙입니다.
Workspace 규칙에는 특정 구성이 없으며 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
에 있는 대체 항목이 표시됩니다.
select()가 예상한 내용을 선택하지 않는 이유는 무엇인가요?
select()
에 //myapp:foo
이 있어야 하는 조건을 선택하지 않으면 cquery와 bazel 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:foo
의 select()
을 확인하는 구성의 해시입니다. 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
파일은 대상 플랫폼에 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": [],
}),
)
이 프로세스는 특정 조건을 정의하여 어떤 플랫폼에서 원하는 조건을 충족하는지 더 명확하게 나타냅니다.
정말로 플랫폼에서 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팀은 이러한 작업을 보증하지 않으며, 빌드가 과도하게 제한되며 예상 조건이 일치하지 않으면 사용자에게 혼란이 발생합니다.