일반적으로 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
의 상위 집합입니다. 예: values = {"cpu": "x86", "compilation_mode": "dbg"}
values = {"cpu": "x86"}
의 명확한 전문 분야입니다.
기본 제공 조건 //conditions:default
은 다음과 같은 경우 자동으로 일치합니다.
아무것도 하지 않습니다.
이 예에서는 deps
를 사용하지만 select()
는 srcs
, resources
, cmd
, 기타 대부분의 속성에서도 잘 작동합니다. 소수의 속성만
구성이 불가능하며 명확하게 주석이 추가되어 있습니다. 예를 들어 config_setting
의 자체 values
속성은 구성할 수 없습니다.
select()
및 종속 항목
특정 속성은 모든 전이 종속 항목의 빌드 매개변수를 변경합니다.
확인할 수 있습니다 예를 들어 genrule
의 tools
는 --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.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
는 해당 플래그의 예상 값입니다. 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 속성
(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_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
Skylib의 selects
모듈에 있는 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의 selects
모듈에 있는 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
는 직접 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({
"//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를 반환하는 이유는 무엇인가요?
정의상 매크로 (규칙 아님) 때문에
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()를 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 = {
"//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()
은
실제로 특정 브랜치로 평가됩니다.
대신 다음과 같이 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
에 있는 대체 항목이 표시됩니다.
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팀은 이러한 작업을 권장하지 않습니다. 빌드를 과도하게 제한하고 예상 조건이 일치하지 않을 때 사용자를 혼동하기 때문입니다.