자주 묻는 질문(FAQ)

문제 신고 소스 보기 Nightly · 8.2 · 8.1 · 8.0 · 7.6 · 7.5

이 페이지에서는 Bazel의 외부 종속 항목과 관련하여 자주 묻는 질문에 대한 답변을 제공합니다.

MODULE.bazel

MODULE.bazel이 load를 지원하지 않는 이유는 무엇인가요?

종속 항목 확인 중에 참조된 모든 외부 종속 항목의 MODULE.bazel 파일이 레지스트리에서 가져옵니다. 이 단계에서는 종속 항목의 소스 보관 파일이 아직 가져와지지 않습니다. 따라서 MODULE.bazel 파일이 다른 파일을 load하는 경우 Bazel은 전체 소스 보관 파일을 가져오지 않고는 해당 파일을 실제로 가져올 방법이 없습니다. MODULE.bazel 파일 자체는 레지스트리에 직접 호스팅되므로 특별합니다.

MODULE.bazel에서 load를 요청하는 사용자가 일반적으로 관심을 갖는 몇 가지 사용 사례가 있으며, 이러한 사용 사례는 load 없이도 해결할 수 있습니다.

  • MODULE.bazel에 나열된 버전이 다른 위치(예: .bzl 파일)에 저장된 빌드 메타데이터와 일치하는지 확인: 이는 BUILD 파일에서 로드된 .bzl 파일에서 native.module_version 메서드를 사용하여 실행할 수 있습니다.
  • 매우 큰 MODULE.bazel 파일을 관리 가능한 섹션으로 분할합니다(특히 모노레포의 경우). 루트 모듈은 include 디렉티브를 사용하여 MODULE.bazel 파일을 여러 세그먼트로 분할할 수 있습니다. MODULE.bazel 파일에서 load를 허용하지 않는 것과 같은 이유로 include는 루트가 아닌 모듈에서 사용할 수 없습니다.
  • 이전 WORKSPACE 시스템의 사용자는 저장소를 선언한 다음 즉시 해당 저장소에서 load하여 복잡한 로직을 실행하는 것을 기억할 수 있습니다. 이 기능은 모듈 확장 프로그램으로 대체되었습니다.

bazel_dep에 SemVer 범위를 지정할 수 있나요?

아니요. npmCargo와 같은 다른 패키지 관리자는 버전 범위를 (암시적 또는 명시적으로) 지원하며, 이 경우 제약 조건 솔버가 필요할 수 있고(사용자가 출력을 예측하기가 더 어려워짐) 버전 확인을 재현할 수 없게 됩니다(락 파일 필요).

대신 Bazel은 Go와 마찬가지로 최소 버전 선택을 사용하므로 출력을 쉽게 예측하고 재현성을 보장할 수 있습니다. 이는 Bazel의 설계 목표에 부합하는 절충안입니다.

또한 Bazel 모듈 버전은 SemVer의 상위 집합이므로 엄격한 SemVer 환경에서 적절한 사항이 Bazel 모듈 버전으로 반영되지 않을 수도 있습니다.

bazel_dep의 최신 버전을 자동으로 받을 수 있나요?

일부 사용자는 bazel_dep(name = "foo", version = "latest")를 지정하여 최신 버전의 종속 항목을 자동으로 가져오는 기능을 요청하는 경우가 있습니다. 이는 SemVer 범위 관련 질문과 유사하며 답변도 마찬가지로 '아니요'입니다.

이 경우 자동화를 통해 이 문제를 해결하는 것이 좋습니다. 예를 들어 Renovate는 Bazel 모듈을 지원합니다.

이 질문을 하는 사용자는 로컬 개발 중에 빠르게 반복하는 방법을 찾고 있는 경우가 있습니다. local_path_override를 사용하여 이를 실행할 수 있습니다.

use_repo가 이렇게 많은 이유는 무엇인가요?

MODULE.bazel 파일의 모듈 확장 프로그램 사용에는 큰 use_repo 지시문이 포함되는 경우가 있습니다. 예를 들어 gazellego_deps 확장 프로그램을 사용하는 일반적인 방법은 다음과 같습니다.

go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
use_repo(
    go_deps,
    "com_github_gogo_protobuf",
    "com_github_golang_mock",
    "com_github_golang_protobuf",
    "org_golang_x_net",
    ...  # potentially dozens of lines...
)

정보가 이미 참조된 go.mod 파일에 있으므로 긴 use_repo 지시어는 중복된 것처럼 보일 수 있습니다.

