플랫폼을 이용한 빌드

문제 신고 소스 보기

Bazel은 모델링 플랫폼도구 모음을 정교하게 지원합니다. 이를 실제 프로젝트와 통합하려면 코드 소유자, 규칙 유지관리자, 핵심 Bazel 개발자 간의 신중한 협력이 필요합니다.

이 페이지에서는 플랫폼의 용도를 요약하고 플랫폼으로 빌드하는 방법을 보여줍니다.

tl;dr: Bazel의 플랫폼 및 도구 모음 API를 사용할 수 있지만 모든 언어 규칙, select(), 기타 기존 참조가 업데이트될 때까지는 어디서나 작동하지 않습니다. 이 같은 노력은 현재도 진행 중입니다. 결국 모든 빌드는 플랫폼을 기반으로 합니다. 아래에서 빌드가 적합한 위치를 확인하세요.

더 공식적인 문서는 다음을 참조하세요.

배경

플랫폼도구 모음은 소프트웨어 프로젝트가 다양한 머신을 타겟팅하고 올바른 언어 도구로 빌드하는 방법을 표준화하기 위해 도입되었습니다.

이는 비교적 최근에 Bazel에 추가된 버전입니다. 언어 유지관리자들이 이미 호환되지 않는 임시적인 방식으로 이 작업을 수행하고 있다는 관찰 결과에서 영감을 받았습니다. 예를 들어 C++ 규칙은 --cpu--crosstool_top를 사용하여 빌드의 대상 CPU 및 C++ 도구 모음을 설정합니다. 둘 다 '플랫폼'을 올바르게 모델링하지 않습니다. 과거의 이러한 시도로 인해 어색하고 부정확한 빌드가 발생했습니다. 이러한 플래그는 --java_toolchain와의 독립적인 자체 인터페이스를 발전시킨 Java 컴파일도 제어하지 않습니다.

Bazel은 대규모 다국어 다중 플랫폼 프로젝트에 사용됩니다. 이를 위해서는 언어와 프로젝트 상호 운용성을 장려하는 명확한 API를 포함하여 이러한 개념에 관한 보다 원칙적인 지원이 필요합니다. 이러한 새 API의 용도는 다음과 같습니다

마이그레이션

플랫폼 및 도구 모음 API는 프로젝트에서 실제로 사용할 때만 작동합니다. 프로젝트의 규칙 로직, 도구 모음, 종속 항목, select()가 이를 지원해야 하므로 이는 그리 간단한 일이 아닙니다. 이 경우 모든 프로젝트와 종속 항목이 올바르게 작동하도록 하기 위해 신중하게 이전해야 합니다.

예를 들어 Bazel의 C++ 규칙은 플랫폼을 지원합니다. 하지만 Apple Rules(사과 규칙)에는 그렇지 않습니다. 개발자의 C++ 프로젝트는 Apple을 신경 쓰지 않을 수도 있습니다. 하지만 일부는 그럴 수 있습니다. 따라서 모든 C++ 빌드에 플랫폼을 전역적으로 사용 설정하는 것은 아직 안전하지 않습니다.

이 페이지의 나머지 부분에서는 이 마이그레이션 순서와 프로젝트를 적합한 시기와 방법에 대해 설명합니다.

목표

모든 프로젝트가 다음 형식으로 빌드되면 Bazel의 플랫폼 마이그레이션이 완료됩니다.

bazel build //:myproject --platforms=//:myplatform

이는 다음을 의미합니다.

  1. 프로젝트에서 사용하는 규칙이 //:myplatform에서 올바른 도구 모음을 추론할 수 있습니다.
  2. 프로젝트의 종속 항목이 사용하는 규칙에 따라 //:myplatform에서 올바른 도구 모음을 추론할 수 있습니다.
  3. 개발자의 프로젝트에 따라 //:myplatform를 지원하거나 또는 프로젝트가 --crosstool_top와 같은 기존 API를 지원합니다.
  4. //:myplatformCPU, OS, 프로젝트 간 자동 호환성을 지원하는 기타 일반 개념의 [공통 선언][공통 플랫폼 선언]{: .external}을 참조합니다.
  5. 모든 관련 프로젝트의 select()//:myplatform에 암시된 머신 속성을 이해합니다.
  6. //:myplatform는 명확하고 재사용 가능한 위치, 즉 플랫폼이 프로젝트에 고유한 경우 프로젝트 저장소에서 정의되고, 그렇지 않은 경우 이 플랫폼을 사용할 수 있는 모든 프로젝트가 찾을 수 있는 위치에서 정의됩니다.

이전 API는 이 목표가 달성되는 즉시 삭제됩니다. 그러면 프로젝트에서 플랫폼과 도구 모음을 선택하는 표준 방법이 됩니다.

플랫폼을 사용해야 하나요?

