Bzlmod로 외부 종속 항목 관리

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

Bzlmod는 새 외부 종속 항목 시스템의 코드명입니다. Bazel 5.0에 도입된 기능입니다 생성형 AI의 여러 가지 고충을 해결하기 위해 점진적으로 수정할 수 없는 이전 시스템 자세한 내용은 원본 설계 문서의 문제 설명 섹션 를 참조하세요.

Bazel 5.0에서는 Bzlmod가 기본적으로 사용 설정되지 않습니다. 깃발 다음 작업을 수행하려면 --experimental_enable_bzlmod를 지정해야 합니다. 있습니다. 플래그 이름에서 알 수 있듯이 이 기능은 현재 실험용입니다. API와 동작은 이 기능이 공식적으로 출시될 때까지 변경될 수 있습니다.

프로젝트를 Bzlmod로 이전하려면 Bzlmod 이전 가이드를 따르세요. examples 저장소에서 Bzlmod 사용 예시를 확인할 수도 있습니다.

Bazel 모듈

기존의 WORKSPACE 기반 외부 종속 항목 시스템은 저장소 규칙 (또는 저장소 규칙)을 통해 만들어진 저장소 (또는 repos) 저장소는 여전히 새로운 시스템에서 중요한 개념이지만 모듈은 핵심 단위가 될 수 있습니다

모듈은 기본적으로 각각 여러 버전을 보유할 수 있는 Bazel 프로젝트입니다. - 종속된 다른 모듈에 관한 메타데이터를 게시합니다. 이것은 다른 종속 항목 관리 시스템의 익숙한 개념인 Maven 아티팩트, npm 패키지, Cargo 크레이트, Go 모듈

모듈은 nameversion 쌍을 사용하여 종속 항목을 지정합니다. WORKSPACE. 그런 다음 종속 항목은 Bazel 레지스트리 기본적으로 Bazel Central 레지스트리. 작업공간에서 각 모듈이 저장소로 변환됩니다

MODULE.bazel

모든 모듈의 모든 버전에는 MODULE.bazel 기타 메타데이터에 적용됩니다 다음은 기본적인 예입니다.

module(
    name = "my-module",
    version = "1.0",
)

bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")

MODULE.bazel 파일은 작업공간 디렉터리의 루트에 있어야 합니다. (WORKSPACE 파일 옆) WORKSPACE 파일과 달리 전이적 종속 항목을 지정합니다. 대신 직접 종속 항목과 종속 항목의 MODULE.bazel 파일은 다음과 같습니다. 처리되어 전이 종속 항목을 자동으로 감지합니다.

MODULE.bazel 파일은 다음 파일을 지원하지 않으므로 BUILD 파일과 유사합니다. 제어 흐름의 형태입니다 또한 load 문을 금지합니다. 지시어 MODULE.bazel 파일 지원은 다음과 같습니다.

버전 형식

Bazel은 다양한 생태계를 보유하고 있으며 프로젝트에서 다양한 버전 관리 체계를 사용합니다. 이 SemVer가 가장 인기 있지만 다음과 같은 다양한 체계를 사용하여 Abseil, 버전은 날짜 기반입니다(예: 20210324.2).

이러한 이유로 Bzlmod는 보다 완화된 버전의 SemVer 사양을 채택합니다. 이 차이점은 다음과 같습니다.

  • SemVer는 “릴리스” 버전의 부분은 3으로 구성되어야 함 세그먼트: MAJOR.MINOR.PATCH. Bazel에서는 이 요구사항이 완화되어 세그먼트가 허용되지 않습니다.
  • SemVer에서 'release' 부분은 숫자로만 이루어져야 합니다. Bazel에서는 문자도 허용하도록 느슨하게 되어 있고, 시맨틱스는 '식별자'와 'prerelease' 있습니다.
  • 또한 주 버전, 부 버전 및 패치 버전 증가의 의미 체계는 적용되지 않습니다. (하지만 자세한 내용은 호환성 수준을 이전 버전과의 호환성을 나타내는 방법에 대해 자세히 알아보세요.)

유효한 SemVer 버전은 모두 유효한 Bazel 모듈 버전입니다. 또한 SemVer 버전 ab는 서로 다른 시점에 동일한 보존 조치가 있으면 a < b를 비교합니다. Bazel 모듈 버전과 비교했습니다

버전 해상도

