소개
Bazel은 다양한 하드웨어, 운영체제, 시스템 구성에서 코드를 빌드하고 테스트할 수 있습니다. 여기에는 링커 및 컴파일러와 같은 다양한 버전의 빌드 도구가 포함될 수 있습니다. 이러한 복잡성을 관리하기 위해 Bazel에는 제약조건 및 플랫폼 이라는 개념이 있습니다.
제약조건 은 빌드 또는 프로덕션 머신의 고유한 속성입니다. 일반적인 제약조건은 CPU 아키텍처, GPU의 유무 또는 로컬에 설치된 컴파일러의 버전입니다. 하지만 제약조건은 빌드 작업을 오케스트레이션할 때 머신을 의미 있게 구분하는 모든 것 이 될 수 있습니다.
플랫폼 은 완전한 머신을 지정하는 제약조건 모음입니다. Bazel은 이 개념을 사용하여 개발자가 빌드할 머신, 컴파일 및 테스트 작업을 실행해야 하는 머신, 빌드 작업이 컴파일해야 하는 도구 모음을 선택할 수 있도록 합니다.
개발자는 제약조건을 사용하여 빌드 규칙에서 커스텀 속성 또는 종속 항목을
선택할 수도 있습니다. 예를 들어 "빌드가 Arm 머신을 타겟팅할 때
사용src_arm.cc" 입니다.
플랫폼 유형
Bazel은 플랫폼이 수행할 수 있는 세 가지 역할을 인식합니다.
- 호스트 - Bazel 자체가 실행되는 플랫폼입니다.
- 실행 - 빌드 출력을 생성하기 위해 컴파일 작업을 실행하는 플랫폼입니다.
- 타겟 - 빌드 중인 코드가 실행되어야 하는 플랫폼입니다.
빌드에는 일반적으로 플랫폼과의 관계가 세 가지 있습니다.
단일 플랫폼 빌드 - 호스트, 실행, 타겟 플랫폼이 동일합니다. 예를 들어 원격 실행 없이 개발자 머신에서 빌드한 다음 동일한 머신에서 빌드된 바이너리를 실행합니다.
교차 컴파일 빌드 - 호스트 및 실행 플랫폼은 동일하지만 타겟 플랫폼은 다릅니다. 예를 들어 원격 실행 없이 Macbook Pro에서 iOS 앱을 빌드합니다.
멀티 플랫폼 빌드 - 호스트, 실행, 타겟 플랫폼이 모두 다릅니다. 예를 들어 Macbook Pro에서 iOS 앱을 빌드하고 원격 Linux 머신을 사용하여 Xcode가 필요하지 않은 C++ 작업을 컴파일합니다.
플랫폼 지정
개발자가 플랫폼을 사용하는 가장 일반적인 방법은 --platforms 플래그로 원하는 타겟 머신을 지정하는 것입니다.
$ bazel build //:my_linux_app --platforms=//myplatforms:linux_x86
일반적으로 조직은 빌드 머신 설정이 조직마다 다르기 때문에 자체 플랫폼 정의를 유지합니다.
--platforms가 설정되지 않은 경우 기본값은 @platforms//host입니다. 이는 빌드가 Bazel이 실행되는 동일한 머신을 타겟팅하도록 호스트 머신의 OS 및 CPU 속성을 자동 감지하도록 특별히 정의됩니다. 빌드 규칙은
선택할 수 있습니다. 이러한 속성을 사용하여
@platforms/os 및
@platforms/cpu
제약조건을
일반적으로 유용한 제약조건 및 플랫폼
생태계를 일관되게 유지하기 위해 Bazel팀은 가장 많이 사용되는 CPU 아키텍처 및 운영체제의 제약조건 정의가 포함된 저장소를 유지관리합니다. 이러한 정의는 모두 https://github.com/bazelbuild/platforms에 있습니다.
Bazel은 다음과 같은 특수 플랫폼 정의와 함께 제공됩니다.
@platforms//host (@bazel_tools//tools:host_platform으로 별칭 지정됨). 이
는 Bazel이 실행되는 머신의 OS 및 CPU 속성을 자동으로 감지합니다.
제약조건 정의
제약조건은 constraint_setting 및
constraint_value 빌드 규칙으로 모델링됩니다.
constraint_setting은 속성 유형을 선언합니다. 예를 들면 다음과 같습니다.
constraint_setting(name = "cpu")
constraint_value는 해당 속성의 가능한 값을 선언합니다.
constraint_value(
name = "x86",
constraint_setting = ":cpu"
)
플랫폼을 정의하거나 빌드 규칙을 맞춤설정할 때 라벨로 참조할 수 있습니다. 위의 예가 cpus/BUILD에 정의되어 있는 경우
제약조건을 x86으로 참조할 수 있습니다.//cpus:x86
공개 상태가 허용하는 경우 기존 constraint_setting에 자체 값을 정의하여 확장할 수 있습니다.
플랫폼 정의
platform 빌드 규칙
은 플랫폼을 constraint_value 모음으로 정의합니다.
platform(
name = "linux_x86",
constraint_values = [
"//oses:linux",
"//cpus:x86",
],
)
이렇게 하면 //oses:linux 및 //cpus:x86 제약조건이 모두 있어야 하는 머신이 모델링됩니다.
플랫폼에는 지정된 constraint_setting에 대해 constraint_value가 하나만 있을 수 있습니다.
즉, 두 번째 값을 모델링하는 다른 constraint_setting 유형을 만들지 않는 한 플랫폼에 CPU가 두 개 있을 수 없습니다.
호환되지 않는 타겟 건너뛰기
특정 타겟 플랫폼을 빌드할 때 해당 플랫폼에서 절대 작동하지 않는 타겟을 건너뛰는 것이 좋습니다. 예를 들어 Windows 기기 드라이버는 //...를 사용하여 Linux 머신에서 빌드할 때 많은 컴파일러 오류를 생성할 수 있습니다.
target_compatible_with
속성을 사용하여 Bazel에 코드의 타겟 플랫폼 제약조건을 알립니다.
이 속성을 가장 간단하게 사용하는 방법은 타겟을 단일 플랫폼으로 제한하는 것입니다.
타겟은 모든 제약조건을 충족하지 않는 플랫폼에 대해 빌드되지 않습니다. 다음 예에서는 win_driver_lib.cc를 64비트 Windows로 제한합니다.
cc_library(
name = "win_driver_lib",
srcs = ["win_driver_lib.cc"],
target_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
],
)
:win_driver_lib 는 64비트 Windows로 빌드하는 데 만 호환되며 다른 모든 것과 호환되지 않습니다. 비호환성은 전이적입니다. 호환되지 않는 타겟에 전이적으로 종속된 타겟은 자체적으로 호환되지 않는 것으로 간주됩니다.
타겟은 언제 건너뛰나요?
타겟은 호환되지 않는 것으로 간주되고 타겟 패턴 확장 프로그램의 일부로 빌드에 포함될 때 건너뜁니다. 예를 들어 다음 두 호출은 타겟 패턴 확장 프로그램에서 발견된 호환되지 않는 타겟을 건너뜁니다.
$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all
test_suite의 호환되지 않는 테스트도
마찬가지로 건너뜁니다. test_suite가 명령줄에서
--expand_test_suites로 지정된 경우
즉, 명령줄의 test_suite 타겟은 :all 및 ...와 같이 동작합니다. --noexpand_test_suites를 사용하면 확장이 방지되고 호환되지 않는 테스트가 있는
test_suite 타겟도 호환되지 않게 됩니다.
명령줄에서 호환되지 않는 타겟을 명시적으로 지정하면 오류 메시지가 표시되고 빌드가 실패합니다.
$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully
--skip_incompatible_explicit_targets가 사용 설정된 경우 호환되지 않는 명시적 타겟은 자동으로 건너뜁니다.
더 표현력이 풍부한 제약조건
제약조건을 더 유연하게 표현하려면 플랫폼이 충족하지 않는
@platforms//:incompatible
constraint_value
를 사용하세요.
select()를
@platforms//:incompatible와 함께 사용하여 더 복잡한 제한사항을 표현합니다. 예를 들어 기본 OR 로직을 구현하는 데 사용합니다. 다음은 macOS 및 Linux와 호환되지만 다른 플랫폼과는 호환되지 않는 라이브러리를 표시합니다.
cc_library(
name = "unixish_lib",
srcs = ["unixish_lib.cc"],
target_compatible_with = select({
"@platforms//os:osx": [],
"@platforms//os:linux": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
)
위의 내용은 다음과 같이 해석할 수 있습니다.
- macOS를 타겟팅할 때 타겟에는 제약조건이 없습니다.
- Linux를 타겟팅할 때 타겟에는 제약조건이 없습니다.
- 그 외의 경우 타겟에는
@platforms//:incompatible제약조건이 있습니다.@platforms//:incompatible은 플랫폼의 일부가 아니므로 타겟은 호환되지 않는 것으로 간주됩니다.
제약조건을 더 읽기 쉽게 만들려면
skylib's
selects.with_or()를 사용하세요.
비호환성을 비슷한 방식으로 표현할 수 있습니다. 다음 예에서는 ARM을 제외한 모든 것과 호환되는 라이브러리를 설명합니다.
cc_library(
name = "non_arm_lib",
srcs = ["non_arm_lib.cc"],
target_compatible_with = select({
"@platforms//cpu:arm": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)
bazel cquery를 사용하여 호환되지 않는 타겟 감지
IncompatiblePlatformProvider
를 bazel cquery's Starlark 출력
형식에서 호환되지 않는 타겟과 호환되는 타겟을 구분할 수 있습니다.
이를 사용하여 호환되지 않는 타겟을 필터링할 수 있습니다. 아래 예에서는 호환되는 타겟의 라벨만 출력합니다. 호환되지 않는 타겟은 출력되지 않습니다.
$ cat example.cquery
def format(target):
if "IncompatiblePlatformProvider" not in providers(target):
return target.label
return ""
$ bazel cquery //... --output=starlark --starlark:file=example.cquery
알려진 문제
호환되지 않는 타겟은 공개 상태 제한사항을 무시합니다.