이 페이지에서는 매크로 사용의 기본사항을 다루며 일반적인 사용 사례, 디버깅, 규칙을 포함합니다.
매크로는 규칙을 인스턴스화할 수 있는 BUILD
파일에서 호출되는 함수입니다.
매크로는 주로 기존 규칙 및 기타 매크로의 캡슐화 및 코드 재사용에 사용됩니다.
매크로에는 두 가지 종류, 즉 이 페이지에서 설명하는 기호형 매크로와 기존 매크로가 있습니다. 가능하면 코드의 명확성을 위해 기호 매크로를 사용하는 것이 좋습니다.
기호 매크로는 유형이 지정된 인수 (매크로가 호출된 위치를 기준으로 문자열을 라벨로 변환)와 생성된 타겟의 공개 상태를 제한하고 지정하는 기능을 제공합니다. 이는 지연 평가 (향후 Bazel 출시에서 추가될 예정)를 수용할 수 있도록 설계되었습니다. 기호 매크로는 Bazel 8에서 기본적으로 사용할 수 있습니다. 이 문서에서 macros
를 언급하는 경우 기호 매크로를 의미합니다.
사용
매크로는 attrs
및 implementation
이라는 두 매개변수를 사용하여 macro()
함수를 호출하여 .bzl
파일에 정의됩니다.
속성
attrs
는 매크로의 인수를 나타내는 속성 유형의 속성 이름 사전을 허용합니다. 두 가지 공통 속성인 이름과 공개 상태는 모든 매크로에 암시적으로 추가되며 attrs에 전달된 사전에 포함되지 않습니다.
# macro/macro.bzl
my_macro = macro(
attrs = {
"deps": attr.label_list(mandatory = True, doc = "The dependencies passed to the inner cc_binary and cc_test targets"),
"create_test": attr.bool(default = False, configurable = False, doc = "If true, creates a test target"),
},
implementation = _my_macro_impl,
)
속성 유형 선언은 매개변수 mandatory
, default
, doc
를 허용합니다. 대부분의 속성 유형은 속성이 select
를 허용하는지 여부를 결정하는 configurable
매개변수도 허용합니다. 속성이 configurable
인 경우 select
가 아닌 값을 구성할 수 없는 select
로 파싱합니다. "foo"
는 select({"//conditions:default": "foo"})
이 됩니다. selects에서 자세히 알아보세요.
구현
implementation
는 매크로의 로직이 포함된 함수를 허용합니다.
구현 함수는 하나 이상의 규칙을 호출하여 타겟을 만드는 경우가 많으며 일반적으로 비공개입니다 (이름 앞에 밑줄이 표시됨). 일반적으로 매크로와 동일한 이름을 사용하지만 앞에 _
이, 뒤에 _impl
이 붙습니다.
속성 참조를 포함하는 단일 인수 (ctx
)를 사용하는 규칙 구현 함수와 달리 매크로 구현 함수는 각 인수에 매개변수를 허용합니다.
# macro/macro.bzl
def _my_macro_impl(name, deps, create_test):
cc_library(
name = name + "_cc_lib",
deps = deps,
)
if create_test:
cc_test(
name = name + "_test",
srcs = ["my_test.cc"],
deps = deps,
)
선언
매크로는 BUILD
파일에서 정의를 로드하고 호출하여 선언됩니다.
# pkg/BUILD
my_macro(
name = "macro_instance",
deps = ["src.cc"] + select(
{
"//config_setting:special": ["special_source.cc"],
"//conditions:default": [],
},
),
create_tests = True,
)
그러면 //pkg:macro_instance_cc_lib
및 //pkg:macro_instance_test
타겟이 생성됩니다.
세부정보
생성된 대상에 대한 이름 지정 규칙
심볼릭 매크로로 생성된 타겟 또는 하위 매크로의 이름은 매크로의 name
매개변수와 일치하거나 name
접두어가 _
(권장), .
또는 -
로 와야 합니다. 예를 들어 my_macro(name = "foo")
는 foo
라는 이름의 파일이나 타겟만 만들거나 foo_
, foo-
또는 foo.
접두사가 있는 파일이나 타겟(예: foo_bar
)만 만들 수 있습니다.
매크로 이름 지정 규칙을 위반하는 타겟 또는 파일은 선언할 수 있지만 빌드할 수 없으며 종속 항목으로 사용할 수 없습니다.
매크로 인스턴스와 동일한 패키지 내에 있는 매크로가 아닌 파일과 타겟은 잠재적인 매크로 타겟 이름과 충돌하는 이름을 가져서는 안 됩니다. 단, 이 배타성은 시행되지 않습니다. Google에서는 이름 지정 스키마를 위반하는 패키지에서 성능이 저하되는 기호 매크로의 성능 개선으로 지연 평가를 구현하고 있습니다.
제한사항
기호 매크로에는 기존 매크로에 비해 몇 가지 추가 제한사항이 있습니다.
기호 매크로
name
인수와visibility
인수를 사용해야 합니다.implementation
함수가 있어야 합니다.- 값을 반환하지 않을 수 있습니다.
args
를 변경할 수 없음- 특수
finalizer
매크로가 아닌 한native.existing_rules()
를 호출하지 않을 수 있습니다. native.package()
를 호출하지 않을 수 있음glob()
을(를) 호출할 수 없습니다.native.environment_group()
를 호출하지 않을 수 있음- 이름이 이름 지정 스키마를 준수하는 타겟을 만들어야 합니다.
- 인수로 선언되거나 전달되지 않은 입력 파일을 참조할 수 없습니다(자세한 내용은 공개 상태 참고).
공개 상태
할 일: 이 섹션 펼치기
타겟 공개 상태
기본적으로 기호화된 매크로에 의해 생성된 타겟은 해당 타겟이 생성된 패키지에 표시됩니다. 또한 visibility
속성을 허용합니다. 이 속성을 사용하면 (visibility
속성을 매크로 호출에서 생성된 타겟에 직접 전달하여) 매크로 호출자에게, (타겟의 공개 범위에서 명시적으로 지정하여) 다른 패키지에 공개 범위를 확장할 수 있습니다.
종속 항목 공개 상태
매크로는 참조하는 파일과 타겟을 볼 수 있어야 합니다. 다음 방법 중 하나로 할 수 있습니다.
- 매크로에
attr
값으로 명시적으로 전달됨
# pkg/BUILD
my_macro(... deps = ["//other_package:my_tool"] )
attr
값의 암시적 기본값
# my_macro:macro.bzl
my_macro = macro(
attrs = {"deps" : attr.label_list(default = ["//other_package:my_tool"])} )
- 매크로 정의에 이미 표시됨
# other_package/BUILD
cc_binary(
name = "my_tool",
visibility = "//my_macro:\\__pkg__",
)
선택
속성이 configurable
인 경우 매크로 구현 함수는 속성 값을 항상 select
값으로 간주합니다. 예를 들어 다음 매크로를 고려해 보세요.
my_macro = macro(
attrs = {"deps": attr.label_list()}, # configurable unless specified otherwise
implementation = _my_macro_impl,
)
my_macro
가 deps = ["//a"]
로 호출되면 _my_macro_impl
가 deps
매개변수가 select({"//conditions:default":
["//a"]})
로 설정된 상태로 호출됩니다.
규칙 대상은 이 변환을 역전하고 사소한 select
를 조건부 값으로 저장합니다. 이 예에서 _my_macro_impl
가 규칙 대상 my_rule(..., deps = deps)
을 선언하면 해당 규칙 대상의 deps
는 ["//a"]
로 저장됩니다.
파이널라이저
규칙 최종 처리기는 BUILD 파일의 문법적 위치와 관계없이 모든 최종 처리기가 아닌 타겟이 정의된 후 패키지 로드의 마지막 단계에서 평가되는 특수한 기호 매크로입니다. 일반적인 기호화된 매크로와 달리 파이널라이저는 기존 매크로와 약간 다르게 동작하는 native.existing_rules()
를 호출할 수 있습니다. 즉, 파이널라이저가 아닌 규칙 타겟 집합만 반환합니다. finalizer는 해당 세트의 상태를 어설션하거나 새 타겟을 정의할 수 있습니다.
finalizer를 선언하려면 finalizer = True
를 사용하여 macro()
를 호출합니다.
def _my_finalizer_impl(name, visibility, tags_filter):
for r in native.existing_rules().values():
for tag in r.get("tags", []):
if tag in tags_filter:
my_test(
name = name + "_" + r["name"] + "_finalizer_test",
deps = [r["name"]],
data = r["srcs"],
...
)
continue
my_finalizer = macro(
attrs = {"tags_filter": attr.string_list(configurable = False)},
implementation = _impl,
finalizer = True,
)
게으름
중요: 지연된 매크로 확장 및 평가를 구현하는 중입니다. 이 기능은 아직 사용할 수 없습니다.
현재 모든 매크로는 BUILD 파일이 로드되는 즉시 평가되므로 비용이 많이 들고 관련 없는 매크로가 있는 패키지의 타겟 성능에 부정적인 영향을 미칠 수 있습니다. 향후 종료자가 아닌 기호 매크로는 빌드에 필요한 경우에만 평가됩니다. 접두사 이름 지정 스키마는 요청된 타겟을 기준으로 Bazel에서 확장할 매크로를 결정하는 데 도움이 됩니다.
이전 문제 해결
다음은 일반적인 이전 문제와 해결 방법입니다.
- 기존 매크로 호출
glob()
glob()
호출을 BUILD 파일 (또는 BUILD 파일에서 호출된 기존 매크로)로 이동하고 label-list 속성을 사용하여 glob()
값을 기호 매크로에 전달합니다.
# BUILD file
my_macro(
...,
deps = glob(...),
)
- 기존 매크로에 유효한 Starlark
attr
유형이 아닌 매개변수가 있습니다.
중첩된 기호 매크로로 최대한 많은 로직을 가져오되 최상위 매크로는 기존 매크로로 유지합니다.
- 기존 매크로가 이름 지정 스키마를 위반하는 타겟을 만드는 규칙을 호출함
괜찮습니다. '오해의 소지가 있는' 타겟에 의존하지 마세요. 이름 지정 검사는 자동으로 무시됩니다.