이 페이지에서는 aspects의 기본 사항과 이점을 설명하고 간단한 고급 예시를 제공합니다.
측면을 통해 추가 정보와 작업으로 빌드 종속 항목 그래프를 보강할 수 있습니다. 다음과 같은 측면이 유용할 수 있습니다.
- Bazel을 통합하는 IDE는 다양한 측면을 사용하여 프로젝트에 관한 정보를 수집할 수 있습니다.
- 코드 생성 도구는 다양한 측면을 대상에 구애받지 않는 방식으로 입력에서 실행할 수 있습니다. 예를 들어
BUILD
파일은 protobuf 라이브러리 정의의 계층 구조를 지정할 수 있고 언어별 규칙은 측면을 사용하여 특정 언어의 protobuf 지원 코드를 생성하는 작업을 연결할 수 있습니다.
가로세로 기본사항
BUILD
파일은 프로젝트의 소스 코드에 관한 설명을 제공합니다. 즉, 프로젝트의 일부인 소스 파일, 이러한 파일에서 빌드해야 하는 아티팩트 (타겟), 파일 간의 종속 항목 등을 알 수 있습니다. Bazel은 이 정보를 사용하여 빌드를 실행합니다. 즉, 아티팩트 (예: 컴파일러 또는 링커 실행)를 생성하는 데 필요한 일련의 작업을 파악하고 이러한 작업을 실행합니다. Bazel은 대상 사이에 종속 항목 그래프를 구성하고 이 그래프를 방문하여 이러한 작업을 수집하여 이를 수행합니다.
다음 BUILD
파일을 살펴보세요.
java_library(name = 'W', ...)
java_library(name = 'Y', deps = [':W'], ...)
java_library(name = 'Z', deps = [':W'], ...)
java_library(name = 'Q', ...)
java_library(name = 'T', deps = [':Q'], ...)
java_library(name = 'X', deps = [':Y',':Z'], runtime_deps = [':T'], ...)
이 BUILD
파일은 다음 그림과 같이 종속 항목 그래프를 정의합니다.
그림 1. BUILD
파일 종속 항목 그래프
Bazel은 위의 예시에 있는 모든 타겟에 해당하는 rule (이 경우 'java_library')의 구현 함수를 호출하여 이 종속 항목 그래프를 분석합니다. 규칙 구현 함수는 .jar
파일과 같은 아티팩트를 빌드하고 해당 아티팩트의 위치 및 이름과 같은 정보를 제공업체에서 이러한 타겟의 역방향 종속 항목에 전달하는 작업을 생성합니다.
측면은 규칙을 생성하고 제공자를 반환하는 구현 함수가 있다는 점에서 규칙과 유사합니다. 그러나 종속 항목 그래프가 빌드되는 방식에서 문제가 발생합니다. 관점에는 구현 및 전파되는 모든 속성 목록이 있습니다. 이름이 'deps'인 속성을 따라 전파되는 A라는 측면을 생각해 보세요. 이 측면은 대상 X에 적용되어 가로세로 애플리케이션 노드 A(X)를 생성할 수 있습니다. 적용 중에 A 요소는 X가 'deps' 속성 (A의 전파 목록에 있는 모든 속성)에서 참조하는 모든 대상에 재귀적으로 적용됩니다.
따라서, 대상 A에 가로세로 A를 적용하는 단일 작업은 다음 그림에 표시된 타겟의 원래 종속 항목 그래프의 '섀도 그래프'를 생성합니다.
그림 2. 다양한 측면으로 그래프를 빌드합니다.
그림자가 있는 유일한 가장자리는 전파 집합의 속성을 따르는 가장자리이므로 이 예에서는 runtime_deps
가장자리가 그림자로 표시되지 않습니다. 그런 다음 원본 그래프의 노드에서 규칙 구현이 호출되는 방식과 유사하게, 섀도우 그래프의 모든 노드에서 가로세로 구현 함수가 호출됩니다.
간단한 예시
이 예에서는 deps
속성이 있는 모든 규칙 및 모든 종속 항목의 소스 파일을 재귀적으로 출력하는 방법을 보여줍니다. 가로세로 구현, 가로세로 정의, Bazel 명령줄에서 가로세로를 호출하는 방법을 보여줍니다.
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files that make up the sources and
# print their paths.
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
print(f.path)
return []
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
예를 들어 각각의 부분으로 나누어 살펴보겠습니다.
가로세로 정의
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
가로세로 정의는 규칙 정의와 비슷하며 aspect
함수를 사용하여 정의됩니다.
규칙과 마찬가지로 가로세로 기능에는 구현 함수(이 경우에는 _print_aspect_impl
)가 있습니다.
attr_aspects
는 가로세로가 적용되는 규칙 속성 목록입니다.
이 경우 가로세로가 적용된 규칙의 deps
속성에 따라 가로세로가 적용됩니다.
attr_aspects
의 또 다른 일반적인 인수는 관점을 규칙의 모든 속성에 전파하는 ['*']
입니다.
가로세로 구현
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files that make up the sources and
# print their paths.
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
print(f.path)
return []
가로세로 구현 함수는 규칙 구현 함수와 유사합니다. 이들은 제공업체를 반환하고, 작업을 생성하고, 두 가지 인수를 받을 수 있습니다.
구현 함수는 ctx.rule.attr
를 통해 대상 규칙의 속성에 액세스할 수 있습니다. 이 메서드는 target
인수를 통해 적용되는 대상에서 제공하는 제공자를 검사할 수 있습니다.
제공업체 목록을 반환하려면 다양한 항목이 필요합니다. 이 예에서 가로세로 항목은 아무것도 제공하지 않으므로 빈 목록을 반환합니다.
명령줄을 사용하여 가로세로 호출
가로세로 비율을 적용하는 가장 간단한 방법은 명령줄에서 --aspects
인수를 사용하는 것입니다. 위 측면이 print.bzl
라는 파일에 정의되었다고 가정해 보겠습니다.
bazel build //MyExample:example --aspects print.bzl%print_aspect
print_aspect
를 대상 example
및 deps
속성을 통해 재귀적으로 액세스할 수 있는 모든 대상 규칙에 적용합니다.
--aspects
플래그는 <extension file label>%<aspect top-level name>
형식의 가로세로 사양인 인수를 하나 사용합니다.
고급 예시
다음 예에서는 타겟의 파일을 계산하는 타겟 규칙의 요소를 사용하여 확장자별로 필터링할 수 있음을 보여줍니다. 제공자를 사용하여 값을 반환하는 방법, 매개변수를 사용하여 인수를 가로세로 구현에 전달하는 방법, 규칙에서 가로세로 비율을 호출하는 방법을 보여줍니다.
file_count.bzl
파일:
FileCountInfo = provider(
fields = {
'count' : 'number of files'
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
return [FileCountInfo(count = count)]
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
def _file_count_rule_impl(ctx):
for dep in ctx.attr.deps:
print(dep[FileCountInfo].count)
file_count_rule = rule(
implementation = _file_count_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [file_count_aspect]),
'extension' : attr.string(default = '*'),
},
)
BUILD.bazel
파일:
load('//:file_count.bzl', 'file_count_rule')
cc_library(
name = 'lib',
srcs = [
'lib.h',
'lib.cc',
],
)
cc_binary(
name = 'app',
srcs = [
'app.h',
'app.cc',
'main.cc',
],
deps = ['lib'],
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
가로세로 정의
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
이 예는 가로세로가 deps
속성을 통해 어떻게 전파되는지 보여줍니다.
attrs
는 한 가지 측면의 속성을 정의합니다. 공개 가로세로 속성은 string
유형이며 매개변수라고 합니다. 매개변수에는 values
속성이 지정되어 있어야 합니다. 이 예시에는 '*
', 'h
' 또는 'cc
'을 값으로 사용할 수 있는 extension
라는 매개변수가 있습니다.
가로세로의 매개변수 값은 가로세로를 요청하는 규칙과 동일한 이름의 문자열 속성에서 가져옵니다 (file_count_rule
의 정의 참고). 매개변수를 갖는 가로세로는 매개변수를 정의하는 문법이 없으므로 명령줄을 통해 사용할 수 없습니다.
또한 가로세로 유형은 label
또는 label_list
유형의 비공개 속성을 가질 수 있습니다. 비공개 라벨 속성은 측면에서 생성된 작업에 필요한 도구 또는 라이브러리의 종속 항목을 지정하는 데 사용할 수 있습니다. 이 예에 정의된 비공개 속성은 없지만 다음 코드 스니펫은 도구를 가로세로로 전달하는 방법을 보여줍니다.
...
attrs = {
'_protoc' : attr.label(
default = Label('//tools:protoc'),
executable = True,
cfg = "exec"
)
}
...
가로세로 구현
FileCountInfo = provider(
fields = {
'count' : 'number of files'
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
return [FileCountInfo(count = count)]
규칙 구현 함수와 마찬가지로 가로세로 구현 함수는 종속 항목에 액세스할 수 있는 제공자 구조체를 반환합니다.
이 예에서 FileCountInfo
는 count
필드가 하나 있는 제공자로 정의됩니다. fields
속성을 사용하여 제공자의 필드를 명시적으로 정의하는 것이 좋습니다.
가로세로 애플리케이션 A(X)의 제공자 집합은 대상 X에 대한 규칙의 구현에서 그리고 가로세로 A의 구현에서 비롯된 제공자의 합집합입니다. 규칙 구현이 전파되는 제공자는 측면이 적용되기 전에 생성되고 고정되며 측면에서 수정할 수 없습니다. 타겟과 이에 적용된 요소가 각각 같은 유형의 제공자를 제공하는 경우 오류가 발생합니다. 단, 규칙 및 가로세로가 다른 출력 그룹을 지정하는 한 병합된 OutputGroupInfo
와 가로세로에서 가져온 InstrumentedFilesInfo
는 예외입니다. 즉, 가로세로 구현은 DefaultInfo
를 반환하지 않을 수 있습니다.
매개변수와 비공개 속성은 ctx
의 속성에 전달됩니다. 이 예에서는 extension
매개변수를 참조하고 계산할 파일을 결정합니다.
재방문 제공업체의 경우 가로세로가 전파되는 속성 값 (attr_aspects
목록에서 가져옴)이 가로세로를 적용한 결과로 대체됩니다. 예를 들어 타겟 X의 종속 항목에 Y와 Z가 있는 경우 A(X)의 ctx.rule.attr.deps
는 [A(Y), A(Z)]가 됩니다.
이 예에서 ctx.rule.attr.deps
는 가로세로가 적용된 원래 타겟의 'Deps'에 가로세로를 적용한 결과인 타겟 객체입니다.
이 예에서는 측면이 타겟 종속 항목에서 FileCountInfo
제공자에 액세스하여 총 전이 파일 수를 누적합니다.
규칙에서 측면 호출
def _file_count_rule_impl(ctx):
for dep in ctx.attr.deps:
print(dep[FileCountInfo].count)
file_count_rule = rule(
implementation = _file_count_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [file_count_aspect]),
'extension' : attr.string(default = '*'),
},
)
규칙 구현은 ctx.attr.deps
를 통해 FileCountInfo
에 액세스하는 방법을 보여줍니다.
규칙 정의에서 매개변수(extension
)를 정의하고 기본값(*
)을 지정하는 방법을 보여줍니다. 가로세로 정의에서 매개변수에 적용된 제한사항으로 인해 'cc
', 'h
', '*
'가 아닌 기본값이 있으면 오류가 발생합니다.
대상 규칙을 통한 가로세로 호출
load('//:file_count.bzl', 'file_count_rule')
cc_binary(
name = 'app',
...
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
규칙을 통해 extension
매개변수를 가로세로로 전달하는 방법을 보여줍니다. 규칙 구현에서 extension
매개변수의 기본값이 있으므로 extension
은 선택적 매개변수로 간주됩니다.
file_count
타겟이 빌드되면 가로세로 요소가 자체적으로 평가되고 모든 타겟이 deps
를 통해 반복적으로 액세스 가능합니다.