특성

문제 신고하기 소스 보기

이 페이지에서는 측면 사용의 기본사항과 이점을 설명하고 간단한 예와 고급 예를 제공합니다.

관점을 사용하면 추가 정보와 작업으로 빌드 종속 항목 그래프를 보강할 수 있습니다. 관점이 유용할 수 있는 일반적인 시나리오는 다음과 같습니다.

  • 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은 위 예의 모든 대상에 상응하는 규칙 (이 경우 'java_library')의 구현 함수를 호출하여 이 종속 항목 그래프를 분석합니다. 규칙 구현 함수는 .jar 파일과 같은 아티팩트를 빌드하고 이러한 아티팩트의 위치 및 이름과 같은 정보를 제공자에 있는 이러한 타겟의 역 종속 항목으로 전달하는 작업을 생성합니다.

관점은 작업을 생성하고 제공자를 반환하는 구현 함수가 있다는 점에서 규칙과 유사합니다. 그러나 이들의 힘은 종속 항목 그래프가 빌드된 방식에서 비롯됩니다. 관점에는 구현과 함께 전파되는 모든 속성의 목록이 있습니다. 'deps'라는 속성을 따라 전파되는 관점 A를 생각해 보세요. 이 관점은 타겟 X에 적용하여 관점 애플리케이션 노드 A(X)를 생성할 수 있습니다. 적용되는 동안 측면 A는 X가 'deps' 속성 (A의 전파 목록에 있는 모든 속성)에서 참조하는 모든 타겟에 재귀적으로 적용됩니다.

따라서 다음 그림과 같이 타겟 X에 관점 A를 적용하는 단일 행동은 타겟의 원래 종속 항목 그래프의 '섀도 그래프'를 생성합니다.

Aspect로 그래프 빌드

그림 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 []

관점 구현 함수는 규칙 구현 함수와 비슷합니다. 제공자를 반환하고 작업을 생성할 수 있으며 다음 두 인수를 사용합니다.

  • target: 관점이 적용되는 타겟입니다.
  • ctx: 속성에 액세스하고 출력과 작업을 생성하는 데 사용할 수 있는 ctx 객체입니다.

구현 함수는 ctx.rule.attr를 통해 대상 규칙의 속성에 액세스할 수 있습니다. 적용되는 타겟에서 제공하는 제공자를 검사할 수 있습니다 (target 인수를 통해).

제공업체 목록을 반환하려면 관점이 필요합니다. 이 예에서 관점은 아무것도 제공하지 않으므로 빈 목록을 반환합니다.

명령줄을 사용하여 관점 호출

관점을 적용하는 가장 간단한 방법은 명령줄에서 --aspects 인수를 사용하는 것입니다. 위의 관점이 print.bzl라는 파일에 정의되어 있다고 가정합니다.

bazel build //MyExample:example --aspects print.bzl%print_aspect

대상 exampledeps 속성을 통해 재귀적으로 액세스할 수 있는 모든 대상 규칙에 print_aspect를 적용합니다.

--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는 관점의 속성 집합을 정의합니다. 공개 관점 속성은 매개변수를 정의하며 bool, int 또는 string 유형이어야 합니다. 규칙 전파 관점의 경우 intstring 매개변수에 values가 지정되어 있어야 합니다. 이 예시에는 '*', 'h' 또는 'cc' 값을 값으로 가질 수 있는 extension라는 매개변수가 있습니다.

규칙 전파 측면의 경우 이름과 유형이 동일한 규칙 속성을 사용하여 관점을 요청하는 규칙에서 매개변수 값을 가져옵니다. file_count_rule의 정의를 참고하세요.

명령줄 측면에서는 --aspects_parameters 플래그를 사용하여 매개변수 값을 전달할 수 있습니다. intstring 매개변수의 values 제한은 생략될 수 있습니다.

관점은 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)]

규칙 구현 함수와 마찬가지로 관점 구현 함수는 종속 항목에 액세스할 수 있는 제공자의 구조체를 반환합니다.

이 예시에서 FileCountInfocount 필드가 하나인 제공업체로 정의됩니다. fields 속성을 사용하여 제공업체의 필드를 명시적으로 정의하는 것이 좋습니다.

관점 애플리케이션 A(X)의 제공자 집합은 타겟 X의 규칙 구현과 관점 A의 구현에서 비롯된 제공자의 합집합입니다. 규칙 구현이 전파하는 제공자는 관점이 적용되기 전에 생성되고 고정되며, 어떤 측면에서든 수정할 수 없습니다. 타겟과 타겟에 적용되는 관점이 각각 동일한 유형의 제공자를 제공하면 오류입니다. 단, OutputGroupInfo(규칙과 관점이 다른 출력 그룹을 지정하는 한 병합됨) 및 InstrumentedFilesInfo(항목에서 가져옴)는 예외입니다. 즉, 관점 구현은 DefaultInfo를 반환하지 않습니다.

매개변수와 비공개 속성은 ctx의 속성으로 전달됩니다. 이 예에서는 extension 매개변수를 참조하고 계산할 파일을 결정합니다.

반환하는 제공자의 경우 attr_aspects 목록에서 관점이 전파되는 속성 값은 관점을 적용한 결과로 대체됩니다. 예를 들어 타겟 X의 dps에 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를 통해 재귀적으로 액세스할 수 있습니다.

참조