프로젝트를 빌드하거나 크로스 컴파일하려면 프로젝트의 공식 문서를 따라야 합니다.

프로젝트, 언어 또는 도구 모음 유지관리자라면 결국에는 새 API를 지원하게 될 것입니다. 전역 마이그레이션이 완료될 때까지 기다릴지 아니면 일찍 선택할지 여부는 구체적인 가치 / 비용 요구사항에 따라 달라집니다.

가치

  • --cpu와 같은 하드 코딩된 플래그 대신 관심 있는 정확한 속성에서 select()하거나 도구 모음을 선택할 수 있습니다. 예를 들어 여러 CPU가 동일한 명령 집합을 지원할 수 있습니다.
  • 더 올바른 빌드. 위의 예에서 --cpuselect()한 다음 동일한 명령 집합을 지원하는 새 CPU를 추가하면 select()가 새 CPU를 인식하지 못합니다. 하지만 플랫폼의 select()는 여전히 정확합니다.
  • 사용자 환경 간소화. 모든 프로젝트는 다음을 이해합니다. --platforms=//:myplatform 명령줄에 여러 언어별 플래그가 필요하지 않습니다.
  • 언어 디자인 간소화. 모든 언어가 도구 모음을 정의하고 도구 모음을 사용하며 플랫폼에 적합한 도구 모음을 선택하기 위한 공통 API를 공유합니다.
  • 대상은 타겟 플랫폼과 호환되지 않는 경우 빌드 및 테스트 단계에서 건너뛰면 됩니다.

비용

  • 아직 플랫폼을 지원하지 않는 종속 프로젝트는 개발자의 프로젝트에서 자동으로 작동하지 않을 수 있습니다.
  • 제대로 작동하려면 추가적인 임시 유지관리가 필요할 수 있습니다.
  • 새 API와 기존 API를 병용하려면 혼동을 피하기 위해 좀 더 신중한 사용자 안내가 필요합니다.
  • OSCPU와 같은 일반 속성의 표준 정의는 계속 변경되고 있으며 초기 참여가 추가로 필요할 수 있습니다.
  • 언어별 도구 모음의 표준 정의는 계속 발전하고 있으며 초기에 추가 기여가 필요할 수 있습니다.

API 검토

platformconstraint_value 타겟의 모음입니다.

platform(
    name = "myplatform",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:arm",
    ],
)

constraint_value은 머신 속성입니다. 동일한 '종류'의 값은 공통 constraint_setting으로 그룹화됩니다.

constraint_setting(name = "os")
constraint_value(
    name = "linux",
    constraint_setting = ":os",
)
constraint_value(
    name = "mac",
    constraint_setting = ":os",
)

toolchainStarlark 법칙입니다. 속성은 언어의 도구 (예: compiler = "//mytoolchain:custom_gcc")를 선언합니다. 도구의 제공자는 이 정보를 이러한 도구로 빌드해야 하는 규칙에 전달합니다.

도구 모음은 타겟팅할 수 있는 머신(target_compatible_with = ["@platforms//os:linux"])과 도구가 실행될 수 있는 머신(exec_compatible_with = ["@platforms//os:mac"])의 constraint_value를 선언합니다.

$ bazel build //:myproject --platforms=//:myplatform를 빌드할 때 Bazel은 빌드 머신에서 실행할 수 있는 도구 모음과 //:myplatform용 빌드 바이너리를 자동으로 선택합니다. 이를 도구 모음 확인이라고 합니다.

사용 가능한 도구 모음 집합은 register_toolchains를 사용하여 WORKSPACE에 등록하거나 명령줄에서 --extra_toolchains를 사용하여 등록할 수 있습니다.

자세한 내용은 여기를 참고하세요.

상태

현재 플랫폼 지원은 언어에 따라 다릅니다. Bazel의 모든 주요 규칙은 플랫폼으로 옮겨가고 있습니다 하지만 이 과정에는 시간이 걸립니다. 여기에는 크게 세 가지 이유가 있습니다.

  1. 새로운 도구 모음 API (ctx.toolchains)에서 도구 정보를 가져오고 --cpu--crosstool_top와 같은 기존 설정 읽기를 중지하려면 규칙 로직을 업데이트해야 합니다. 비교적 간단합니다.

  2. 도구 모음 유지관리자는 도구 모음을 정의하고 사용자가 도구 모음을 액세스할 수 있도록 해야 합니다 (GitHub 저장소 및 WORKSPACE 항목). 이는 기술적으로는 간단하지만 쉬운 사용자 환경을 유지하려면 지능적으로 구성해야 합니다.

    플랫폼 정의도 필요합니다 (Bazel이 실행되는 동일한 머신용으로 빌드하지 않는 한). 일반적으로 프로젝트는 자체 플랫폼을 정의해야 합니다.

  3. 기존 프로젝트를 이전해야 합니다. select()전환도 이전해야 합니다. 이것이 가장 큰 과제입니다. 다국어 프로젝트에서는 특히 어렵습니다. 모든 언어가 --platforms를 읽을 수 없으면 실패할 수 있습니다.

