규칙

<ph type="x-smartling-placeholder"></ph> 문제 신고 소스 보기 1박 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

규칙은 Bazel이 수행하는 일련의 작업을 정의합니다. 입력을 사용하여 출력 세트를 생성하며, 이는 providers 규칙의 구현 함수. 예를 들어, C++ 바이너리 규칙은 다음과 같을 수 있습니다.

  1. .cpp 소스 파일 (입력) 집합을 가져옵니다.
  2. 소스 파일에서 g++를 실행합니다 (작업).
  3. 실행 가능한 출력 및 기타 파일과 함께 DefaultInfo 제공자를 반환합니다. 런타임 시 사용할 수 있게 해야 합니다
  4. 다음에서 수집된 C++ 관련 정보가 있는 CcInfo 제공자를 반환합니다. 타겟과 그 종속 항목이 포함됩니다

Bazel의 관점에서 볼 때 g++ 및 표준 C++ 라이브러리도 입력입니다. 추가할 수 있습니다. 규칙 작성자는 사용자가 제공한 특성뿐 아니라 실행하는 데 필요한 모든 도구와 라이브러리를 지정할 수 있습니다.

규칙을 만들거나 수정하기 전에 Bazel의 빌드 단계에서 설명합니다. 이 세 가지 개념을 각 단계 (로드, 분석, 실행)의 한 단계를 거칩니다. 또한 규칙과 매크로의 차이를 이해하기 위해 매크로에 대해 매크로가 포함되어 있습니다. 시작하려면 먼저 규칙 튜토리얼을 검토합니다. 그런 다음 이 페이지를 참고하시기 바랍니다.

Bazel 자체에 몇 가지 규칙이 내장되어 있습니다. 이러한 기본 규칙의 예시는 다음과 같습니다. cc_libraryjava_binary는 특정 언어에 대한 핵심 지원을 제공합니다. 자체 규칙을 정의하여 언어 및 도구에 대한 유사한 지원을 추가할 수 있습니다. Bazel에서 지원하지 않는 API를 사용할 수 있습니다

Bazel은 Python용 확장 모델을 사용하여 Starlark 언어 이러한 규칙은 .bzl 파일로 작성되며 BUILD 파일에서 직접 로드할 수 있습니다.

자체 규칙을 정의할 때는 규칙이 지원하는 속성과 출력을 생성하는 방법을 배우게 됩니다.

규칙의 implementation 함수는 분석 단계입니다. 이 함수는 외부 명령어인 대신 사용될 작업을 등록합니다. 규칙의 출력을 빌드하기 위해 할 수 있습니다

규칙 생성

.bzl 파일에서 rule 함수를 사용하여 새 규칙 결과를 전역 변수에 저장합니다. rule 호출은 속성구현 함수:

example_library = rule(
    implementation = _example_library_impl,
    attrs = {
        "deps": attr.label_list(),
        ...
    },
)

이는 example_library이라는 규칙의 종류를 정의합니다.

rule 호출은 규칙이 executable 출력 (executable=True 포함) 또는 구체적으로 테스트 실행 파일 (test=True 사용) 후자의 경우 규칙은 테스트 규칙이고 규칙의 이름은 _test(으)로 끝나야 합니다.

타겟 인스턴스화

규칙은 BUILD 파일에서 로드하고 호출할 수 있습니다.

load('//some/pkg:rules.bzl', 'example_library')

example_library(
    name = "example_target",
    deps = [":another_target"],
    ...
)

빌드 규칙을 호출할 때마다 값을 반환하지는 않지만 정의를 정의하는 부작용이 있습니다. 있습니다. 이를 규칙 인스턴스화라고 합니다. 이 속성은 새 타겟과 타겟의 속성 값을 업데이트합니다.

규칙은 Starlark 함수에서 호출하여 .bzl 파일에 로드할 수도 있습니다. 규칙을 호출하는 Starlark 함수를 Starlark 매크로라고 합니다. Starlark 매크로는 궁극적으로 BUILD 파일에서 호출되어야 하며 BUILD인 경우 로드 단계 중에 호출됩니다. 파일이 대상을 인스턴스화하도록 평가됩니다.

속성

속성은 규칙 인수입니다. 속성은 대상의 구현 또는 종속 항목 그래프를 생성합니다.

규칙별 속성(예: srcs 또는 deps)은 지도를 전달하여 정의됩니다. 속성 이름에서 스키마로 변경(attr을(를) 사용하여 생성) 모듈)을 ruleattrs 매개변수에 추가합니다. 일반적인 속성: namevisibility는 모든 규칙에 암시적으로 추가됩니다. 추가 속성은 암시적으로 실행 규칙 및 테스트 규칙을 구체적으로 살펴보겠습니다 속성 전달된 사전에 포함될 수 없는 규칙에 암시적으로 추가된 경우 attrs

종속 항목 속성

소스 코드를 처리하는 규칙은 일반적으로 다음 속성을 정의하여 다양한 종속 항목 유형:

  • srcs는 대상의 작업으로 처리되는 소스 파일을 지정합니다. 일반적으로 속성 스키마는 정렬에 예상되는 파일 확장자를 지정합니다. 소스 파일의 요약본을 제공합니다. 헤더 파일이 있는 언어 규칙 일반적으로 hdrs 알게 되었습니다.
  • deps는 타겟의 코드 종속 항목을 지정합니다. 속성 스키마는 이러한 종속 항목이 제공해야 하는 제공자를 지정합니다. ( 예를 들어 cc_libraryCcInfo를 제공합니다.)
  • data는 런타임에 모든 실행 파일이 사용할 수 있도록 할 파일을 지정합니다. 타겟에 따라 다릅니다 그러면 임의의 파일이 지정합니다.
example_library = rule(
    implementation = _example_library_impl,
    attrs = {
        "srcs": attr.label_list(allow_files = [".example"]),
        "hdrs": attr.label_list(allow_files = [".header"]),
        "deps": attr.label_list(providers = [ExampleInfo]),
        "data": attr.label_list(allow_files = True),
        ...
    },
)

다음은 종속 항목 속성의 예입니다. PersistentVolumeClaim을 입력 라벨( attr.label_list님, attr.label 또는 attr.label_keyed_string_dict) 특정 유형의 종속 항목을 대상과 라벨 (또는 해당하는 Label 객체)이 정의할 수 있습니다 이러한 라벨의 저장소 및 경로 확인됨 타겟의 상대적 비율을 나타냅니다

example_library(
    name = "my_target",
    deps = [":other_target"],
)

example_library(
    name = "other_target",
    ...
)

