Bazel은 링커, 컴파일러와 같은 다양한 버전의 빌드 도구를 사용하여 다양한 하드웨어, 운영체제 및 시스템 구성에서 코드를 빌드하고 테스트할 수 있습니다. 이러한 복잡성을 해소하기 위해 Bazel은 제약조건과 플랫폼 개념을 가지고 있습니다. 제약조건은 빌드나 프로덕션 환경이 CPU 아키텍처, GPU의 존재 또는 부재, 시스템에 설치된 컴파일러 버전 등 다를 수 있는 측정기준입니다. 플랫폼은 이러한 제약 조건에 따라 이름이 지정된 선택 모음으로, 일부 환경에서 사용할 수 있는 특정 리소스를 나타냅니다.
환경을 플랫폼으로 모델링하면 Bazel이 빌드 작업에 적합한 도구 모음을 자동으로 선택할 수 있습니다. 또한 플랫폼을 config_setting 규칙과 함께 사용하여 구성 가능한 속성을 작성할 수 있습니다.
Bazel은 플랫폼이 제공할 수 있는 세 가지 역할을 인식합니다.
- 호스트 - Bazel이 실행되는 플랫폼입니다.
- 실행 - 빌드 도구가 빌드 작업을 실행하여 중간 및 최종 출력을 생성하는 플랫폼
- 타겟 - 최종 출력이 상주하고 실행되는 플랫폼입니다.
Bazel은 플랫폼과 관련하여 다음과 같은 빌드 시나리오를 지원합니다.
단일 플랫폼 빌드 (기본값) - 호스트, 실행, 대상 플랫폼이 동일합니다. 예를 들어 Intel x64 CPU에서 실행되는 Ubuntu에서 Linux 실행 파일을 빌드합니다.
크로스 컴파일 빌드 - 호스트 및 실행 플랫폼은 동일하지만 타겟 플랫폼은 다릅니다. 예를 들어 MacBook Pro에서 실행되는 macOS에서 iOS 앱을 빌드해야 합니다.
멀티 플랫폼 빌드 - 호스트, 실행, 타겟 플랫폼은 모두 다릅니다.
제약조건 및 플랫폼 정의
플랫폼에 사용할 수 있는 선택 공간은 BUILD
파일 내의 constraint_setting
및 constraint_value
규칙을 사용하여 정의됩니다. constraint_setting
는 새 측정기준을 만드는 반면 constraint_value
는 지정된 측정기준에 대한 새 값을 만듭니다. enum과 가능한 값을 효과적으로 정의합니다. 예를 들어 BUILD
파일의 다음 스니펫은 가능한 값이 2개 있는 시스템의 glibc 버전에 대한 제약조건을 도입합니다.
constraint_setting(name = "glibc_version")
constraint_value(
name = "glibc_2_25",
constraint_setting = ":glibc_version",
)
constraint_value(
name = "glibc_2_26",
constraint_setting = ":glibc_version",
)
제약조건 및 제약조건의 값은 작업공간의 여러 패키지에서 정의될 수 있습니다. 라벨별로 참조되고 일반적인 공개 상태 제어가 적용됩니다. 공개 상태를 허용하는 경우 기존 제약조건 설정을 자체 값으로 정의하여 확장할 수 있습니다.
platform
규칙에서는 특정 제약 조건 값을 선택할 수 있는 새 플랫폼을 도입합니다. 다음은 linux_x86
라는 플랫폼을 만들고 glibc 버전 2.25가 있는 x86_64 아키텍처에서 Linux 운영체제를 실행하는 환경을 설명합니다. Bazel의 기본 제공 제약조건에 대한 자세한 내용은 아래를 참조하세요.
platform(
name = "linux_x86",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
":glibc_2_25",
],
)
일반적으로 유용한 제약조건 및 플랫폼
생태계의 일관성을 유지하기 위해 Bazel팀은 가장 많이 사용되는 CPU 아키텍처 및 운영체제에 대한 제약조건 정의가 포함된 저장소를 유지합니다. 모두 https://github.com/bazelbuild/platforms에 있습니다.
Bazel은 특수 플랫폼 정의(@local_config_platform//:host
)와 함께 제공됩니다. 자동 감지된 호스트 플랫폼 값입니다. Bazel이 실행 중인 시스템에서 자동으로 감지된 플랫폼을 나타냅니다.
빌드용 플랫폼 지정
다음 명령줄 플래그를 사용하여 빌드의 호스트 및 대상 플랫폼을 지정할 수 있습니다.
--host_platform
- 기본값은@bazel_tools//platforms:host_platform
--platforms
- 기본값은@bazel_tools//platforms:target_platform
호환되지 않는 타겟을 건너뜁니다.
특정 타겟 플랫폼에 맞게 빌드할 때는 해당 플랫폼에서 전혀 작동하지 않는 타겟을 건너뛰는 것이 바람직한 경우가 많습니다. 예를 들어 //...
를 사용하여 Linux 시스템에서 빌드할 때 Windows 기기 드라이버에서 많은 컴파일러 오류가 발생할 수 있습니다. 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
가 명령줄에서 --expand_test_suites
로 지정된 경우 test_suite
에서 호환되지 않는 테스트를 건너뜁니다.
즉, 명령줄의 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의 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
를 사용하여 호환되지 않는 타겟 감지
bazel cquery
의 Starlark 출력 형식에서 IncompatiblePlatformProvider
를 사용하여 호환되지 않는 타겟을 호환되는 타겟과 구분할 수 있습니다.
호환되지 않는 타겟을 필터링하는 데 사용할 수 있습니다. 아래 예시에서는 호환되는 타겟의 라벨만 출력합니다. 호환되지 않는 타겟은 출력되지 않습니다.
$ cat example.cquery
def format(target):
if "IncompatiblePlatformProvider" not in providers(target):
return target.label
return ""
$ bazel cquery //... --output=starlark --starlark:file=example.cquery
알려진 문제
호환되지 않는 타겟은 공개 상태 제한을 무시합니다.