새 규칙 집합을 설계하는 경우 처음부터 플랫폼을 지원해야 합니다. 이렇게 하면 규칙이 다른 규칙 및 프로젝트와 자동으로 호환되며, 플랫폼 API가 보편화됨에 따라 더 많은 가치를 얻을 수 있습니다.

일반적인 플랫폼 속성

여러 프로젝트에서 공통적으로 사용되는 OS, CPU 등의 플랫폼 속성은 중앙 집중식 표준 위치에서 선언해야 합니다. 이는 프로젝트 간 및 언어 간 호환성을 촉진합니다.

예를 들어 MyApp에서 constraint_value @myapp//cpus:armselect()가 있고 SomeCommonLib@commonlib//constraints:armselect()가 있는 경우 호환되지 않는 기준과 함께 'arm' 모드를 트리거합니다.

전역적으로 공통된 속성은 @platforms 저장소에 선언됩니다. 따라서 위 예의 표준 라벨은 @platforms//cpu:arm입니다. 언어 공통 속성은 각 언어의 저장소에서 선언되어야 합니다.

기본 플랫폼

일반적으로 프로젝트 소유자는 빌드할 머신 종류를 설명하는 명시적인 플랫폼을 정의해야 합니다. 그런 다음 --platforms를 사용하여 트리거됩니다.

--platforms가 설정되지 않은 경우 Bazel은 기본적으로 로컬 빌드 머신을 나타내는 platform로 설정합니다. 이는 @local_config_platform//:host에서 자동 생성되므로 명시적으로 정의할 필요가 없습니다. 로컬 머신의 OSCPU@platforms에 선언된 constraint_value와 매핑합니다.

C++