다이아몬드 종속 항목 문제는 버전이 지정된 종속 항목의 핵심 관리할 수 있습니다. 다음과 같은 종속 항목 그래프가 있다고 가정해 보겠습니다.

       A 1.0
      /     \
   B 1.0    C 1.1
     |        |
   D 1.0    D 1.1

어떤 버전의 D를 사용해야 합니까? 이 문제를 해결하기 위해 Bzlmod는 최소 버전 선택 (MVS) 알고리즘을 사용합니다. MVS는 모든 새로운 모듈 버전은 이전 버전과 호환되므로 모든 종속 항목에 의해 지정된 버전 (이 예에서는 D 1.1)입니다. 이를 'minimal' 왜냐하면 여기서는 D 1.1이 요구사항을 충족할 수 있는 최소 버전이기 때문입니다. D 1.2 이상이 있어도 이를 선택하지 않습니다. 여기에는 추가 이점이 있습니다. 버전 선택이 고충실하고 재현 가능해야 합니다.

버전 확인은 레지스트리가 아닌 머신에서 로컬로 수행됩니다.

호환성 수준

이전 버전과의 호환성에 관한 MVS의 가정이 현실적인 이유는 다음과 같습니다. 이전 버전과 호환되지 않는 버전의 모듈을 별도의 모듈로 취급합니다. SemVer의 관점에서 A 1.x와 A 2.x는 별개의 모듈로 간주되며 해결된 종속 항목 그래프에 공존할 수 있습니다. 이것은 결과적으로 메이저 버전이 패키지의 패키지 경로에 인코딩되어 있으므로 컴파일 시간 또는 연결 시간 충돌이 없습니다.

Bazel에서는 이러한 보장을 제공하지 않습니다. 따라서 '전장'을 나타내는 버전' 번호 1개를 사용하여 이전 버전과 호환되지 않는 버전을 감지합니다. 이 번호 호환성 수준이라고 하며, module() 지시문을 포함하는 것이 좋습니다. 이 정보가 있으면 호환성이 다른 동일한 모듈의 버전이 감지될 때 해결된 종속 항목 그래프에 여러 수준이 있는 것을 확인할 수 있습니다

저장소 이름

Bazel에는 모든 외부 종속 항목에 저장소 이름이 있습니다. 때로는 종속 항목이 다른 저장소 이름을 통해 사용될 수 있습니다 (예: @io_bazel_skylib@bazel_skylib 평균 Bazel skylib) 또는 동일 저장소 이름은 여러 프로젝트의 다양한 종속 항목에 사용될 수 있습니다.