Bazel에 이 use_repo 디렉티브가 필요한 이유는 모듈 확장 프로그램을 지연 실행하기 때문입니다. 즉, 모듈 확장 프로그램은 결과가 관찰된 경우에만 실행됩니다. 모듈 확장 프로그램의 '출력'은 저장소 정의이므로 정의하는 저장소가 요청된 경우에만 모듈 확장 프로그램을 실행합니다 (예: 위 예시에서 타겟 @org_golang_x_net//:foo가 빌드된 경우). 그러나 모듈 확장 프로그램이 정의할 저장소는 실행한 후에야 알 수 있습니다. 여기에서 use_repo 디렉티브가 사용됩니다. 사용자는 확장 프로그램이 생성될 것으로 예상되는 저장소를 Bazel에 알릴 수 있으며, 그러면 Bazel은 이러한 특정 저장소가 사용될 때만 확장 프로그램을 실행합니다.

use_repo 디렉티브를 유지하는 데 도움이 되도록 모듈 확장 프로그램은 구현 함수에서 extension_metadata 객체를 반환할 수 있습니다. 사용자는 bazel mod tidy 명령어를 실행하여 이러한 모듈 확장 프로그램의 use_repo 디렉티브를 업데이트할 수 있습니다.

Bzlmod 이전

MODULE.bazel과 WORKSPACE 중 먼저 평가되는 것은 무엇인가요?

--enable_bzlmod--enable_workspace가 모두 설정된 경우 어떤 시스템이 먼저 컨설트되는지 궁금할 수 있습니다. 간단히 말해 MODULE.bazel(Bzlmod)이 먼저 평가됩니다.

긴 답변은 '어떤 것이 먼저 평가되나요?'가 올바른 질문이 아니라는 것입니다. 올바른 질문은 표준 이름@@foo인 저장소의 컨텍스트에서 표시되는 저장소 이름 @bar이 무엇으로 확인되는가입니다. 또는 @@base의 저장소 매핑은 무엇인가요?

명시적인 저장소 이름 (앞에 단일 @)이 있는 라벨은 라벨이 확인된 컨텍스트에 따라 다른 항목을 참조할 수 있습니다. 라벨 @bar//:baz가 표시되었을 때 실제로 가리키는 대상이 무엇인지 궁금하다면 먼저 컨텍스트 저장소가 무엇인지 알아야 합니다. 예를 들어 라벨이 저장소 @@foo에 있는 BUILD 파일에 있는 경우 컨텍스트 저장소는 @@foo입니다.

그런 다음 컨텍스트 저장소에 따라 마이그레이션 가이드의 '저장소 공개 상태' 표를 사용하여 표시 이름이 실제로 확인되는 저장소를 찾을 수 있습니다.

  • 컨텍스트 저장소가 기본 저장소 (@@)인 경우:
    1. bar가 루트 모듈의 MODULE.bazel 파일 (bazel_dep, use_repo, module, use_repo_rule 중 하나를 통해)에서 도입한 명시적 저장소 이름인 경우 @bar은 MODULE.bazel 파일에서 주장하는 것으로 확인됩니다.
    2. 그 외의 경우 bar이 WORKSPACE에 정의된 저장소인 경우 (즉, 표준 이름이 @@bar인 경우) @bar@@bar로 확인됩니다.
    3. 그러지 않으면 @bar@@[unknown repo 'bar' requested from @@]와 같이 확인되어 궁극적으로 오류가 발생합니다.
  • 컨텍스트 저장소가 Bzlmod-world 저장소인 경우 (즉, 루트가 아닌 Bazel 모듈에 해당하거나 모듈 확장 프로그램에서 생성됨) 다른 Bzlmod-world 저장소만 표시되고 WORKSPACE-world 저장소는 표시되지 않습니다.
    • 특히 여기에는 루트 모듈의 non_module_deps 유형 모듈 확장 프로그램에 도입된 모든 저장소 또는 루트 모듈의 use_repo_rule 인스턴스화가 포함됩니다.
  • 컨텍스트 저장소가 WORKSPACE에 정의된 경우:
    1. 먼저 컨텍스트 저장소 정의에 매직 repo_mapping 속성이 있는지 확인합니다. 그렇다면 먼저 매핑을 살펴봅니다. repo_mapping = {"@bar": "@baz"}로 정의된 저장소의 경우 아래의 @baz를 살펴봅니다.
    2. bar가 루트 모듈의 MODULE.bazel 파일에 의해 도입된 명시적 저장소 이름인 경우 @bar는 MODULE.bazel 파일이 주장하는 것으로 확인됩니다. (기본 저장소 케이스의 항목 1과 동일합니다.)
    3. 그렇지 않으면 @bar@@bar로 확인됩니다. 이는 WORKSPACE에 정의된 저장소 bar를 가리킬 가능성이 큽니다. 이러한 저장소가 정의되지 않으면 Bazel에서 오류가 발생합니다.

더 간결한 버전:

  • Bzlmod-world 저장소 (기본 저장소 제외)에는 Bzlmod-world 저장소만 표시됩니다.
  • WORKSPACE-world 저장소 (기본 저장소 포함)는 먼저 Bzlmod 세계의 루트 모듈이 정의하는 항목을 확인한 다음 WORKSPACE-world 저장소를 확인하도록 대체됩니다.

참고로 Bazel 명령줄의 라벨 (Starlark 플래그, 라벨 유형 플래그 값, 빌드/테스트 타겟 패턴 포함)은 기본 저장소를 컨텍스트 저장소로 사용하는 것으로 간주됩니다.

기타

오프라인 빌드를 준비하고 실행하려면 어떻게 해야 하나요?

bazel fetch 명령어를 사용하여 저장소를 미리 가져옵니다. --repo 플래그(예: bazel fetch --repo @foo)를 사용하여 @foo 저장소 (기본 저장소의 컨텍스트에서 확인됨, 위 질문 참고)만 가져오거나 타겟 패턴 (예: bazel fetch @foo//:bar)을 사용하여 @foo//:bar의 모든 전이 종속 항목을 가져올 수 있습니다 (bazel build --nobuild @foo//:bar와 동일).

빌드 중에 가져오기가 발생하지 않도록 하려면 --nofetch를 사용하세요. 더 정확히 말하자면 로컬이 아닌 저장소 규칙을 실행하려고 하면 실패합니다.

저장소를 가져와서 수정한 후 로컬에서 테스트하려면 bazel vendor 명령어를 사용하는 것이 좋습니다.

HTTP 프록시를 사용하려면 어떻게 해야 하나요?

Bazel은 curl과 같은 다른 프로그램에서 일반적으로 허용하는 http_proxyHTTPS_PROXY 환경 변수를 따릅니다.

이중 스택 IPv4/IPv6 설정에서 Bazel이 IPv6를 우선하도록 하려면 어떻게 해야 하나요?

IPv6 전용 머신에서는 Bazel이 변경사항 없이 종속 항목을 다운로드할 수 있습니다. 그러나 이중 스택 IPv4/IPv6 머신에서는 Bazel이 Java와 동일한 규칙을 따르며 사용 설정된 경우 IPv4를 선호합니다. IPv4 네트워크가 외부 주소를 확인하거나 연결할 수 없는 경우와 같이 경우에 따라 Network unreachable 예외와 빌드 실패가 발생할 수 있습니다. 이 경우 java.net.preferIPv6Addresses=true 시스템 속성을 사용하여 IPv6를 선호하도록 Bazel의 동작을 재정의할 수 있습니다. 구체적인 날짜는 다음과 같습니다.

  • --host_jvm_args=-Djava.net.preferIPv6Addresses=true 시작 옵션을 사용합니다. 예를 들어 .bazelrc 파일에 다음 줄을 추가합니다.

    startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true

  • 인터넷에 연결해야 하는 Java 빌드 타겟 (예: 통합 테스트)을 실행할 때는 --jvmopt=-Djava.net.preferIPv6Addresses=true 도구 플래그를 사용하세요. 예를 들어 .bazelrc 파일에 다음을 포함합니다.

    build --jvmopt=-Djava.net.preferIPv6Addresses

  • 종속 항목 버전 확인에 rules_jvm_external를 사용하는 경우 COURSIER_OPTS 환경 변수에 -Djava.net.preferIPv6Addresses=true를 추가하여 Coursier에 JVM 옵션을 제공합니다.

원격 실행을 사용하여 저장소 규칙을 원격으로 실행할 수 있나요?

아니요. 적어도 아직은 아닙니다. 빌드 속도를 높이기 위해 원격 실행 서비스를 사용하는 사용자는 저장소 규칙이 여전히 로컬에서 실행되는 것을 볼 수 있습니다. 예를 들어 http_archive는 먼저 로컬 머신에 다운로드된 후 (해당하는 경우 로컬 다운로드 캐시 사용) 추출되고 각 소스 파일은 입력 파일로 원격 실행 서비스에 업로드됩니다. 원격 실행 서비스가 해당 아카이브를 다운로드하고 추출하여 쓸모없는 왕복을 줄이지 않는 이유를 궁금해할 수 있습니다.

그 이유는 저장소 규칙 (및 모듈 확장 프로그램)이 Bazel 자체에서 실행하는 '스크립트'와 유사하기 때문입니다. 원격 실행자에게 Bazel이 설치되어 있지 않아도 됩니다.

또 다른 이유는 Bazel에서 로드 및 분석을 실행하기 위해 다운로드 및 추출된 보관 파일의 BUILD 파일이 필요한 경우가 많기 때문입니다. 이 작업은 로컬에서 실행됩니다.

저장소 규칙을 빌드 규칙으로 재해석하여 이 문제를 해결하는 초안 아이디어가 있습니다. 이렇게 하면 저장소 규칙을 자연스럽게 원격으로 실행할 수 있지만, 반대로 새로운 아키텍처 관련 문제가 발생합니다 (예: query 명령어는 작업을 실행해야 할 수 있으므로 설계가 복잡해짐).

이 주제에 관한 이전의 자세한 내용은 가져오기에 Bazel이 필요한 저장소를 지원하는 방법을 참고하세요.