이 페이지에서는 프로젝트 빌드 방식을 맞춤설정하는 Bazel API인 Starlark 구성의 이점과 기본 사용법을 설명합니다. 빌드 설정을 정의하는 방법을 설명하고 예시를 제공합니다.
이를 통해 다음이 가능합니다.
- 프로젝트의 맞춤 플래그를 정의하여
--define
의 필요성을 없앱니다. - 전환을 작성하여 상위 항목과 다른 구성(예:
--compilation_mode=opt
또는--cpu=arm
)으로 종속 항목을 구성합니다. - 규칙에 더 나은 기본값 적용 (예: 지정된 SDK로
//my:android_app
자동 빌드)
등을 모두 .bzl 파일에서 완전히 가져옵니다 (Bazel 출시 필요 없음). 예시는 bazelbuild/examples
저장소를 참고하세요.
사용자 정의 빌드 설정
빌드 설정은 단일 구성 정보입니다. 구성을 키/값 맵으로 생각하세요. --cpu=ppc
및 --copt="-DFoo"
을 설정하면 {cpu: ppc, copt: "-DFoo"}
와 같은 구성이 생성됩니다. 각 항목은 빌드 설정입니다.
cpu
및 copt
와 같은 기존 플래그는 네이티브 설정입니다. 키가 정의되고 값이 네이티브 Bazel Java 코드 내에 설정됩니다.
Bazel 사용자는 명령줄과 기본적으로 유지관리되는 기타 API를 통해서만 이를 읽고 쓸 수 있습니다. 네이티브 플래그와 이를 노출하는 API를 변경하려면 Bazel 출시가 필요합니다. 사용자 정의 빌드 설정은 .bzl
파일에 정의되므로 변경사항을 등록하기 위해 Bazel 출시가 필요하지 않습니다. 명령줄을 통해 설정할 수도 있습니다(flags
로 지정된 경우 아래 참고). 사용자 정의 전환을 통해 설정할 수도 있습니다.
빌드 설정 정의
build_setting
rule()
매개변수
빌드 설정은 다른 규칙과 같은 규칙이며 Starlark rule()
함수의 build_setting
속성을 사용하여 구분됩니다.
# example/buildsettings/build_settings.bzl
string_flag = rule(
implementation = _impl,
build_setting = config.string(flag = True)
)
build_setting
속성은 빌드 설정의 유형을 지정하는 함수를 사용합니다. 유형은 bool
, string
과 같은 기본 Starlark 유형 집합으로 제한됩니다. 자세한 내용은 config
모듈 문서를 참고하세요. 더 복잡한 입력은 규칙의 구현 함수에서 실행할 수 있습니다. 자세한 내용은 아래를 참고하세요.
config
모듈의 함수는 기본적으로 false로 설정되는 선택적 불리언 매개변수 flag
를 사용합니다. flag
가 true로 설정되면 규칙 작성자가 기본값과 전환을 통해 내부적으로 설정할 수 있을 뿐만 아니라 사용자가 명령줄에서 빌드 설정을 설정할 수도 있습니다.
일부 설정은 사용자가 설정할 수 없어야 합니다. 예를 들어 규칙 작성자가 테스트 규칙 내에서 사용 설정하고 싶은 디버그 모드가 있는 경우 사용자가 다른 테스트가 아닌 규칙 내에서 무차별적으로 해당 기능을 사용 설정할 수 있도록 허용하지 않으려고 합니다.
ctx.build_setting_value 사용
모든 규칙과 마찬가지로 빌드 설정 규칙에는 구현 함수가 있습니다.
빌드 설정의 기본 Starlark 유형 값은 ctx.build_setting_value
메서드를 통해 액세스할 수 있습니다. 이 메서드는 빌드 설정 규칙의 ctx
객체에만 사용할 수 있습니다. 이러한 구현 메서드는 빌드 설정 값을 직접 전달하거나 유형 검사 또는 더 복잡한 구조체 생성과 같은 추가 작업을 실행할 수 있습니다. enum
유형 빌드 설정을 구현하는 방법은 다음과 같습니다.
# example/buildsettings/build_settings.bzl
TemperatureProvider = provider(fields = ['type'])
temperatures = ["HOT", "LUKEWARM", "ICED"]
def _impl(ctx):
raw_temperature = ctx.build_setting_value
if raw_temperature not in temperatures:
fail(str(ctx.label) + " build setting allowed to take values {"
+ ", ".join(temperatures) + "} but was set to unallowed value "
+ raw_temperature)
return TemperatureProvider(type = raw_temperature)
temperature = rule(
implementation = _impl,
build_setting = config.string(flag = True)
)
다중 집합 문자열 플래그 정의
문자열 설정에는 명령줄이나 bazelrc에서 플래그를 여러 번 설정할 수 있는 allow_multiple
매개변수가 추가로 있습니다. 기본값은 여전히 문자열 유형 속성으로 설정됩니다.
# example/buildsettings/build_settings.bzl
allow_multiple_flag = rule(
implementation = _impl,
build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "allow_multiple_flag")
allow_multiple_flag(
name = "roasts",
build_setting_default = "medium"
)
플래그의 각 설정은 단일 값으로 취급됩니다.
$ bazel build //my/target --//example:roasts=blonde \
--//example:roasts=medium,dark
위의 내용은 {"//example:roasts": ["blonde", "medium,dark"]}
로 파싱되고 ctx.build_setting_value
는 ["blonde", "medium,dark"]
목록을 반환합니다.
빌드 설정 인스턴스화
build_setting
매개변수로 정의된 규칙에는 암시적 필수 build_setting_default
속성이 있습니다. 이 속성은 build_setting
매개변수에 의해 선언된 것과 동일한 유형을 사용합니다.
# example/buildsettings/build_settings.bzl
FlavorProvider = provider(fields = ['type'])
def _impl(ctx):
return FlavorProvider(type = ctx.build_setting_value)
flavor = rule(
implementation = _impl,
build_setting = config.string(flag = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
name = "favorite_flavor",
build_setting_default = "APPLE"
)
사전 정의된 설정
Skylib 라이브러리에는 커스텀 Starlark를 작성하지 않고도 인스턴스화할 수 있는 사전 정의된 설정이 포함되어 있습니다.
예를 들어 제한된 문자열 값 집합을 허용하는 설정을 정의하려면 다음을 실행하세요.
# example/BUILD
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
name = "myflag",
values = ["a", "b", "c"],
build_setting_default = "a",
)
전체 목록은 일반적인 빌드 설정 규칙을 참고하세요.
빌드 설정 사용
빌드 설정에 따라 다름
타겟이 구성 정보를 읽으려면 일반 속성 종속 항목을 통해 빌드 설정을 직접 종속하면 됩니다.
# example/rules.bzl
load("//example/buildsettings:build_settings.bzl", "FlavorProvider")
def _rule_impl(ctx):
if ctx.attr.flavor[FlavorProvider].type == "ORANGE":
...
drink_rule = rule(
implementation = _rule_impl,
attrs = {
"flavor": attr.label()
}
)
# example/BUILD
load("//example:rules.bzl", "drink_rule")
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
name = "favorite_flavor",
build_setting_default = "APPLE"
)
drink_rule(
name = "my_drink",
flavor = ":favorite_flavor",
)
언어는 해당 언어의 모든 규칙이 종속되는 표준 빌드 설정 집합을 만들 수 있습니다. fragments
의 기본 개념은 더 이상 Starlark 구성 세계에서 하드코딩된 객체로 존재하지 않지만 이 개념을 변환하는 한 가지 방법은 일반적인 암시적 속성 집합을 사용하는 것입니다. 예를 들면 다음과 같습니다.
# kotlin/rules.bzl
_KOTLIN_CONFIG = {
"_compiler": attr.label(default = "//kotlin/config:compiler-flag"),
"_mode": attr.label(default = "//kotlin/config:mode-flag"),
...
}
...
kotlin_library = rule(
implementation = _rule_impl,
attrs = dicts.add({
"library-attr": attr.string()
}, _KOTLIN_CONFIG)
)
kotlin_binary = rule(
implementation = _binary_impl,
attrs = dicts.add({
"binary-attr": attr.label()
}, _KOTLIN_CONFIG)
명령줄에서 빌드 설정 사용
대부분의 네이티브 플래그와 마찬가지로 명령줄을 사용하여 플래그로 표시된 빌드 설정을 설정할 수 있습니다. 빌드 설정의 이름은 name=value
구문을 사용하는 전체 타겟 경로입니다.
$ bazel build //my/target --//example:string_flag=some-value # allowed
$ bazel build //my/target --//example:string_flag some-value # not allowed
특수 불리언 구문이 지원됩니다.
$ bazel build //my/target --//example:boolean_flag
$ bazel build //my/target --no//example:boolean_flag
빌드 설정 별칭 사용
명령줄에서 더 쉽게 읽을 수 있도록 빌드 설정 타겟 경로의 별칭을 설정할 수 있습니다. 별칭은 네이티브 플래그와 유사하게 작동하며 이중 대시 옵션 구문도 사용합니다.
.bazelrc
에 --flag_alias=ALIAS_NAME=TARGET_PATH
을 추가하여 별칭을 설정합니다 . 예를 들어 coffee
에 별칭을 설정하려면 다음을 실행합니다.
# .bazelrc
build --flag_alias=coffee=//experimental/user/starlark_configurations/basic_build_setting:coffee-temp
권장사항: 별칭을 여러 번 설정하면 가장 최근에 설정한 별칭이 우선합니다. 의도하지 않은 파싱 결과를 방지하려면 고유한 별칭 이름을 사용하세요.
별칭을 사용하려면 빌드 설정 타겟 경로 대신 별칭을 입력합니다.
위의 예에서 사용자의 .bazelrc
에 coffee
이 설정된 경우:
$ bazel build //my/target --coffee=ICED
다음을 대신해서 사용합니다.
$ bazel build //my/target --//experimental/user/starlark_configurations/basic_build_setting:coffee-temp=ICED
권장사항: 명령줄에서 별칭을 설정할 수 있지만 .bazelrc
에 별칭을 두면 명령줄이 깔끔해집니다.
라벨 유형 빌드 설정
다른 빌드 설정과 달리 라벨 유형 설정은 build_setting
규칙 매개변수를 사용하여 정의할 수 없습니다. 대신 Bazel에는 label_flag
및 label_setting
의 두 가지 기본 제공 규칙이 있습니다. 이러한 규칙은 빌드 설정이 설정된 실제 타겟의 제공자를 전달합니다. label_flag
및 label_setting
는 전환에 의해 읽고 쓸 수 있으며 label_flag
는 다른 build_setting
규칙과 같이 사용자가 설정할 수 있습니다. 유일한 차이점은 맞춤 정의할 수 없다는 것입니다.
라벨 유형 설정은 결국 늦은 바인딩 기본값의 기능을 대체합니다. 지연 바인딩된 기본 속성은 최종 값이 구성에 영향을 받을 수 있는 라벨 유형 속성입니다. Starlark에서는 configuration_field
API를 대체합니다.
# example/rules.bzl
MyProvider = provider(fields = ["my_field"])
def _dep_impl(ctx):
return MyProvider(my_field = "yeehaw")
dep_rule = rule(
implementation = _dep_impl
)
def _parent_impl(ctx):
if ctx.attr.my_field_provider[MyProvider].my_field == "cowabunga":
...
parent_rule = rule(
implementation = _parent_impl,
attrs = { "my_field_provider": attr.label() }
)
# example/BUILD
load("//example:rules.bzl", "dep_rule", "parent_rule")
dep_rule(name = "dep")
parent_rule(name = "parent", my_field_provider = ":my_field_provider")
label_flag(
name = "my_field_provider",
build_setting_default = ":dep"
)
빌드 설정 및 select()
사용자는 select()
를 사용하여 빌드 설정에서 속성을 구성할 수 있습니다. 빌드 설정 타겟은 config_setting
의 flag_values
속성에 전달할 수 있습니다. 구성과 일치시킬 값은 String
로 전달된 후 일치시킬 빌드 설정의 유형으로 파싱됩니다.
config_setting(
name = "my_config",
flag_values = {
"//example:favorite_flavor": "MANGO"
}
)
사용자 정의 전환
구성 전환은 빌드 그래프 내에서 구성된 한 타겟에서 다른 타겟으로의 변환을 매핑합니다.
이러한 값을 설정하는 규칙에는 특수 속성이 포함되어야 합니다.
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
)
전환을 추가하면 빌드 그래프의 크기가 매우 쉽게 커질 수 있습니다. 이렇게 하면 이 규칙의 타겟을 만들 수 있는 패키지에 허용 목록이 설정됩니다. 위 코드 블록의 기본값은 모든 것을 허용 목록에 추가합니다. 하지만 규칙을 사용하는 사용자를 제한하려면 속성을 자체 맞춤 허용 목록을 가리키도록 설정하면 됩니다. 전환이 빌드 성능에 미치는 영향을 이해하는 데 도움이 필요하면 bazel-discuss@googlegroups.com에 문의하세요.
정의
전환은 규칙 간의 구성 변경사항을 정의합니다. 예를 들어 '상위와 다른 CPU용으로 종속 항목 컴파일'과 같은 요청은 전환에 의해 처리됩니다.
공식적으로 전환은 입력 구성에서 하나 이상의 출력 구성으로의 함수입니다. 대부분의 전환은 '--cpu=ppc
로 입력 구성을 재정의'와 같이 1:1입니다. 1:2 이상의 전환도 있을 수 있지만 특별한 제한이 적용됩니다.
Starlark에서 전환은 정의 transition()
함수와 구현 함수를 사용하여 규칙과 매우 유사하게 정의됩니다.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return {"//example:favorite_flavor" : "MINT"}
hot_chocolate_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//example:favorite_flavor"]
)
transition()
함수는 구현 함수, 읽을 빌드 설정 집합(inputs
), 쓸 빌드 설정 집합(outputs
)을 사용합니다. 구현 함수에는 settings
및 attr
이라는 두 매개변수가 있습니다. settings
는 inputs
매개변수에서 transition()
에 선언된 모든 설정의 사전 {String
:Object
}입니다.
attr
은 전환이 연결된 규칙의 속성과 값의 딕셔너리입니다. 나가는 가장자리 전환으로 연결되면 이러한 속성의 값은 모두 select() 해결 후 구성됩니다. 수신 에지 전환으로 연결된 경우 attr
에는 선택기를 사용하여 값을 확인하는 속성이 포함되지 않습니다. --foo
의 수신 에지 전환이 속성 bar
을 읽은 다음 --foo
에서 선택하여 속성 bar
을 설정하는 경우 수신 에지 전환이 전환에서 bar
의 잘못된 값을 읽을 수 있습니다.
구현 함수는 적용할 새 빌드 설정 값의 사전 (또는 여러 출력 구성이 있는 전환의 경우 사전 목록)을 반환해야 합니다. 반환된 사전 키 세트에는 전환 함수의 outputs
매개변수에 전달된 빌드 설정 세트가 정확히 포함되어야 합니다. 이는 전환 과정에서 빌드 설정이 실제로 변경되지 않는 경우에도 마찬가지입니다. 원래 값은 반환된 딕셔너리에서 명시적으로 전달되어야 합니다.
1:2 이상의 전환 정의
나가는 가장자리 전환은 단일 입력 구성을 두 개 이상의 출력 구성에 매핑할 수 있습니다. 이는 다중 아키텍처 코드를 번들로 묶는 규칙을 정의하는 데 유용합니다.
1:2 이상의 전환은 전환 구현 함수에서 사전 목록을 반환하여 정의됩니다.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return [
{"//example:favorite_flavor" : "LATTE"},
{"//example:favorite_flavor" : "MOCHA"},
]
coffee_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//example:favorite_flavor"]
)
규칙 구현 함수가 개별 종속 항목을 읽는 데 사용할 수 있는 맞춤 키를 설정할 수도 있습니다.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return {
"Apple deps": {"//command_line_option:cpu": "ppc"},
"Linux deps": {"//command_line_option:cpu": "x86"},
}
multi_arch_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//command_line_option:cpu"]
)
전환 연결
전환은 수신 에지와 발신 에지라는 두 곳에 연결할 수 있습니다. 즉, 규칙은 자체 구성을 전환 (수신 에지 전환)하고 종속 항목의 구성을 전환 (발신 에지 전환)할 수 있습니다.
참고: 현재 Starlark 전환을 네이티브 규칙에 연결할 방법은 없습니다. 이 작업이 필요한 경우 bazel-discuss@googlegroups.com에 문의하여 해결 방법을 알아보세요.
수신 에지 전환
들어오는 가장자리 전환은 rule()
의 cfg
매개변수에 transition
객체(transition()
로 생성됨)를 연결하여 활성화됩니다.
# example/rules.bzl
load("example/transitions:transitions.bzl", "hot_chocolate_transition")
drink_rule = rule(
implementation = _impl,
cfg = hot_chocolate_transition,
...
들어오는 가장자리 전환은 1:1 전환이어야 합니다.
나가는 가장자리 전환
나가는 가장자리 전환은 transition()
로 생성된 transition
객체를 속성의 cfg
매개변수에 연결하여 활성화됩니다.
# example/rules.bzl
load("example/transitions:transitions.bzl", "coffee_transition")
drink_rule = rule(
implementation = _impl,
attrs = { "dep": attr.label(cfg = coffee_transition)}
...
나가는 에지 전환은 1:1 또는 1:2 이상일 수 있습니다.
이러한 키를 읽는 방법은 전환을 사용하여 속성에 액세스하기를 참고하세요.
네이티브 옵션의 전환
Starlark 전환은 옵션 이름에 특수 접두사를 통해 네이티브 빌드 구성 옵션에 대한 읽기 및 쓰기를 선언할 수도 있습니다.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return {"//command_line_option:cpu": "k8"}
cpu_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//command_line_option:cpu"]
지원되지 않는 기본 옵션
Bazel은 "//command_line_option:define"
을 사용하여 --define
에서 전환하는 것을 지원하지 않습니다. 대신 맞춤 빌드 설정을 사용하세요. 일반적으로 빌드 설정을 사용하는 것이 권장되므로 --define
의 새로운 사용은 권장되지 않습니다.
Bazel은 --config
에서의 전환을 지원하지 않습니다. 이는 --config
가 다른 플래그로 확장되는 '확장' 플래그이기 때문입니다.
중요한 점은 --config
에 --spawn_strategy
와 같이 빌드 구성에 영향을 미치지 않는 플래그가 포함될 수 있다는 것입니다. Bazel은 설계상 이러한 플래그를 개별 타겟에 바인딩할 수 없습니다. 즉, 전환에 일관된 방식으로 적용할 방법이 없습니다.
해결 방법으로 전환에서 구성에 포함되는 플래그를 명시적으로 나열할 수 있습니다. 이렇게 하려면 --config
의 확장을 두 곳에서 유지해야 하며 이는 알려진 UI 결함입니다.
여러 빌드 설정 허용 시 전환
여러 값을 허용하는 빌드 설정을 설정할 때 설정 값은 목록으로 설정해야 합니다.
# example/buildsettings/build_settings.bzl
string_flag = rule(
implementation = _impl,
build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "string_flag")
string_flag(name = "roasts", build_setting_default = "medium")
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
# Using a value of just "dark" here will throw an error
return {"//example:roasts" : ["dark"]},
coffee_transition = transition(
implementation = _transition_impl,
inputs = [],
outputs = ["//example:roasts"]
)
무작동 전환
전환에서 {}
, []
또는 None
를 반환하면 모든 설정을 원래 값으로 유지한다는 의미입니다. 이렇게 하면 각 출력을 자체적으로 명시적으로 설정하는 것보다 편리할 수 있습니다.
# example/transitions/transitions.bzl
def _impl(settings, attr):
_ignore = (attr)
if settings["//example:already_chosen"] is True:
return {}
return {
"//example:favorite_flavor": "dark chocolate",
"//example:include_marshmallows": "yes",
"//example:desired_temperature": "38C",
}
hot_chocolate_transition = transition(
implementation = _impl,
inputs = ["//example:already_chosen"],
outputs = [
"//example:favorite_flavor",
"//example:include_marshmallows",
"//example:desired_temperature",
]
)
전환을 사용하여 속성에 액세스
나가는 간선에 전환을 연결할 때(전환이 1:1 전환인지 1:2+ 전환인지와 관계없이) ctx.attr
이 이미 목록이 아닌 경우 목록으로 강제됩니다. 이 목록의 요소 순서는 지정되지 않습니다.
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
return {"//example:favorite_flavor" : "LATTE"},
coffee_transition = transition(
implementation = _transition_impl,
inputs = [],
outputs = ["//example:favorite_flavor"]
)
def _rule_impl(ctx):
# Note: List access even though "dep" is not declared as list
transitioned_dep = ctx.attr.dep[0]
# Note: Access doesn't change, other_deps was already a list
for other_dep in ctx.attr.other_deps:
# ...
coffee_rule = rule(
implementation = _rule_impl,
attrs = {
"dep": attr.label(cfg = coffee_transition)
"other_deps": attr.label_list(cfg = coffee_transition)
})
전환이 1:2+
이고 맞춤 키를 설정하는 경우 ctx.split_attr
를 사용하여 각 키의 개별 종속 항목을 읽을 수 있습니다.
# example/transitions/rules.bzl
def _impl(settings, attr):
_ignore = (settings, attr)
return {
"Apple deps": {"//command_line_option:cpu": "ppc"},
"Linux deps": {"//command_line_option:cpu": "x86"},
}
multi_arch_transition = transition(
implementation = _impl,
inputs = [],
outputs = ["//command_line_option:cpu"]
)
def _rule_impl(ctx):
apple_dep = ctx.split_attr.dep["Apple deps"]
linux_dep = ctx.split_attr.dep["Linux deps"]
# ctx.attr has a list of all deps for all keys. Order is not guaranteed.
all_deps = ctx.attr.dep
multi_arch_rule = rule(
implementation = _rule_impl,
attrs = {
"dep": attr.label(cfg = multi_arch_transition)
})
전체 예는 여기를 참고하세요.
플랫폼 및 도구 체인과의 통합
오늘날 --cpu
및 --crosstool_top
와 같은 많은 네이티브 플래그는 도구 모음 해결과 관련이 있습니다. 향후 이러한 유형의 플래그에 대한 명시적 전환은 타겟 플랫폼에서의 전환으로 대체될 가능성이 높습니다.
메모리 및 성능 고려사항
빌드에 전환(따라서 새로운 구성)을 추가하면 빌드 그래프가 커지고, 빌드 그래프가 덜 이해하기 쉬워지고, 빌드가 느려지는 비용이 발생합니다. 빌드 규칙에서 전환을 사용하는 것을 고려할 때 이러한 비용을 고려하는 것이 좋습니다. 아래는 전환으로 인해 빌드 그래프가 기하급수적으로 증가할 수 있는 방법을 보여주는 예입니다.
잘못된 동작을 하는 빌드: 사례 연구
그림 1. 최상위 타겟과 종속 항목을 보여주는 확장성 그래프
이 그래프는 두 타겟(//pkg:1_0
및 //pkg:1_1
)에 종속된 최상위 타겟 //pkg:app
를 보여줍니다. 이러한 두 타겟은 //pkg:2_0
및 //pkg:2_1
의 두 타겟에 종속됩니다. 두 타겟 모두 //pkg:3_0
및 //pkg:3_1
의 두 타겟에 종속됩니다.
이는 단일 타겟 //pkg:dep
에 모두 종속되는 //pkg:n_0
및 //pkg:n_1
까지 계속됩니다.
//pkg:app
를 빌드하려면 다음 타겟이 필요합니다. \(2n+2\)
//pkg:app
//pkg:dep
- \([1..n]\)의 \(i\) 에 대한
//pkg:i_0
및//pkg:i_1
--//foo:owner=<STRING>
플래그를 구현하고 //pkg:i_b
이 적용된다고 가정해 보겠습니다.
depConfig = myConfig + depConfig.owner="$(myConfig.owner)$(b)"
즉, //pkg:i_b
는 모든 종속 항목의 --owner
이전 값에 b
을 추가합니다.
그러면 다음과 같은 구성된 타겟이 생성됩니다.
//pkg:app //foo:owner=""
//pkg:1_0 //foo:owner=""
//pkg:1_1 //foo:owner=""
//pkg:2_0 (via //pkg:1_0) //foo:owner="0"
//pkg:2_0 (via //pkg:1_1) //foo:owner="1"
//pkg:2_1 (via //pkg:1_0) //foo:owner="0"
//pkg:2_1 (via //pkg:1_1) //foo:owner="1"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_0) //foo:owner="00"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_1) //foo:owner="01"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_0) //foo:owner="10"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_1) //foo:owner="11"
...
//pkg:dep
는 \(2^n\) 구성된 타겟을 생성합니다. config.owner=
\(\{0,1\}\)의 모든 \(b_i\) 에 대해 '\(b_0b_1...b_n\)'
이렇게 하면 빌드 그래프가 타겟 그래프보다 기하급수적으로 커지며 그에 따라 메모리 및 성능 문제가 발생합니다.
TODO: 이러한 문제의 측정 및 완화 전략 추가
추가 자료
빌드 구성 수정에 관한 자세한 내용은 다음을 참고하세요.
- Starlark 빌드 구성
- Bazel 구성 가능성 로드맵
- 엔드 투 엔드 예시의 전체 세트