Bzlmod에서는 Bazel 모듈로 저장소를 생성할 수 있으며 모듈 확장 프로그램. 저장소 이름 충돌을 해결하려면 Google에서는 저장소 매핑을 메커니즘을 제공합니다 다음은 두 가지 중요한 개념입니다.

  • 표준 저장소 이름: 각 항목의 전역적으로 고유한 저장소 이름입니다. 저장소 저장소가 있는 디렉터리 이름입니다.
    다음과 같이 구성됩니다 (경고: 표준 이름 형식은 이 API는 언제든지 변경될 수 있습니다.

    • Bazel 모듈 저장소: module_name~version
      (. @bazel_skylib~1.0.3)
    • 모듈 확장 프로그램 저장소: module_name~version~extension_name~repo_name
      (. @rules_cc~0.0.1~cc_configure~local_config_cc)
  • 실제 저장소 이름: BUILD.bzl 파일을 업로드할 수 있습니다. 동일한 종속 항목이 서로 다른 이름을 지정할 수 있습니다
    다음과 같이 결정됩니다.

    • Bazel 모듈 저장소: module_name by 기본 또는 repo_name 속성으로 지정된 이름 bazel_dep
    • 모듈 확장 저장소: 다음을 통해 도입된 저장소 이름 use_repo

모든 저장소에는 직접 종속 항목의 저장소 매핑 사전이 있습니다. 이는 명백한 저장소 이름에서 표준 저장소 이름으로의 매핑입니다. Google Cloud는 라벨을 지정합니다. 표준 저장소 이름은 충돌하지 않으며 명백한 저장소 이름의 사용법은 MODULE.bazel를 파싱하여 검색할 수 있습니다. 파일 시스템 때문에 충돌을 쉽게 포착하여 해결할 수 있기 때문에 다른 종속 항목이 포함되어 있습니다

엄격한 deps

새로운 종속 항목 사양 형식을 사용하면 더 엄격한 검사를 실행할 수 있습니다. 포함 특히, 이제 모듈이 자체 직접 종속 항목일 수 있습니다 이를 통해 실수로 인한 중단 및 디버그하기 어려운 중단을 방지할 수 있습니다. 전이 종속 항목 그래프에서 무언가가 변경될 때

엄격한 deps는 다음을 기반으로 구현됩니다. 저장소 매핑을 참조하세요. 기본적으로 각 저장소의 저장소 매핑에는 모든 직접 종속 항목, 다른 저장소는 표시되지 않습니다 각 저장소에 표시되는 종속 항목은 다음과 같습니다. 다음과 같이 결정됩니다.

  • Bazel 모듈 저장소는 MODULE.bazel 파일에 도입된 모든 저장소를 볼 수 있습니다. bazel_depuse_repo입니다.
  • 모듈 확장 저장소는 확장 프로그램을 비롯하여 동일한 모듈에서 생성된 다른 모든 저장소를 제공합니다. 확장자가 포함됩니다.

레지스트리

Bzlmod가 Bazel에 정보를 요청하여 종속 항목 발견 레지스트리입니다. Bazel 레지스트리는 단순히 Bazel 모듈의 데이터베이스입니다. 유일한 지원되는 레지스트리 형식은 색인 레지스트리이며 정적 HTTP 서버를 생성하는 것입니다. 앞으로는 단일 모듈 레지스트리에 대한 지원을 추가할 계획입니다. 단일 모듈 레지스트리는 프로젝트의 소스와 기록이 포함된 Git 저장소입니다.

색인 레지스트리

색인 레지스트리는 다음을 포함하는 로컬 디렉터리 또는 정적 HTTP 서버입니다. 모듈 목록에 대한 정보(홈페이지, 유지관리 담당자, 각 버전의 MODULE.bazel 파일 및 각 버전의 소스를 가져오는 방법 있습니다. 특히 소스 보관 파일 자체를 제공할 필요는 없습니다.

색인 레지스트리는 다음 형식을 따라야 합니다.

  • /bazel_registry.json: 다음과 같은 레지스트리의 메타데이터가 포함된 JSON 파일입니다. <ph type="x-smartling-placeholder">
      </ph>
    • mirrors: 소스 보관 파일에 사용할 미러 목록을 지정합니다.
    • module_base_path: 다음이 있는 모듈의 기본 경로 지정 source.json 파일의 local_repository 유형
  • /modules: 이 모듈의 각 모듈의 하위 디렉터리가 포함된 디렉터리입니다. 레지스트리에 등록했습니다
  • /modules/$MODULE: 각 버전의 하위 디렉터리가 포함된 디렉터리입니다. 이 모듈의 다음 파일도 포함됩니다. <ph type="x-smartling-placeholder">
      </ph>
    • metadata.json: 모듈에 관한 정보가 포함된 JSON 파일입니다. 다음 필드로 대체합니다. <ph type="x-smartling-placeholder">
        </ph>
      • homepage: 프로젝트 홈페이지의 URL입니다.
      • maintainers: JSON 객체의 목록으로, 다음에 해당합니다. 레지스트리에 있는 모듈 유지관리자의 정보 이 정보는 다음의 작성자와 살펴보겠습니다
      • versions: 찾을 수 있는 이 모듈의 모든 버전 목록입니다. 이 레지스트리.
      • yanked_versions: 이 모듈의 양크된 버전 목록입니다. 이 현재는 작동하지 않지만 향후에는 양크화된 버전이 건너뛰거나 오류가 발생합니다.
  • /modules/$MODULE/$VERSION: 다음 파일이 포함된 디렉터리입니다. <ph type="x-smartling-placeholder">
      </ph>
    • MODULE.bazel: 이 모듈 버전의 MODULE.bazel 파일입니다.
    • source.json: JSON 파일에서 이 모듈 버전의 소스입니다.
      • 기본 유형은 '보관처리'입니다. 다음 필드로 대체합니다. <ph type="x-smartling-placeholder">
          </ph>
        • url: 소스 보관 파일의 URL입니다.
        • integrity: 하위 리소스 무결성 아카이브의 체크섬입니다.
        • strip_prefix: 파일을 추출할 때 삭제할 디렉터리 접두어입니다. 소스 보관 파일
        • patches: 문자열 목록으로, 각각 패치 파일의 이름을 지정합니다. 추출된 보관 파일에 적용됩니다 패치 파일은 /modules/$MODULE/$VERSION/patches 디렉터리에 있습니다.
        • patch_strip: Unix 패치의 --strip 인수와 동일합니다.
      • 유형은 다음 필드가 있는 로컬 경로를 사용하도록 변경할 수 있습니다. <ph type="x-smartling-placeholder">
          </ph>
        • type: local_path
        • path: 저장소의 로컬 경로로, 다음과 같이 계산됩니다. <ph type="x-smartling-placeholder">
            </ph>
          • 경로가 절대 경로인 경우 있는 그대로 사용됩니다.
          • 경로가 상대 경로이고 module_base_path가 절대 경로인 경우 경로가 <module_base_path>/<path>로 확인됩니다.
          • 경로와 module_base_path가 모두 상대 경로인 경우 경로는 <registry_path>/<module_base_path>/<path>로 결정되었습니다. 레지스트리는 로컬에서 호스팅하고 --registry=file://<registry_path>에서 사용해야 합니다. 그렇지 않으면 Bazel에서 오류가 발생합니다.
    • patches/: 패치 파일이 포함된 선택적 디렉터리이며 source.json에 'archive'가 있는 경우에만 사용됩니다. 있습니다.

Bazel 중앙 레지스트리

Bazel Central Registry (BCR)는 bcr.bazel.build. 내용 GitHub 저장소에서 bazelbuild/bazel-central-registry

BCR은 Bazel 커뮤니티에서 관리합니다. 기부자는 언제든지 가져올 수 있습니다 자세한 내용은 Bazel 중앙 레지스트리 정책 및 절차

일반 색인 레지스트리의 형식을 따르는 것 외에도 BCR은 각 모듈 버전의 presubmit.yml 파일 (/modules/$MODULE/$VERSION/presubmit.yml). 이 파일은 이것의 유효성을 검사하는 데 사용할 수 있는 대상을 빌드하고 테스트합니다. 모듈 버전이며 상호 운용성을 보장하기 위해 BCR의 CI 파이프라인에서 사용됩니다 모듈 간 차이점입니다.

레지스트리 선택

반복 가능한 Bazel 플래그 --registry를 사용하여 모듈을 요청할 수 있으므로 프로젝트를 설정하여 종속 항목을 삭제할 수 있습니다 이전 레지스트리는 우선 적용됩니다 편의를 위해 --registry 플래그 목록을 프로젝트의 .bazelrc 파일

모듈 확장 프로그램

모듈 확장을 사용하면 입력 데이터를 읽어 모듈 시스템을 확장할 수 있습니다. 종속 항목 그래프 전반의 모듈에서 마지막으로 저장소 규칙을 호출하여 저장소를 만듭니다. 둘은 비슷함 오늘날의 WORKSPACE 매크로와 호환되지만 전이 종속 항목이 포함됩니다

모듈 확장 프로그램은 저장소 규칙과 마찬가지로 .bzl 파일에서 정의됩니다. WORKSPACE 매크로 직접 호출되지 않습니다. 각 모듈은 태그라는 데이터 조각을 지정하여 확장 프로그램이 읽을 수 있도록 합니다. 그런 다음 버전 확인이 완료되면 모듈 확장 프로그램이 실행됩니다. 각 확장 프로그램은 모듈 결정 이후에 한 번 (빌드가 실제로 발생하기 전) 전체 종속 항목 그래프에서 여기에 속한 모든 태그를 읽을 수 있습니다.

          [ A 1.1                ]
          [   * maven.dep(X 2.1) ]
          [   * maven.pom(...)   ]
              /              \
   bazel_dep /                \ bazel_dep
            /                  \
[ B 1.2                ]     [ C 1.0                ]
[   * maven.dep(X 1.2) ]     [   * maven.dep(X 2.1) ]
[   * maven.dep(Y 1.3) ]     [   * cargo.dep(P 1.1) ]
            \                  /
   bazel_dep \                / bazel_dep
              \              /
          [ D 1.4                ]
          [   * maven.dep(Z 1.4) ]
          [   * cargo.dep(Q 1.1) ]

위의 종속 항목 그래프 예에서 A 1.1B 1.2 등은 Bazel 모듈입니다. 각 파일을 MODULE.bazel 파일로 생각할 수 있습니다. 각 모듈은 모듈 확장용 태그, 여기서는 'maven', 일부는 'cargo'에 지정되어 있습니다. 이 종속 항목 그래프가 완료되면 예를 들어 B 1.2가 실제로 D 1.3bazel_dep를 보유하고 있지만 다음으로 업그레이드되었을 수 있습니다. D 1.4 C로 인해 확장 프로그램 'maven'이 실행되고 maven.* 태그: 이 태그의 정보를 사용하여 만들 저장소를 결정합니다. 'cargo'의 경우 확장자가 포함됩니다.

확장 프로그램 사용

확장 프로그램은 Bazel 모듈 자체에서 호스팅되므로 먼저 모듈에 bazel_dep를 추가한 다음 use_extension 내장 함수를 사용하여 범위로 가져옵니다. 다음 예를 살펴보겠습니다. 가상의 'maven'을 사용하기 위한 MODULE.bazel 파일 확장자가 rules_jvm_external 모듈:

bazel_dep(name = "rules_jvm_external", version = "1.0")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

확장 프로그램을 범위로 가져온 후 점 문법을 사용하여 지정할 수 있습니다 태그는 해당하는 태그 클래스 (확장 프로그램 정의 참조) 참조). 다음은 maven.depmaven.pom 태그를 지정하는 예입니다.

maven.dep(coord="org.junit:junit:3.0")
maven.dep(coord="com.google.guava:guava:1.2")
maven.pom(pom_xml="//:pom.xml")

확장 프로그램이 모듈에서 사용할 저장소를 생성하는 경우 선언할 use_repo 지시어 있습니다. 이는 엄격한 deps 조건을 충족하고 로컬 저장소 이름을 피하기 위한 것입니다. 있습니다.

use_repo(
    maven,
    "org_junit_junit",
    guava="com_google_guava_guava",
)

확장 프로그램에서 생성한 저장소는 API의 일부이므로 'maven'이라는 광고 확장으로 'org_junit_junit'라는 저장소와 'com_google_guava_guava'라는 새 저장소를 만듭니다. 다음으로 바꿉니다. use_repo: 모듈 범위에서 다음과 같이 선택적으로 이름을 바꿀 수 있습니다. '구아바' 여기에서 확인하세요.

확장 프로그램 정의

모듈 확장은 저장소 규칙과 유사하게 다음을 사용하여 정의됩니다. module_extension 함수 둘 다 구현 기능이 있습니다. 저장소 규칙에는 속성, 모듈 확장 프로그램에는 tag_class. 각 필드에는 속성 개수입니다. 태그 클래스는 이 이벤트에서 사용하는 태그의 스키마를 정의합니다. 확장자가 포함됩니다. 가상의 'maven'에 대한 예시를 계속 살펴보겠습니다. 확장자:

# @rules_jvm_external//:extensions.bzl
maven_dep = tag_class(attrs = {"coord": attr.string()})
maven_pom = tag_class(attrs = {"pom_xml": attr.label()})
maven = module_extension(
    implementation=_maven_impl,
    tag_classes={"dep": maven_dep, "pom": maven_pom},
)

이러한 선언을 통해 maven.depmaven.pom 태그가 위에서 정의한 속성 스키마를 사용하여 지정합니다.

구현 함수는 WORKSPACE 매크로와 비슷하지만 module_ctx 객체를 가져와 종속 항목 그래프와 모든 관련 태그에 액세스할 수 있어야 합니다. 구현 함수에서 저장소 규칙을 호출하여 저장소를 생성합니다.

# @rules_jvm_external//:extensions.bzl
load("//:repo_rules.bzl", "maven_single_jar")
def _maven_impl(ctx):
  coords = []
  for mod in ctx.modules:
    coords += [dep.coord for dep in mod.tags.dep]
  output = ctx.execute(["coursier", "resolve", coords])  # hypothetical call
  repo_attrs = process_coursier(output)
  [maven_single_jar(**attrs) for attrs in repo_attrs]

위의 예에서는 종속 항목 그래프의 모든 모듈을 살펴봅니다. (ctx.modules)로, 각각 tags 필드가 있는 bazel_module 객체 모듈의 모든 maven.* 태그를 노출합니다. 그런 다음 명령줄을 사용하여 CLI 유틸리티를 Maven에 문의하여 해결 방법을 안내합니다. 마지막으로, 가상의 maven_single_jar를 사용하여 여러 개의 저장소를 만듭니다. repo 규칙을 만듭니다.