--incompatible_enable_cc_toolchain_resolution를 설정할 때 Bazel의 C++ 규칙은 플랫폼을 사용하여 도구 모음을 선택합니다. (#7260)

즉, 다음을 사용하여 C++ 프로젝트를 구성할 수 있습니다.

bazel build //:my_cpp_project --platforms=//:myplatform

레거시가 아닌

bazel build //:my_cpp_project` --cpu=... --crosstool_top=...  --compiler=...

프로젝트가 순수 C++이고 C++가 아닌 프로젝트에 의존하지 않는 경우 select전환이 호환되는 한 플랫폼을 안전하게 사용할 수 있습니다. 자세한 내용은 #7260C++ 도구 모음 구성을 참조하세요.

이 모드는 기본적으로 사용 설정되어 있지 않습니다. Apple 프로젝트는 여전히 --cpu--crosstool_top로 C++ 종속 항목을 구성하기 때문입니다(예시). 따라서 이는 플랫폼으로 이전하는 Apple 규칙에 따라 다릅니다.

Java

Bazel의 Java 규칙은 플랫폼을 사용합니다.

이는 기존 플래그 --java_toolchain, --host_java_toolchain, --javabase, --host_javabase를 대체합니다.

구성 플래그를 사용하는 방법을 알아보려면 Bazel 및 Java 설명서를 참조하세요. 자세한 내용은 디자인 문서를 참고하세요.

아직 기존 플래그를 사용 중인 경우 문제 #7849의 이전 프로세스를 따르세요.

Android

Bazel의 Android 규칙은 --incompatible_enable_android_toolchain_resolution를 설정할 때 플랫폼을 사용하여 도구 모음을 선택합니다.

이 기능은 기본적으로 사용 설정되어 있지 않습니다. 그러나 이전은 순조롭게 진행되고 있습니다.

사과

Bazel의 Apple 규칙은 아직 Apple 도구 모음을 선택하는 플랫폼을 지원하지 않습니다.

또한 기존 --crosstool_top를 사용하여 C++ 도구 모음을 설정하기 때문에 플랫폼 지원 C++ 종속 항목을 지원하지 않습니다. 이 버전이 이전될 때까지는 Apple 프로젝트를 플랫폼 매핑(예시)과 함께 Platorm 지원 C++와 혼합할 수 있습니다.

다른 언어

새로운 언어에 대한 규칙을 설계하는 경우 플랫폼을 사용하여 언어의 도구 모음을 선택합니다. 자세한 둘러보기는 도구 모음 문서를 참고하세요.

select()

프로젝트는 constraint_value 타겟에서 select()할 수 있지만 플랫폼을 완성할 수는 없습니다. 이는 select()가 가능한 한 다양한 머신을 지원하도록 의도된 것입니다. ARM 관련 소스가 있는 라이브러리는 더 구체적인 이유가 없는 한 모든 ARM 지원 머신을 지원해야 합니다.

하나 이상의 constraint_value를 선택하려면 다음을 사용합니다.

config_setting(
    name = "is_arm",
    constraint_values = [
        "@platforms//cpu:arm",
    ],
)

이는 일반적으로 --cpu에서 선택하는 것과 같습니다.

config_setting(
    name = "is_arm",
    values = {
        "cpu": "arm",
    },
)

자세한 내용은 여기를 참조하세요.

--cpu, --crosstool_top 등의 select--platforms를 이해하지 못합니다. 프로젝트를 플랫폼으로 이전할 때는 프로젝트를 constraint_values로 변환하거나 플랫폼 매핑을 사용하여 이전 기간 동안 두 스타일을 모두 지원해야 합니다.

화면전환

Starlark 전환은 빌드 그래프의 일부 아래로 플래그를 변경합니다. 프로젝트에서 --cpu, --crossstool_top 또는 기타 기존 플래그를 설정하는 전환을 사용하는 경우 --platforms를 읽는 규칙에는 이러한 변경사항이 표시되지 않습니다.

프로젝트를 플랫폼으로 이전할 때는 return { "//command_line_option:cpu": "arm" }와 같은 변경사항을 return { "//command_line_option:platforms": "//:my_arm_platform" }로 변환하거나 플랫폼 매핑을 사용하여 이전 창을 통해 두 스타일을 모두 지원해야 합니다.

현재 플랫폼 사용 방법

프로젝트를 빌드하거나 크로스 컴파일하려면 프로젝트의 공식 문서를 따라야 합니다. 플랫폼과 통합하는 방법 및 시기, 플랫폼이 제공하는 가치를 결정하는 것은 언어 및 프로젝트 유지관리자에게 달려 있습니다.

개발자가 프로젝트, 언어 또는 도구 모음 유지관리자이고 빌드에서 기본적으로 플랫폼을 사용하지 않는 경우 전역 이전을 기다리는 것 외에 세 가지 옵션이 있습니다.

  1. 프로젝트의 언어(플랫폼이 있는 경우)의 'use platform'(플랫폼 사용) 플래그를 켜고 관심 있는 프로젝트가 작동하는지 확인하기 위해 필요한 모든 테스트를 수행합니다.

  2. 관심 있는 프로젝트가 여전히 --cpu--crosstool_top와 같은 기존 플래그를 사용하는 경우 --platforms와 함께 사용합니다.

    bazel build //:my_mixed_project --platforms==//:myplatform --cpu=... --crosstool_top=...
    

    유지보수 비용이 약간 발생합니다. 설정이 일치하는지 수동으로 확인해야 합니다. 단, 무단 전환이 없는 경우에는 이 방식으로 정상 처리됩니다.

  3. --cpu 스타일 설정을 해당 플랫폼에 매핑하거나 그 반대로 매핑하여 두 스타일을 모두 지원하는 플랫폼 매핑을 작성합니다.

플랫폼 매핑

플랫폼 매핑은 후자의 지원 중단 기간까지 동일한 빌드에 플랫폼 기반 로직과 레거시 기반 로직이 공존할 수 있도록 하는 임시 API입니다.

플랫폼 매핑은 platform()를 상응하는 기존 플래그 세트에 매핑하거나 그 반대로 합니다. 예를 들면 다음과 같습니다.

platforms:
  # Maps "--platforms=//platforms:ios" to "--cpu=ios_x86_64 --apple_platform_type=ios".
  //platforms:ios
    --cpu=ios_x86_64
    --apple_platform_type=ios

flags:
  # Maps "--cpu=ios_x86_64 --apple_platform_type=ios" to "--platforms=//platforms:ios".
  --cpu=ios_x86_64
  --apple_platform_type=ios
    //platforms:ios

  # Maps "--cpu=darwin --apple_platform_type=macos" to "//platform:macos".
  --cpu=darwin
  --apple_platform_type=macos
    //platforms:macos

Bazel은 이를 사용하여 전환을 포함하여 빌드 전체에 플랫폼 기반 및 레거시 설정을 포함한 모든 설정이 일관되게 적용되도록 보장합니다.

기본적으로 Bazel은 작업공간 루트에 있는 platform_mappings 파일에서 매핑을 읽습니다. --platform_mappings=//:my_custom_mapping를 설정할 수도 있습니다.

자세한 내용은 여기를 참고하세요.

질문

마이그레이션 일정에 대한 일반적인 지원 및 질문이 있는 경우 bazel-discuss@googlegroups.com 또는 해당 규칙 소유자에게 문의하세요.

플랫폼/도구 모음 API의 설계와 발전에 관한 논의는 bazel-dev@googlegroups.com으로 문의하세요.

참고 항목