이 페이지에서는 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 범위를 지정할 수 있나요?
아니요. npm 및 Cargo와 같은 다른 패키지 관리자는 버전 범위를 (암시적 또는 명시적으로) 지원하며, 이 경우 제약 조건 솔버가 필요할 수 있고(사용자가 출력을 예측하기가 더 어려워짐) 버전 확인을 재현할 수 없게 됩니다(락 파일 필요).
대신 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
지시문이 포함되는 경우가 있습니다. 예를 들어 gazelle
의 go_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
입니다.
그런 다음 컨텍스트 저장소에 따라 마이그레이션 가이드의 '저장소 공개 상태' 표를 사용하여 표시 이름이 실제로 확인되는 저장소를 찾을 수 있습니다.
- 컨텍스트 저장소가 기본 저장소 (
@@
)인 경우:bar
가 루트 모듈의 MODULE.bazel 파일 (bazel_dep
,use_repo
,module
,use_repo_rule
중 하나를 통해)에서 도입한 명시적 저장소 이름인 경우@bar
은 MODULE.bazel 파일에서 주장하는 것으로 확인됩니다.- 그 외의 경우
bar
이 WORKSPACE에 정의된 저장소인 경우 (즉, 표준 이름이@@bar
인 경우)@bar
은@@bar
로 확인됩니다. - 그러지 않으면
@bar
가@@[unknown repo 'bar' requested from @@]
와 같이 확인되어 궁극적으로 오류가 발생합니다.
- 컨텍스트 저장소가 Bzlmod-world 저장소인 경우 (즉, 루트가 아닌 Bazel 모듈에 해당하거나 모듈 확장 프로그램에서 생성됨) 다른 Bzlmod-world 저장소만 표시되고 WORKSPACE-world 저장소는 표시되지 않습니다.
- 특히 여기에는 루트 모듈의
non_module_deps
유형 모듈 확장 프로그램에 도입된 모든 저장소 또는 루트 모듈의use_repo_rule
인스턴스화가 포함됩니다.
- 특히 여기에는 루트 모듈의
- 컨텍스트 저장소가 WORKSPACE에 정의된 경우:
- 먼저 컨텍스트 저장소 정의에 매직
repo_mapping
속성이 있는지 확인합니다. 그렇다면 먼저 매핑을 살펴봅니다.repo_mapping = {"@bar": "@baz"}
로 정의된 저장소의 경우 아래의@baz
를 살펴봅니다. bar
가 루트 모듈의 MODULE.bazel 파일에 의해 도입된 명시적 저장소 이름인 경우@bar
는 MODULE.bazel 파일이 주장하는 것으로 확인됩니다. (기본 저장소 케이스의 항목 1과 동일합니다.)- 그렇지 않으면
@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_proxy
및 HTTPS_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이 필요한 저장소를 지원하는 방법을 참고하세요.