이 예에서 other_targetmy_target의 종속 항목이므로 other_target가 먼저 분석됩니다. 인코더-디코더에 주기가 있으면 대상의 종속 항목 그래프

비공개 속성 및 암시적 종속 항목

기본값이 있는 종속 항목 속성은 암시적 종속 항목을 생성합니다. 그것은 대상 그래프의 일부이기 때문에 암시적인 BUILD 파일에서 지정할 수 있습니다. 암시적 종속성은 컨테이너 이미지를 하드코딩하는 데 도구 (예: 빌드 시간 종속 항목, 대부분의 경우 사용자는 무엇을 지정할지를 지정하는 데 관심이 없기 때문에 사용할 수 있습니다. 규칙의 구현 함수 내에서 사용할 수 있습니다

사용자가 다음 작업을 하도록 허용하지 않고 암시적 종속 항목을 제공하려는 경우 재정의하려면 이름을 지정하여 속성을 private으로 만들 수 있습니다. 밑줄 (_)로 시작하는 단어입니다. 비공개 속성에는 기본값이 있어야 합니다. 값으로 사용됩니다. 일반적으로 암시적 전달을 위해 비공개 속성을 사용하는 것은 종속 항목이 포함됩니다

example_library = rule(
    implementation = _example_library_impl,
    attrs = {
        ...
        "_compiler": attr.label(
            default = Label("//tools:example_compiler"),
            allow_single_file = True,
            executable = True,
            cfg = "exec",
        ),
    },
)

이 예에서는 example_library 유형의 모든 타겟에 암시적 컴파일러 //tools:example_compiler에 종속되지 않습니다. 이렇게 하면 example_library의 구현 함수: 사용자가 라벨을 입력으로 전달하지 않았더라도 마찬가지입니다. 이후 _compiler는 비공개 속성으로, ctx.attr._compiler 뒤에 옵니다. 이 규칙의 모든 대상에서 항상 //tools:example_compiler을(를) 가리킵니다. 있습니다. 또는 다음과 같이 속성 이름을 compiler로 지정할 수 있습니다. 기본값을 유지합니다. 이렇게 하면 사용자가 필요한 경우 다른 컴파일러를 제공하지만 컴파일러의 라벨을 지정합니다.

암시적 종속 항목은 일반적으로 동일한 저장소를 규칙 구현으로 사용합니다. 도구의 출처가 실행 플랫폼 또는 다른 저장소인 경우 도구 모음에서 해당 도구를 가져와야 합니다.

출력 속성

출력 속성(예: attr.outputattr.output_list인 경우 생성합니다. 이는 종속 항목 속성과는 두 가지 측면에서 다릅니다.

  • 정의된 타겟을 참조하는 대신 출력 파일 타겟을 정의합니다. 확인할 수 있습니다
  • 출력 파일 대상은 그 반대의 경우도 마찬가지입니다.

일반적으로 출력 속성은 규칙이 출력을 생성해야 하는 경우에만 사용됩니다. 대상 이름을 기반으로 할 수 없는 사용자 정의 이름이 있습니다. 규칙에 출력 속성 하나는 일반적으로 out 또는 outs로 명명됩니다.

출력 속성은 사전 선언된 출력을 만드는 데 선호되는 방법이며, 구체적으로 설명하거나 요청합니다.

구현 함수

모든 규칙에는 implementation 함수가 필요합니다. 이러한 함수는 분석 단계에서 엄격하게 처리하여 로드 단계에서 생성된 표적의 그래프를 작업입니다. 따라서 구현 함수는 실제로 파일을 읽거나 쓸 수 없습니다.

규칙 구현 함수는 일반적으로 비공개입니다. 밑줄)을 입력합니다. 일반적으로 규칙과 동일한 이름이 지정되지만 접미사가 붙습니다. _impl를 사용합니다.

구현 함수는 정확히 하나의 매개변수( 규칙 컨텍스트로, 일반적으로 ctx이라고 이름이 지정됩니다. 이 함수는 제공업체와는 다릅니다.

대상

종속 항목은 분석 시점에 Target로 표시됩니다. 객체입니다. 이러한 객체에는 제공업체가 타겟의 구현 함수가 실행되었습니다.

ctx.attr에는 각 종속 항목 속성: 각 직접 객체를 나타내는 Target 객체를 포함합니다. 해당 속성을 통해 종속됩니다. label_list 속성의 경우 Targets label 속성의 경우 단일 Target 또는 None입니다.

제공자 객체의 목록은 타겟의 구현 함수에 의해 반환됩니다.

return [ExampleInfo(headers = depset(...))]

이러한 항목은 색인 표기법 ([])을 사용하여 액세스할 수 있으며 제공자 유형은 다음과 같습니다. 생성합니다. 이는 Starlark에서 정의된 커스텀 제공자일 수 있습니다. Starlark로 제공되는 네이티브 규칙용 제공업체 전역 변수입니다

예를 들어 규칙이 hdrs 속성을 통해 헤더 파일을 가져와 그 내용을 표적과 그 소비자의 컴파일 작업에 연결하면 다음과 같이 수집합니다.

def _example_library_impl(ctx):
    ...
    transitive_headers = [hdr[ExampleInfo].headers for hdr in ctx.attr.hdrs]

struct가 대상의 구현 함수를 구현합니다.

return struct(example_info = struct(headers = depset(...)))

Target 객체의 해당 필드에서 제공자를 가져올 수 있습니다.

transitive_headers = [hdr.example_info.headers for hdr in ctx.attr.hdrs]

이 스타일은 사용하지 않는 것이 좋으며, 규칙은 이전하지 않았을 때

파일

파일은 File 객체로 표현됩니다. Bazel은 파일 I/O를 수행하지만 이러한 객체는 파일 콘텐츠를 직접 읽거나 쓸 수 있습니다. 대신 작업을 내보내는 함수 (ctx.actions 참고)를 사용하여 액션 그래프입니다.

File은 소스 파일이거나 생성된 파일일 수 있습니다. 생성된 각 파일은 정확히 한 작업의 출력이어야 합니다. 소스 파일은 실행할 수 있습니다

각 종속 항목 속성에 대해 ctx.files에는 모든 출력의 기본 출력 목록이 포함되어 있습니다. 종속 항목을 호출합니다.

def _example_library_impl(ctx):
    ...
    headers = depset(ctx.files.hdrs, transitive=transitive_headers)
    srcs = ctx.files.srcs
    ...

ctx.file에는 다음 표현식에 대한 단일 File 또는 None가 포함됩니다. 사양에서 allow_single_file=True를 설정한 종속 항목 속성입니다. ctx.executablectx.file와 동일하게 동작하지만 사양이 executable=True로 설정된 종속 항목 속성의 필드가 포함됩니다.

출력 선언

분석 단계에서는 규칙의 구현 함수가 출력을 생성할 수 있습니다. 로드 단계에서 모든 라벨을 알아야 하므로 출력에 라벨이 없습니다. 출력의 File 객체는 다음을 사용하여 만들 수 있습니다. ctx.actions.declare_filectx.actions.declare_directory입니다. 보통 출력 이름은 대상 이름을 기반으로 하며 ctx.label.name:

def _example_library_impl(ctx):
  ...
  output_file = ctx.actions.declare_file(ctx.label.name + ".output")
  ...

사전 선언된 출력(예: 출력 속성, File 객체를 대신 가져올 수 있음 ctx.outputs의 해당 필드에서 가져옵니다.

작업

작업은 입력 세트에서 출력 세트를 생성하는 방법을 설명합니다. 'hello.c에서 gcc를 실행하고 hello.o 가져오기'를 예로 들 수 있습니다. 작업이 생성되면 Bazel은 명령어를 즉시 실행하지는 않습니다 종속 항목 그래프에 등록하고 한 작업이 다른 작업의 출력에 종속될 수 있기 때문입니다. 예를 들어 C에서 컴파일러는 컴파일러 이후에 호출해야 합니다.

작업을 생성하는 범용 함수는 ctx.actions:

ctx.actions.args를 사용하면 작업의 인수를 축적할 수 있습니다. 다음 시점까지는 depset를 평평하게 하지 않습니다. 실행 시간:

def _example_library_impl(ctx):
    ...

    transitive_headers = [dep[ExampleInfo].headers for dep in ctx.attr.deps]
    headers = depset(ctx.files.hdrs, transitive=transitive_headers)
    srcs = ctx.files.srcs
    inputs = depset(srcs, transitive=[headers])
    output_file = ctx.actions.declare_file(ctx.label.name + ".output")

    args = ctx.actions.args()
    args.add_joined("-h", headers, join_with=",")
    args.add_joined("-s", srcs, join_with=",")
    args.add("-o", output_file)

    ctx.actions.run(
        mnemonic = "ExampleCompile",
        executable = ctx.executable._compiler,
        arguments = [args],
        inputs = inputs,
        outputs = [output_file],
    )
    ...

작업은 입력 파일의 목록 또는 depset를 취하여 출력 파일도 포함됩니다. 입력 및 출력 파일 세트는 분석 단계에 있습니다. 이 값은 속성을 포함하지만 확인할 수 있습니다. 예를 들어 작업에서 unzip 명령어를 실행하면 는 압축 풀기를 실행하기 전에 팽창될 것으로 예상되는 파일을 지정해야 합니다. 내부적으로 가변적인 수의 파일을 생성하는 작업은 이러한 파일을 단일 파일 (예: zip, tar 또는 기타 보관 파일 형식)

작업은 모든 입력을 나열해야 합니다. 사용되지 않는 입력을 나열하는 것은 허용되지만 비효율적입니다

작업은 모든 출력을 생성해야 합니다. 다른 파일을 작성할 수도 있지만 출력에 없는 것은 소비자가 사용할 수 없습니다. 선언된 모든 출력 어떤 작업으로 작성해야 합니다.

작업은 순수 함수와 비슷합니다. 즉, 함수와 컴퓨터 정보, 사용자 이름, 시계, 네트워크 또는 I/O 장치 (입력 읽기 및 출력 쓰기 제외)에 사용합니다. 이것은 출력이 캐시되고 재사용되기 때문에 중요합니다.

종속 항목은 Bazel이 해결하여 실행할 작업을 결정합니다. 실행됩니다 종속 항목 그래프에 주기가 있으면 오류입니다. 생성 중 어떤 작업이 실행될지를 보장하지 않으며, 그 결과는 다음에 따라 출력이 빌드에 필요합니다

제공업체

제공자는 규칙이 실행 중인 다른 규칙에 노출하는 있습니다. 이 데이터에는 전달할 출력 파일, 라이브러리, 매개변수가 포함될 수 있습니다. 툴의 명령줄 또는 표적의 소비자가 알아야 하는 다른 것에 대한 공격 정의합니다.

규칙의 구현 함수는 인스턴스화된 타겟의 직접적인 종속 항목이기 때문에 규칙은 대상의 종속 항목이 알고 있어야 하는 대상의 종속 항목 정보를 일반적으로 이를 depset에 누적하여 생성합니다.

대상의 제공자는 다음에서 반환한 Provider 객체 목록으로 지정됩니다. 구현 함수입니다.

기존 구현 함수를 다음과 같이 기존 스타일로 작성할 수도 있습니다. 구현 함수는 현재 실행 중인 함수 목록의 대신 struct을 provider 객체입니다. 이 스타일은 사용하지 않는 것이 좋으며, 규칙은 이전하지 않았을 때

기본 출력

대상의 기본 출력은 다음과 같은 경우 기본적으로 요청되는 출력입니다. 타겟이 명령줄에서 빌드하도록 요청됩니다 예를 들어 java_library 타겟 //pkg:foo에는 foo.jar가 기본 출력으로 있으므로 bazel build //pkg:foo 명령어로 빌드됩니다.

기본 출력은 다음의 files 매개변수로 지정됩니다. DefaultInfo:

def _example_library_impl(ctx):
    ...
    return [
        DefaultInfo(files = depset([output_file]), ...),
        ...
    ]

규칙 구현이나 files에서 DefaultInfo가 반환되지 않는 경우 매개변수가 지정되지 않은 경우 DefaultInfo.files의 기본값은 모두입니다. 사전 선언된 출력 (일반적으로 출력 속성)을 참조하세요.

작업을 실행하는 규칙은 기본 출력을 제공해야 합니다. 직접 사용되지 않을 것으로 예상됩니다. 그래프에 없는 액션은 요청된 출력이 프루닝됩니다 출력이 대상의 소비자만 사용하는 경우 이러한 작업은 타겟이 격리된 상태로 빌드될 때는 수행되지 않습니다. 이 디버깅이 더 어려워집니다. 왜냐하면 실패한 타겟만 다시 빌드하는 것은 문제를 재현할 수 있습니다

실행 파일

실행 파일은 런타임 시 타겟이 사용하는 파일 세트입니다 (빌드가 아님). 시간). 실행 단계 중에 Bazel은 실행 파일을 가리키는 심볼릭 링크를 포함하는 디렉터리 트리. 이렇게 하면 런타임 중 실행 파일에 액세스할 수 있도록 하는 것입니다.

규칙 생성 중에 실행 파일을 수동으로 추가할 수 있습니다. runfiles 객체는 runfiles 메서드로 만들 수 있습니다. ctx.runfiles의 규칙 컨텍스트에서 선언되고 DefaultInforunfiles 매개변수 실행 가능한 출력은 실행 가능 규칙이 암시적으로 실행 파일에 추가됩니다.

일부 규칙은 일반적으로 data - 그 출력이 다음에 추가됩니다. 대상 실행할 수 있습니다 실행 파일은 data에서도 병합되어야 합니다. 최종 실행을 위한 코드를 제공할 수 있는 모든 속성에서 srcs (연결된 data가 있는 filegroup 타겟을 포함할 수 있음) 및 deps입니다.

def _example_library_impl(ctx):
    ...
    runfiles = ctx.runfiles(files = ctx.files.data)
    transitive_runfiles = []
    for runfiles_attr in (
        ctx.attr.srcs,
        ctx.attr.hdrs,
        ctx.attr.deps,
        ctx.attr.data,
    ):
        for target in runfiles_attr:
            transitive_runfiles.append(target[DefaultInfo].default_runfiles)
    runfiles = runfiles.merge_all(transitive_runfiles)
    return [
        DefaultInfo(..., runfiles = runfiles),
        ...
    ]

커스텀 제공업체

provider를 사용하여 제공업체를 정의할 수 있습니다. 함수를 사용하여 규칙별 정보를 전달합니다.

ExampleInfo = provider(
    "Info needed to compile/link Example code.",
    fields={
        "headers": "depset of header Files from transitive dependencies.",
        "files_to_link": "depset of Files from compilation.",
    })

그러면 규칙 구현 함수에서 제공자 인스턴스를 구성하고 반환할 수 있습니다.

def _example_library_impl(ctx):
  ...
  return [
      ...
      ExampleInfo(
          headers = headers,
          files_to_link = depset(
              [output_file],
              transitive = [
                  dep[ExampleInfo].files_to_link for dep in ctx.attr.deps
              ],
          ),
      )
  ]
제공자 커스텀 초기화

커스텀 API를 사용하여 제공자의 인스턴스화를 전처리 및 검증 로직을 살펴보겠습니다 이 방법을 사용하면 모든 제공자 인스턴스는 특정 불변 항목을 따르거나 사용자에게 인스턴스 가져오기

init 콜백을 provider 함수 이 콜백이 제공되면 provider()의 반환 유형이 두 값의 튜플이 되도록 변경됩니다. 제공자 init가 사용되지 않는 경우 일반적인 반환 값이고 '원시'는 '생성자'로 설정합니다.

이 경우 제공자 기호가 호출되면 새 인스턴스는 init 콜백에 인수를 전달합니다. 이 콜백의 반환 값은 필드 이름 (문자열)을 값에 매핑하는 dict여야 합니다. 새 인스턴스의 필드를 초기화하는 데 사용됩니다. Note that the 콜백에 서명이 있을 수 있고 인수가 서명과 일치하지 않는 경우 콜백이 직접 호출된 것처럼 오류가 보고됩니다.

반면에 원시 생성자는 init 콜백을 우회합니다.

다음 예시에서는 init를 사용하여 인수를 전처리하고 검증합니다.

# //pkg:exampleinfo.bzl

_core_headers = [...]  # private constant representing standard library files

# It's possible to define an init accepting positional arguments, but
# keyword-only arguments are preferred.
def _exampleinfo_init(*, files_to_link, headers = None, allow_empty_files_to_link = False):
    if not files_to_link and not allow_empty_files_to_link:
        fail("files_to_link may not be empty")
    all_headers = depset(_core_headers, transitive = headers)
    return {'files_to_link': files_to_link, 'headers': all_headers}

ExampleInfo, _new_exampleinfo = provider(
    ...
    init = _exampleinfo_init)

export ExampleInfo

그러면 규칙 구현이 다음과 같이 제공자를 인스턴스화할 수 있습니다.

    ExampleInfo(
        files_to_link=my_files_to_link,  # may not be empty
        headers = my_headers,  # will automatically include the core headers
    )

원시 생성자를 사용하여 대체 공개 팩토리 함수를 정의할 수 있습니다. init 로직을 거치지 않습니다. 예를 들어 exampleinfo.bzl에서 는 다음을 정의할 수 있습니다.

def make_barebones_exampleinfo(headers):
    """Returns an ExampleInfo with no files_to_link and only the specified headers."""
    return _new_exampleinfo(files_to_link = depset(), headers = all_headers)

일반적으로 원시 생성자는 이름이 밑줄 (위 _new_exampleinfo)을 사용하여 사용자 코드로 로드할 수 없고 임의의 제공자 인스턴스를 생성합니다.

init의 또 다른 용도는 단순히 사용자가 제공자를 호출하지 못하게 하는 것입니다. 대신 팩토리 함수를 사용하도록 강제합니다.

def _exampleinfo_init_banned(*args, **kwargs):
    fail("Do not call ExampleInfo(). Use make_exampleinfo() instead.")

ExampleInfo, _new_exampleinfo = provider(
    ...
    init = _exampleinfo_init_banned)

def make_exampleinfo(...):
    ...
    return _new_exampleinfo(...)

실행 가능한 규칙 및 테스트 규칙

실행 가능한 규칙은 bazel run 명령어로 호출할 수 있는 대상을 정의합니다. 테스트 규칙은 특별한 종류의 실행 가능한 규칙이며 대상도 bazel test 명령어에 의해 호출됩니다. 실행 가능한 규칙과 테스트 규칙은 각 executable 설정 또는 rule 호출에서 Truetest 인수:

example_binary = rule(
   implementation = _example_binary_impl,
   executable = True,
   ...
)

example_test = rule(
   implementation = _example_binary_impl,
   test = True,
   ...
)

테스트 규칙의 이름은 _test로 끝나야 합니다. (대상 이름도 자주 테스트함 이는 규칙에 따라 _test로 끝나지만 이는 필수는 아닙니다.) 테스트 이외의 규칙은 허용되지 않음 이 접미사가 있습니다.

두 종류의 규칙 모두 실행 가능한 출력 파일( 사전 선언됨) run 또는 test 명령어에 의해 호출됩니다. 알리기 어떤 규칙의 출력을 이 실행 파일로 사용할 Bazel의 반환된 DefaultInfoexecutable 인수 제공업체 해당 executable가 규칙의 기본 출력에 추가되므로 executablefiles에 모두 전달할 필요는 없습니다. 또한 암시적으로 runfiles에 추가됩니다.

def _example_binary_impl(ctx):
    executable = ctx.actions.declare_file(ctx.label.name)
    ...
    return [
        DefaultInfo(executable = executable, ...),
        ...
    ]

이 파일을 생성하는 작업은 파일에서 실행 가능 비트를 설정해야 합니다. 대상 ctx.actions.run 또는 이 완료해야 할 ctx.actions.run_shell 작업 기본 도구에 의해 처리됩니다. ctx.actions.write 작업에서 is_executable=True을 전달합니다.

레거시 동작과 같이 실행 가능한 규칙에는 특수 ctx.outputs.executable 사전 선언 출력 이 파일은 DefaultInfo를 사용하여 지정하지 않은 경우 기본 실행 파일 다음과 같아서는 안 됩니다. 사용할 수 없습니다. 이 출력 메커니즘은 분석 시 실행 파일의 이름을 사용자 지정하는 데 사용됩니다.

예시 보기 실행 가능한 규칙테스트 규칙을 따릅니다.

실행 가능한 규칙테스트 규칙에는 속성에 추가된 속성 외에도 암시적으로 정의된 모든 규칙을 사용합니다. 기본값은 암시적으로 추가된 속성은 변경할 수 없지만 이 문제를 해결할 수는 있습니다. Starlark 매크로에서 비공개 규칙을 래핑하여 기본값:

def example_test(size="small", **kwargs):
  _example_test(size=size, **kwargs)

_example_test = rule(
 ...
)

실행 파일 위치

실행 파일 타겟이 bazel run (또는 test)로 실행되면 runfiles 디렉토리가 실행 파일에 인접해 있습니다. 경로는 다음과 같습니다.

# Given launcher_path and runfile_file:
runfiles_root = launcher_path.path + ".runfiles"
workspace_name = ctx.workspace_name
runfile_path = runfile_file.short_path
execution_root_relative_path = "%s/%s/%s" % (
    runfiles_root, workspace_name, runfile_path)

실행 파일 디렉터리 아래의 File 경로는 다음에 상응합니다. File.short_path

bazel에서 직접 실행되는 바이너리가 runfiles 디렉터리 그러나 실행 파일에서 호출된 바이너리는 사용할 수 있습니다. 이를 완화하려면 각 바이너리는 환경 또는 명령줄을 사용하여 runfile 루트를 매개변수로 수락 인수/플래그를 지정합니다. 이렇게 하면 바이너리가 올바른 표준 실행 파일 루트를 전달할 수 있습니다. 복사해야 합니다 이를 설정하지 않으면 바이너리는 첫 번째 바이너리가 호출되고 인접한 runfiles 디렉터리를 찾습니다.

고급 주제

출력 파일 요청

단일 대상에는 여러 출력 파일이 있을 수 있습니다. bazel build 명령어가 다음과 같은 경우 명령어를 실행하면 지정된 대상의 출력 중 일부가 요청됩니다. Bazel은 이렇게 요청된 파일과 영향을 미칩니다. (작업 그래프의 경우, Bazel은 애플리케이션의 전이 종속 항목으로 연결할 수 있는 작업을 않습니다.)

기본 출력 외에도 사전 선언된 출력은 명시적으로 요청될 수 있습니다 규칙은 사전 선언된 출력을 출력 속성을 통해 출력할 수 있습니다. 이 경우 사용자는 규칙을 인스턴스화할 때 출력 라벨을 명시적으로 선택합니다. 획득하려면 출력 속성의 경우 File 객체를 사용하는 경우 해당하는 ctx.outputs의 속성입니다. 규칙에서 다음을 기반으로 사전 선언된 출력을 암시적으로 정의합니다. 대상 이름에도 적용되지만 이 기능은 더 이상 사용되지 않습니다.

기본 출력 외에도 컬렉션인 출력 그룹이 있습니다. 출력 파일의 개수를 줄여줍니다. 이러한 포드는 --output_groups 대상 예를 들어 대상 //pkg:mytargetdebug_files가 있는 규칙 유형인 경우 출력 그룹의 경우 이러한 파일은 bazel build //pkg:mytarget --output_groups=debug_files를 실행하여 빌드할 수 있습니다. 사전 선언되지 않은 출력에는 라벨이 없으므로 기본 출력 또는 출력에 표시되는 방법으로만 요청할 수 있음 그룹

출력 그룹은 OutputGroupInfo 공급자. 여타와 달리 기본 제공 제공자인 경우 OutputGroupInfo는 임의의 이름으로 매개변수를 사용할 수 있습니다. 해당 이름으로 출력 그룹을 정의합니다.

def _example_library_impl(ctx):
    ...
    debug_file = ctx.actions.declare_file(name + ".pdb")
    ...
    return [
        DefaultInfo(files = depset([output_file]), ...),
        OutputGroupInfo(
            debug_files = depset([debug_file]),
            all_files = depset([output_file, debug_file]),
        ),
        ...
    ]

또한 대부분의 제공업체와 달리 OutputGroupInfoaspect 및 해당 관점이 적용되는 규칙 대상은 동일한 출력 그룹을 정의하지 않는 경우에 한합니다 이 경우 제공업체가 병합됩니다.

일반적으로 OutputGroupInfo는 특정 정렬을 전달하는 데 사용하면 안 됩니다. 소비자의 활동에 이르기까지 다양한 파일 형식을 지원합니다. 정의 규칙별 제공업체를 대신 사용하세요.

구성

다른 아키텍처용 C++ 바이너리를 빌드하려고 한다고 가정해 보겠습니다. 이 빌드는 복잡하고 여러 단계가 수반될 수 있습니다. 중급 수준의 컴파일러 및 코드 생성기와 같은 바이너리는 실행 플랫폼 (호스트, 실행할 수 있습니다. 최종 출력과 같은 일부 바이너리는 타겟 아키텍처를 포함합니다.

이러한 이유로 Bazel에는 '구성'이라는 개념이 있습니다. 사용할 수 있습니다. 이 최상위 대상 (명령줄에서 요청된 대상)은 'target' 실행 플랫폼에서 실행되어야 하는 도구는 'exec'에 빌드되고 구성할 수 있습니다 규칙에 따라 전달되는 CPU 아키텍처를 변경하는 등의 작업이 필요할 수 있습니다. 컴파일러에 전달합니다. 경우에 따라 서로 다른 객체에 동일한 라이브러리가 구성할 수 있습니다 이러한 경우, 분석된 후 빌드할 수 있습니다. 여러 번 반복해야 할 수도 있습니다.

기본적으로 Bazel은 대상의 종속 항목을 타겟 자체를 전환할 수 있습니다. 종속 항목이 도구 중 하나인 경우 해당 속성은 exec 구성으로의 전환을 지정합니다. 이렇게 하면 도구와 모든 종속 항목을 생성합니다.

각 종속 항목 속성에 cfg를 사용하여 종속 항목 exec 구성으로 전환해야 합니다. 종속 항목 속성에 executable=True 플래그가 있으면 cfg를 설정해야 합니다. 명시적으로 초기화합니다. 이는 실수로 잘못된 용도의 도구를 구성할 수 있습니다 예시 보기

일반적으로 소스, 종속 라이브러리, 실행 파일은 같은 구성을 사용할 수 있습니다.

빌드의 일부로 실행되는 도구 (예: 컴파일러 또는 코드 생성기) 실행 구성을 위해 빌드되어야 합니다 이 경우 cfg="exec"를 속성

그렇지 않은 경우 런타임에 사용되는 실행 파일 (예: 테스트의 일부로)은 빌드될 수 있습니다 이 경우 cfg="target"를 속성

cfg="target"는 실제로 아무것도 하지 않습니다. 순전히 규칙 디자이너가 의도를 명확히 할 수 있도록 합니다. executable=False인 경우, 즉, cfg는 선택사항이므로 가독성에 실제로 도움이 되는 경우에만 설정합니다.

cfg=my_transition를 사용하여 사용자 정의 전환을 통해 규칙 작성자는 보다 유연하게 구성을 변경할 수 있으며, 단점은 빌드 그래프를 더 크고 이해하기 쉽게 만듭니다.

참고: 지금까지 Bazel에는 실행 플랫폼 개념이 없었습니다. 대신 모든 빌드 작업이 호스트 머신에서 실행되는 것으로 간주되었습니다. 바젤 6.0 이전 버전에서는 별개의 '호스트'를 나타냅니다. 'host'라는 참조가 표시되는 경우 이것이 바로 이것입니다 나타냅니다. 이러한 추가적인 개념적 개념을 피하려면 Bazel 6.0 이상을 사용하는 것이 좋습니다. 발생할 수 있습니다

구성 프래그먼트

규칙에서 액세스할 수 있는 항목 구성 프래그먼트(예: cpp, java, jvm 하지만 모든 필수 프래그먼트는 방법은 다음과 같습니다.

def _impl(ctx):
    # Using ctx.fragments.cpp leads to an error since it was not declared.
    x = ctx.fragments.java
    ...

my_rule = rule(
    implementation = _impl,
    fragments = ["java"],      # Required fragments of the target configuration
    host_fragments = ["java"], # Required fragments of the host configuration
    ...
)

일반적으로 실행 파일 트리에 있는 파일의 상대 경로는 소스 트리나 생성된 출력 트리에 있는 해당 파일의 상대 경로입니다. 만약 어떤 이유로든 달라야 하는 경우 root_symlinks 또는 symlinks 인수. root_symlinks는 파일을 찾을 수 있습니다. 여기서 경로는 실행 파일 디렉터리의 루트를 기준으로 합니다. 이 symlinks 사전은 동일하지만 경로에 암시적으로 기본 작업공간의 이름입니다 ( 현재 타겟).

    ...
    runfiles = ctx.runfiles(
        root_symlinks = {"some/path/here.foo": ctx.file.some_data_file2}
        symlinks = {"some/path/here.bar": ctx.file.some_data_file3}
    )
    # Creates something like:
    # sometarget.runfiles/
    #     some/
    #         path/
    #             here.foo -> some_data_file2
    #     <workspace_name>/
    #         some/
    #             path/
    #                 here.bar -> some_data_file3

symlinks 또는 root_symlinks를 사용하는 경우 서로 다른 두 개를 매핑하지 않도록 주의하세요. 실행 파일 트리에서 동일한 경로로 이동하는 것입니다. 이로 인해 빌드가 실패합니다. 충돌을 설명하는 오류가 표시됩니다. 문제를 해결하려면 ctx.runfiles 인수를 사용하여 충돌을 제거합니다. 다음에 대해 확인이 수행됩니다. 규칙을 사용하는 모든 대상 및 해당 규칙을 사용하는 모든 종류의 대상 있습니다 이는 도구가 전이적으로 사용될 가능성이 있는 경우 특히 위험합니다. 다른 도구에 의해 영향을 받습니다. 심볼릭 링크 이름은 도구의 실행 파일 전체에서 고유해야 하며 모든 종속 항목이 포함됩니다

코드 적용 범위

coverage 명령어가 실행되면 빌드가 특정 타겟에 대한 커버리지 계측을 추가해야 할 수도 있습니다. 이 빌드는 계측된 소스 파일 목록도 수집합니다. 하위집합 대상은 플래그로 제어되며 --instrumentation_filter 테스트 대상은 제외됩니다. --instrument_test_targets 드림 지정합니다.

규칙 구현이 빌드 시간에 적용 범위 계측을 추가하는 경우 구현 함수에서 이를 고려합니다. ctx.coverage_instrumented는 대상의 소스를 계측해야 하는 경우 적용 범위 모드입니다.

# Are this rule's sources instrumented?
if ctx.coverage_instrumented():
  # Do something to turn on coverage for this compile action

적용 범위 모드 (타겟의 소스인지 여부)에서 항상 켜져 있어야 하는 로직입니다. 계측 또는 되지 않음)를 결정하는 데 ctx.configuration.coverage_enabled.

컴파일 전에 규칙이 종속 항목의 소스를 직접 포함하는 경우 (헤더 파일 등)를 사용하고 있다면 다음과 같은 경우 컴파일 시간 계측을 종속 항목의 소스는 다음과 같이 계측되어야 합니다.

# Are this rule's sources or any of the sources for its direct dependencies
# in deps instrumented?
if (ctx.configuration.coverage_enabled and
    (ctx.coverage_instrumented() or
     any([ctx.coverage_instrumented(dep) for dep in ctx.attr.deps]))):
    # Do something to turn on coverage for this compile action

또한 규칙은 관련성이 높은 속성에 대한 InstrumentedFilesInfo 제공자와의 커버리지를 생성하며 coverage_common.instrumented_files_info instrumented_files_infodependency_attributes 매개변수는 deps 등의 코드 종속 항목을 포함한 모든 런타임 종속 항목 속성 데이터 종속 항목(예: data) source_attributes 매개변수는 규칙의 소스 파일 속성을 업데이트합니다.

def _example_library_impl(ctx):
    ...
    return [
        ...
        coverage_common.instrumented_files_info(
            ctx,
            dependency_attributes = ["deps", "data"],
            # Omitted if coverage is not supported for this rule:
            source_attributes = ["srcs", "hdrs"],
        )
        ...
    ]

InstrumentedFilesInfo가 반환되지 않으면 각 ID와 함께 기본 URL이 생성됩니다. 다음과 같이 도구 이외의 종속 항목 속성입니다. cfg를 속성 스키마의 "host" 또는 "exec"로 변경) dependency_attributes (이는 이상적인 동작이 아니며, source_attributes 대신 dependency_attributessrcs와 같지만 모든 규칙에 대해 명시적인 적용 범위 구성을 종속 항목 체인)

검증 작업

빌드에 대한 무언가를 검증해야 할 때도 있고 검증을 수행하는 데 필요한 정보는 아티팩트에서만 사용할 수 있음 (소스 파일 또는 생성된 파일) 이 정보는 아티팩트에 있으므로 규칙을 읽을 수 없기 때문에 분석 시 규칙이 검증을 수행할 수 없습니다. 할 수 있습니다. 대신 작업은 실행 시 이 유효성 검사를 수행해야 합니다. 날짜 유효성 검사가 실패하면 작업이 실패하므로 빌드도 실패합니다.

실행할 수 있는 검증의 예로는 정적 분석, 린트 작업, 스타일 검사, 종속 항목 검사, 일관성 검사 등을 사용할 수 있습니다

검증 작업은 움직이는 부분을 통해 빌드 성능을 개선하는 데도 도움이 될 수 있습니다. 몇 가지 작업을 수행할 수 있습니다. 예를 들어 컴파일과 린트 작업을 실행하는 단일 작업이 컴파일 작업과 린트 작업으로 구분되고 린트 작업이 작업을 검증 작업으로 실행하고 다른 작업과 동시에 실행할 수 있습니다.

이러한 '유효성 검사 작업'은 다른 곳에서 사용하는 것은 아무것도 생성하지 않는 경우가 많습니다 자신의 입력에 대해 어설션하기만 하면 되기 때문입니다. 이 문제가 발생할 수 있는데, 유효성 검사 작업이 오류를 생성하지 않는 경우 가 빌드의 다른 곳에서 사용되는 경우 규칙을 통해 해당 작업을 실행하려면 어떻게 해야 할까요? 이전에는 검증 작업 출력을 빈 상태로 만드는 방식을 사용했습니다. 파일의 다른 중요한 입력에 인위적으로 작업을 실행할 수 있습니다.

이는 컴파일할 때 Bazel이 항상 유효성 검사 작업을 실행하기 때문에 하지만 여기에는 중요한 단점이 있습니다.

  1. 유효성 검사 작업은 빌드의 주요 경로에서 이루어집니다. Bazel 빈 출력이 컴파일 작업을 실행하는 데 필요하다고 판단하면 유효성 검사 작업을 먼저 해야 합니다. 이는 컴파일 작업이 입력을 무시하더라도 마찬가지입니다. 따라서 동시 로드가 줄어들고 빌드 속도가 느려집니다.

  2. 빌드의 다른 작업이 유효성 검사 작업의 빈 출력을 해당 작업도 실행합니다 (예: java_library의 소스 jar 출력). 이것은 컴파일 작업 대신 실행될 수 있는 새 작업이 비어 있는 유효성 검사 출력이 실수로 중단된 것입니다.

이 문제의 해결 방법은 유효성 검사 출력 그룹을 사용하는 것입니다.

검증 출력 그룹

검증 출력 그룹은 인위적으로 조정할 필요가 없도록 유효성 검사 작업의 사용되지 않은 출력 다른 작업의 입력에 추가됩니다.

이 그룹은 --output_groups 플래그의 값(타겟 값과 무관) 종속된 모든 컨테이너 (예: 명령줄, 종속 항목으로 또는 대상의 암시적 출력) 일반 캐싱 및 성과 증분은 계속 적용됩니다. 유효성 검사 작업에 대한 입력이 변경되지 않았고 이전에 성공한 유효성 검사 작업의 경우 유효성 검사 작업을 실행할 수 없습니다. 실행할 수 있습니다

이 출력 그룹을 사용하려면 여전히 유효성 검사 작업이 일부 파일을 출력해야 합니다. 빈 항목도 있을 수 있습니다 이를 위해서는 일반적으로 빌드되지 않는 일부 도구를 래핑해야 할 수 있습니다. 출력을 생성할 수 있습니다.

대상의 유효성 검사 작업은 다음 세 가지 경우에 실행되지 않습니다.

  • 대상이 도구로 사용되는 경우
  • 타겟이 암시적 종속 항목으로 의존하는 경우 (예: '_')로 시작하는 속성
  • 타겟이 호스트 또는 exec 구성에서 빌드되는 경우

이러한 표적에는 자체적인 검증 실패를 알아낼 수 있는 별도의 빌드 및 테스트를 진행합니다.

검증 출력 그룹 사용

검증 출력 그룹의 이름은 _validation이며 다른 모든 것과 마찬가지로 사용됩니다. 출력 그룹:

def _rule_with_validation_impl(ctx):

  ctx.actions.write(ctx.outputs.main, "main output\n")

  ctx.actions.write(ctx.outputs.implicit, "implicit output\n")

  validation_output = ctx.actions.declare_file(ctx.attr.name + ".validation")
  ctx.actions.run(
      outputs = [validation_output],
      executable = ctx.executable._validation_tool,
      arguments = [validation_output.path])

  return [
    DefaultInfo(files = depset([ctx.outputs.main])),
    OutputGroupInfo(_validation = depset([validation_output])),
  ]


rule_with_validation = rule(
  implementation = _rule_with_validation_impl,
  outputs = {
    "main": "%{name}.main",
    "implicit": "%{name}.implicit",
  },
  attrs = {
    "_validation_tool": attr.label(
        default = Label("//validation_actions:validation_tool"),
        executable = True,
        cfg = "exec"),
  }
)

유효성 검사 출력 파일은 DefaultInfo 또는 작업을 수행할 수 있습니다. 이 규칙 종류의 대상에 대한 유효성 검사 작업 대상이 라벨이나 대상의 직간접적으로 의존합니다

일반적으로 유효성 검사 작업의 출력이 다른 작업의 입력에는 추가되지 않으므로 이는 동시 로드 게인을 무효화할 수 있습니다 하지만 Bazel은 현재 이를 적용하기 위한 특별한 확인이 있어야 합니다. 따라서 애플리케이션의 유효성 검사 작업 출력이 살펴보겠습니다 예를 들면 다음과 같습니다.

load("@bazel_skylib//lib:unittest.bzl", "analysistest")

def _validation_outputs_test_impl(ctx):
  env = analysistest.begin(ctx)

  actions = analysistest.target_actions(env)
  target = analysistest.target_under_test(env)
  validation_outputs = target.output_groups._validation.to_list()
  for action in actions:
    for validation_output in validation_outputs:
      if validation_output in action.inputs.to_list():
        analysistest.fail(env,
            "%s is a validation action output, but is an input to action %s" % (
                validation_output, action))

  return analysistest.end(env)

validation_outputs_test = analysistest.make(_validation_outputs_test_impl)

유효성 검사 작업 플래그

검증 작업 실행은 --run_validations 명령줄로 제어됩니다. true로 기본 설정되어 있습니다.

지원이 중단된 기능

지원 중단된 사전 선언 출력

사전 선언된 출력을 사용하는 방법에는 지원 중단되는 두 가지 방법이 있습니다.

  • ruleoutputs 매개변수는 출력을 생성하기 위한 출력 속성 이름과 문자열 템플릿 간의 매핑은 출력 라벨을 지정합니다 사전 선언되지 않은 출력 사용을 선호함 출력을 DefaultInfo.files에 명시적으로 추가합니다. 규칙 대상의 출력을 사용하는 규칙에 대한 입력으로 라벨을 지정합니다. 출력 라벨입니다.

  • 실행 가능 규칙의 경우 ctx.outputs.executable는 다음을 나타냅니다. 를 규칙 대상과 동일한 이름으로 미리 선언된 실행 가능 출력에 추가합니다. 출력을 명시적으로 선언하는 것을 선호합니다(예: ctx.actions.declare_file(ctx.label.name)를 실행하고, 실행을 허용하도록 권한을 설정합니다 명시적 실행 가능한 출력을 DefaultInfoexecutable 매개변수에 전달합니다.

피해야 할 실행 파일 기능

ctx.runfilesrunfiles 유형에는 복잡한 특성 세트가 있으며 그 중 다수는 레거시 이유로 유지됩니다. 다음 권장사항은 복잡성을 줄이는 데 도움이 됩니다.

  • 다음의 collect_data 모드와 collect_default 모드를 사용하지 마세요. ctx.runfiles입니다. 이러한 모드는 암시적으로 runfile을 실행할 수 없습니다. 대신 다음과 같은 files 또는 transitive_files 매개변수를 사용하여 파일을 추가합니다. ctx.runfiles 또는 종속 항목의 실행 파일에서 runfiles = runfiles.merge(dep[DefaultInfo].default_runfiles)입니다.

  • 다음 표현식의 data_runfilesdefault_runfiles 사용을 피합니다. DefaultInfo 생성자 대신 DefaultInfo(runfiles = ...)를 지정하세요. '기본'의 차이점 'data' 실행 파일이 유지관리되는 동안 도움이 될 수 있습니다 예를 들어 일부 규칙은 기본 출력을 data_runfiles(default_runfiles 제외) kubectl 명령어 data_runfiles, 규칙은 기본 출력을 모두 포함하고 실행 파일을 제공하는 속성의 default_runfiles (종종 data)을 입력합니다.

  • DefaultInfo에서 runfiles를 가져올 때 (일반적으로 병합에만 해당) 실행 파일이 필요한 경우 DefaultInfo.data_runfiles아닌 DefaultInfo.default_runfiles입니다.

기존 제공업체에서 마이그레이션

지금까지 Bazel 제공자는 Target 객체의 단순 필드였습니다. 그들은 점 연산자를 사용하여 액세스할 수 있으며 (규칙의 구현 함수에서 반환한 구조체에 포함)

이 스타일은 지원 중단되었으며 새 코드에서 사용해서는 안 됩니다. 자세한 내용은 아래를 참고하세요. 마이그레이션에 도움이 될 만한 정보를 살펴보세요. 새로운 제공자 메커니즘은 있습니다. 또한 외부 IP 주소 없이도 데이터에 액세스하는 모든 코드가 provider 인스턴스를 사용해야 합니다.

현재 기존 제공업체는 계속 지원됩니다. 규칙은 둘 다 다음과 같습니다.

def _old_rule_impl(ctx):
  ...
  legacy_data = struct(x="foo", ...)
  modern_data = MyInfo(y="bar", ...)
  # When any legacy providers are returned, the top-level returned value is a
  # struct.
  return struct(
      # One key = value entry for each legacy provider.
      legacy_info = legacy_data,
      ...
      # Additional modern providers:
      providers = [modern_data, ...])

dep가 이 규칙의 인스턴스에 관한 결과 Target 객체인 경우 제공자와 그 콘텐츠는 dep.legacy_info.x로 가져올 수 있고 dep[MyInfo].y입니다.

반환된 구조체는 providers 외에도 여러 다른 특별한 의미가 있으므로 해당하는 레거시를 생성하지 않는 필드 제공업체).

  • files, runfiles, data_runfiles, default_runfilesexecutableDefaultInfo 다음 중 어떤 것도 지정할 수 없습니다. 이러한 필드를 유지하면서 DefaultInfo 제공자도 반환합니다.

  • output_groups 필드는 구조체 값을 가지며 OutputGroupInfo

provides 규칙 선언에서 providers 종속 항목 선언 속성, 기존 제공자는 문자열로 전달되고 최신 제공자는 *Info 기호로 전달됩니다. 반드시 문자열에서 기호로 바꿔야 함 할 수 있습니다. 업데이트가 어려운 복잡하거나 큰 규칙 집합 모든 규칙을 분리하는 경우 단계:

  1. 레거시 제공업체를 생성하는 규칙을 수정하여 두 레거시 최신 공급업체를 지원합니다. 포드의 상태를 선언하는 규칙의 경우 기존 제공업체를 반환하려면 레거시 및 최신 제공업체

  2. 대신 기존 제공업체를 사용하는 규칙을 수정하여 최신 제공업체입니다. 속성 선언에 기존 제공자가 필요한 경우 대신 최신 제공자를 요구하도록 업데이트합니다. 원하는 경우 소비자가 다음 중 하나를 수락/요구하도록 하여 이 작업을 1단계와 인터리브 처리 provider: 명령어를 사용하여 기존 제공업체의 존재 여부를 테스트합니다. hasattr(target, 'foo') 또는 FooInfo in target를 사용하는 새 제공업체입니다.

  3. 모든 규칙에서 기존 제공업체를 완전히 삭제합니다.