일반적으로 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"}
입니다.
* 어떤 항목의 values
은 다른 모든 요소의 엄격한 상위 집합입니다. 예를 들어 values = {"cpu": "x86", "compilation_mode": "dbg"}
는 values = {"cpu": "x86"}
의 명확한 특수화입니다.
기본 제공 조건 //conditions:default
은 다음과 같은 경우 자동으로 일치합니다.
아무것도 하지 않습니다.
이 예에서는 deps
를 사용하지만 select()
는 srcs
, resources
, cmd
, 기타 대부분의 속성에서도 잘 작동합니다. 소수의 속성만 구성할 수 없으며 이러한 속성에는 명확하게 주석이 달려 있습니다. 예를 들어
config_setting
님의 소유
values
속성은 구성할 수 없습니다.
select()
및 종속 항목
특정 속성은 모든 전이 종속 항목의 빌드 매개변수를 변경합니다.
확인할 수 있습니다 예를 들어 genrule
의 tools
는 --cpu
를 다음 CPU의 CPU로 변경합니다.
Bazel을 실행하는 머신 (크로스 컴파일 덕분에
더 높은 CPU 사용률이 발생할 수 있습니다. 이것을
구성 전환에 대해 자세히 알아보세요.
Given
#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
는 --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_setting
의
flag_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",
],
)
플랫폼은 명령줄에서 지정할 수 있습니다. 플랫폼의 constraint_values
하위 집합을 포함하는 config_setting
를 활성화하여 이러한 config_setting
가 select()
표현식에서 일치하도록 합니다.
예를 들어 my_rocks
의 srcs
속성을 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
매크로 Skylib의
selects
모듈은 select
내에서 직접 OR
ing 조건을 지원합니다.
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
매크로 Skylib의
selects
모듈은 여러 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
는 직접 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()를 dict처럼 읽을 수 있나요?
매크로가 선택사항을 평가할 수 없습니다. 이는 매크로가 이전에 평가되기 때문입니다.
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 규칙이고
지정할 수 있습니다
$ 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()
가 있는 경우 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": [],
}),
)
이 프로세스는 특정 의미론을 정의하여 사용자가 원하는 조건을 충족하는 플랫폼을 더 명확하게 파악할 수 있도록 합니다.
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팀은 이러한 작업을 권장하지 않습니다. 빌드를 과도하게 제한하고 예상 조건이 일치하지 않을 때 사용자를 혼동하기 때문입니다.