Soong Build

cluelin·2022년 1월 17일
0

https://android.googlesource.com/platform/build/soong/+/refs/heads/master/README.md

Soong

Soong은 안드로이드 make 빌드 시스템의 대체품입니다. Android.mk 파일을 Android.bp 파일로 대체하며, 이는 빌드할 모듈에 대한 JSON과 비슷한 선언문입니다.

Android.bp 파일 포맷

디자인상 Android.bp 파일은 매우 간단합니다. 조건문이나 제어 흐름문은 없으며 모든 복잡성은 Go로 작성된 빌드 로직으로 처리됩니다. Android.bp 파일의 구문과 의미는 가능하면 Bazel BUILD 파일과 유사하게 구성되었습니다.

Modules

Android.bp의 모듈은 모듈 타입으로 시작하고 name: value, format: 과 같은 속성값들이 따라옵니다.

cc_binary {
    name: "gzip",
    srcs: ["src/test/minigzip.c"],
    shared_libs: ["libz"],
    stl: "none",
}

모든 모듈에는 이름 속성이 있어야 하며 값은 모든 Android.bp 파일에서 고유해야 합니다.

유효한 모듈 유형 및 해당 속성 목록은 m soong_docs 를 호출하여 생성할 수 있습니다. $OUT_DIR/soong/docs/soong_build.html에 기록됩니다. 현재 버전의 목록은 여기에서 확인할 수 있습니다.

파일리스트

파일 목록을 가져오는 속성은 glob 패턴 및 출력 경로 확장도 수행할 수 있습니다.

glob 패턴은 와일드카드 *를 포함할 수 있습니다(예: "*.java").

glob 패턴은 경로 요소로 단일 ** 와일드카드를 포함할 수도 있으며, 이 와일드카드는 0개 이상의 경로 요소와 일치합니다.
예를 들어, java/**/*.javajava/Main.javajava/com/android/Main.java 와 일치합니다.

출력 경로 확장 형식은 :module 또는 :module{.tag} 이며, 여기서 module은 출력 파일을 생성하는 모듈의 이름입니다. 옵션인 {.tag} 접미사를 사용하면 모듈에서 태그에 따라 다른 출력 목록을 생성할 수 있습니다.

예를 들어, 이름이 "my-docs"인 droiddoc 모듈은 .stubs.srcjar 출력을 ":my-docs"과 함께 반환하고, .doc.zip 파일을 ":my-docs{.doc.zip}"과 함께 반환합니다.

일반적으로 출력 파일이 src로 구성된 파일 그룹 모듈을 참조하는 데 사용됩니다.

Variables

Android.bp 파일은 최상위 변수 할당을 포함할 수 있습니다.

gzip_srcs = ["src/test/minigzip.c"],

cc_binary {
    name: "gzip",
    srcs: gzip_srcs,
    shared_libs: ["libz"],
    stl: "none",
}

변수는 선언된 파일의 나머지 부분뿐만 아니라 하위 Android.bp 파일로 범위가 지정됩니다.

변수는 한 가지 예외를 제외하고 불변합니다. 변수는 += 할당으로 추가할 수 있지만 참조되기 전에만 추가할 수 있습니다.

코멘트

Android.bp 파일에는
C 스타일 다중 줄 /* */ 및
C++ 스타일 단일 라인 //
코멘트가 포함될 수 있습니다.

Types

변수 및 속성은 강력한 유형이며, 변수는 첫 번째 할당을 기반으로 동적으로 지정되며, 속성은 모듈 유형에 따라 정적으로 지정됩니다. 지원되는 유형은 다음과 같습니다.

  • Bool (true or false)
  • Integers (int)
  • Strings ("string")
  • Lists of strings (["string1", "string2"])
  • Maps ({key1: "value1", key2: ["value2"]})

map 은 중첩 map 을 포함하여 모든 유형의 값을 사용할 수 있습니다. List와 map은 마지막 값 뒤에 쉼표가 있을 수 있습니다.

문자열은 \"를 사용 하여 "를 표현할수있습니다.
예를 들어 "cat \"a b\"를 사용하여 큰 따옴표를 포함할 수 있습니다.

Operators

문자열, 문자열 목록 및 맵은 + 연산자를 사용하여 추가할 수 있습니다.
정수는 + 연산자를 사용하여 합칠 수 있습니다.
맵을 추가하면 두 맵에 있는 키의 조합이 생성되며 두 맵에 있는 모든 키의 값을 추가합니다.

Defaults modules

Defaults modules을 사용하여 여러 모듈에서 동일한 속성을 반복할 수 있습니다. 예:

cc_defaults {
    name: "gzip_defaults",
    shared_libs: ["libz"],
    stl: "none",
}

cc_binary {
    name: "gzip",
    defaults: ["gzip_defaults"],
    srcs: ["src/test/minigzip.c"],
}

Packages

빌드는 패키지로 구성되며 각 패키지는 관련 파일의 모음이며 모듈 형태로 그들 사이의 의존성에 대한 명세이다.

패키지는 Android.bp 파일을 포함하는 디렉터리로 정의되며 빌드에서 최상위 디렉터리 아래에 위치하고
이름은 최상위 디렉터리의 path와 연관됩니다. 패키지에는 디렉터리에 있는 모든 파일과 그 아래에 있는 모든 하위 디렉터리가 포함됩니다. 단, Android.bp 파일을 가지고있는 하위 디렉토리는 제외됩니다.

패키지의 Android.bp 안에있는 모듈 및 포함된 파일은 모듈의 일부입니다.

예를 들어, 다음 디렉터리 트리(여기서 .../android/는 최상위 안드로이드 디렉터리)에는 my/app 및 하위 패키지 my/app/tests의 두 개의 패키지가 있습니다. my/app/data는 패키지가 아니라 패키지 my/app에 속하는 디렉터리입니다.

.../android/my/app/Android.bp
.../android/my/app/app.cc
.../android/my/app/data/input.txt
.../android/my/app/tests/Android.bp
.../android/my/app/tests/test.cc

이것은 Bazel 패키지 컨셉을 기반으로 합니다.

패키지 모듈 유형은 패키지에 관한 정확한 정보를 제공해줍니다. 패키지당 하나의 패키지 모듈만 지정할 수 있으며 동일한 패키지 디렉토리에 여러 개의 .bp 파일이 있는 경우 패키지 모듈(필요한 경우)을 Android.bp 파일에 지정하는 것이 좋습니다.

대부분의 모듈 타입과 달리 패키지는 이름 속성이 없습니다. 대신 패키지 이름으로 설정됩니다(예: 패키지가 top/intermediate/package에 있는 경우 패키지 이름은 //top/intermediate/package).

예: 다음은 패키지에 정의된 모든 모듈과 자체 기본 가시성을 설정하지 않은 하위 패키지에 대한 기본 가시성을 모든 하위 패키지에 기본적으로 표시되도록 설정합니다.

package {
    default_visibility: [":__subpackages"]
}

Referencing Modules

모듈 libfoo는 이름으로 참조할 수 있습니다

cc_binary {
    name: "app",
    shared_libs: ["libfoo"],
}

소스 트리에 libfoo 모듈이 하나만 있는 경우에만 동작합니다. 트리가 더 커지는 경우에 이름을 고유하게 유지하는것이 어려울수 있습니다. 예를들어 다른 디바이스를 구현할때와 같이 복수의 상호 배타적인 하위트리에서 기능적으로 동등한 모듈을 서술하기 위해 같은 이름을 사용하고 싶을 수 있습니다.
Song 네임스페이스를 입력하세요.

Namespaces

Android.bp 파일의 song_namespace {..} 문이 네임스페이스를 정의합니다. 예를 들어

soong_namespace {
    ...
}
...

device/google/bonito/Android.bp는 device/google/bonito 패키지 내에서 모듈 이름이 고유함을 Song에게 알립니다. 즉, device/google/bonito 트리의 Android.bp 파일에 정의된 모든 모듈이 고유 이름을 가지고 있습니다.
그러나 device/google/bonito 트리 외부에 동일한 이름의 모듈이 있을 수 있습니다. 실제로 "pixelstats-vendor" 모듈이 device/google/bonito/pixelstats 와 device/google/coral/pixelstats 양쪽 모두에 있습니다.

네임스페이스의 이름은 디렉터리의 경로입니다. 따라서 위의 예에서 네임스페이스의 이름은 device/google/bonito 입니다.

implicit global namespace는 전체적으로 소스 트리에 해당합니다. 이름이 비어 있습니다.

모듈 이름의 scope는 해당 이름을 포함하는 가장 작은 네임스페이스입니다. 소스 트리에 device/my 및 device/my/display 네임스페이스가 있다고 가정합니다. libfoo 모듈이 device/my/display/lib/Android.bp에 정의된 경우 해당 네임스페이스는 device/my/display입니다.

따라서 이름이 고유하다는 말은 모듈의 이름이 해당 범위 내에서 고유하다는 것을 의미합니다. 즉, "/scope:name"은 "//device/google/bonito:pixelstats-vendor"와 같이 globally unique한 모듈 참조입니다.
모듈의 네임스페이스 이름은 모듈의 패키지 이름과 다를 수 있습니다. libfoo는 장치/my/display 네임스페이스에 속하지만 장치/my/display/lib 패키지에 포함되어 있습니다.

Name Resolution

모듈 참조의 형식은 Sung이 모듈을 찾는 방법을 결정합니다.

"//scope:name" 양식의 global reference를 위해 Soong은 "scope"라는 네임스페이스가 있는지 확인한 다음 "name" 모듈이 포함되어 있는지 확인하고 사용합니다. Soong은 Android.bp 파일을 구문 분석할 때 처음에 "scope"에 "이름"이 하나만 있는지 확인합니다.

local reference는 "이름" 형식을 가지며, 이를 resolve하기 위해서는 하나 이상의 네임스페이스에서 모듈 "이름"을 찾는 것이 포함된다.

기본적으로 전역 네임스페이스에만 "name"이 검색됩니다(즉, 명시적으로 정의된 범위에 속하지 않는 모듈만 고려됨). song_namespace의 가져오기 특성을 사용하여 모듈을 찾을 위치를 지정할 수 있습니다. 예를 들어 device/google/bonito/Android.bp는 다음을 포함합니다.

soong_namespace {
    imports: [
        "hardware/google/interfaces",
        "hardware/google/pixel",
        "hardware/qcom/bootctrl",
    ],
}

"libpixelstats"에 대한 참조는 이 모듈이 hardware/google/pixel 네임스페이스에 있기 때문에 hardware/google/pixel/pixelstats/Android.bp 에 정의된 모듈로 확인됩니다.

makefile에 있는 modules를 참조하기.

makefile을 Android.bp 파일로 변환하는 동안,

Android 빌드는 Android.bp 및 Android.mk 파일을 섞어놓은 상태가 되며, Android.mk 파일에 정의된 모듈이 Android.bp 파일에 정의된 모듈을 참조할 수 있습니다.

예를 들어, Android.mk 파일에 정의된 바이너리가 Android.bp로 정의된 라이브러리를 dependency로 가질 수 있습니다.

Android.bp 파일에 정의되어 있고 글로벌 네임스페이스에 속하는 모듈은 추가 작업 없이 makefile에서 참조할 수 있습니다.

모듈이 명시적 네임스페이스에 속한 경우 네임스페이스의 이름을 PRODUCT_SONG_NAMESPACES 변수 값에 추가한 후에만 makefile에서 참조할 수 있습니다.

*주의할점
makefiles에는 네임스페이스 개념이 없으며 PRODUCT_SONG_NAMESPACES를 통해 동일한 모듈로 네임스페이스가 노출되면 Make failure가 발생할 수 있습니다.

예를 들어 device/google/bonito 및 device/google/coral 네임스페이스가 모두 노출되면 pixelstats-vendor 모듈의 대상이 두 개 표시되므로 Make failure가 실패합니다.

Visibility

모듈의 가시성 속성은 모듈을 다른 패키지에서 사용할 수 있는지 여부를 제어합니다. 모듈은 항상 동일한 패키지에 선언된 다른 모듈에서 볼 수 있습니다. 이것은 Bazel 가시성 메커니즘에 기초한다.

지정된 경우 가시성 속성에 하나 이상의 규칙이 포함되어야 합니다.

속성의 각 규칙은 다음 형식 중 하나여야 합니다.

  • ["//visibility:public"]
  • ["//visibility:private"]
    ...

Formatter

Soong은 gofmt와 유사한 Android.bp 파일의 표준 포맷터를 포함합니다. 현재 디렉터리에 있는 모든 Android.bp 파일을 재귀적으로 다시 포맷하려면

bpfmt -w .

표준 형식은 다중 요소 목록의 모든 요소 뒤에 새 줄인 4개의 공백 들여쓰기를 포함하며 목록과 지도에 항상 뒤에 오는 쉼표를 포함합니다.

Convert Android.mk files

androidmk Android.mk > Android.bp

이 도구는 변수, 모듈, 주석 및 일부 조건을 변환하지만 사용자 지정 Makefile 규칙, 복잡한 조건 또는 추가 포함은 손으로 변환해야 합니다.

Differences between Android.mk and Android.bp

Android.mk 파일은 여러개의 모듈이 같은 이름을 사용하는 경우가 있다.(예를 들어 정적 및 공유 라이브러리 버전 혹은 host 및 device 버전).
Android.bp 파일에는 모든 모듈이 고유한 이름을 가지고있어야 하지만 단일 모듈을 여러 변형으로 빌드할 수 있습니다. 예를들어 host_supported: true를 추가한다던가...
Androidmk 변환기는 충돌하는 여러 모듈을 생성하며, 이러한 모듈은 target: { android: { }, host: { } } blocks 안에 있는 차이점에 대해서 단일 모듈로 수동으로 풀어 줘야 합니다.

Conditionals

Soong은 고의적으로 Android.bp 파일에서 대부분의 조건문들을 지원하지 않는다. 빌드에서 대부분의 조건문을 제거하는 것을 추천합니다. 조건문을 제거하는 방법에 대한 몇 가지 예는 모범 사례를 참조하십시오.

Soong에서 native로 지원하는 대부분의 조건문들은 map 속성으로 변환된다. 모듈을 빌드할 때 맵의 특성 중 하나가 선택되고 모듈의 최상위 레벨에서 동일한 이름으로 특성에 값이 추가됩니다.

예를 들어, 아키텍처별 파일을 지원하려면 다음과 같이 하십시오.

cc_library {
    ...
    srcs: ["generic.cpp"],
    arch: {
        arm: {
            srcs: ["arm.cpp"],
        },
        x86: {
            srcs: ["x86.cpp"],
        },
    },
}

arm용 모듈을 제작할 때 generic.cpp 및 arm.cpp 소스가 구축됩니다. x86용으로 빌드할 때 generic.cpp 및 'x86.cpp' 소스가 구축된다.

Soong Config Variables

조건문이 포함된 vendor 모듈을 변환할 때, 간단한 조건문은
모듈 유형, 변수 및 가능한 값을 설명하는 songconfig* 모듈을 사용하여 Soong 구성 변수를 통해 지원될 수있습니다.

soong_config_module_type {
    name: "acme_cc_defaults",
    module_type: "cc_defaults",
    config_namespace: "acme",
    variables: ["board"],
    bool_variables: ["feature"],
    value_variables: ["width"],
    properties: ["cflags", "srcs"],
}

soong_config_string_variable {
    name: "board",
    values: ["soc_a", "soc_b", "soc_c"],
}

이 예에서는 cc_defaults 모듈 유형을 확장하는 새로운 acme_cc_defaults 모듈 유형을 설명합니다. 해당 모듈은 세가지 추가적인 조건
cflags 및 srcs 특성에 영향을 미칠 수 있는 변수 board, feature 및 width를 기반으로하는 세 가지 추가 조건을 가집니다.
또한 각 조건에는 conditions_default 속성은 다음과 같은 조건에서 cflags 및 srcs에 영향을 미칠 수 있습니다.

  • bool 변수(예: feature): 변수가 지정되지 않았거나 참 값으로 설정되지 않았습니다.
  • 값 변수(예: width): 변수가 지정되지 않음
  • 문자열 변수(예: board): 변수가 지정되지 않았거나 변수가 지정된 모듈에서 사용되지 않는 문자열로 설정되었습니다. 예를 들어, 보드의 경우 보드에 속성 soc_a와 conditions_default가 포함되어 있으면 board=soc_b일 때 cflags와 srcs 값이 conditions_default에 사용됩니다. soc_b에 대해 속성을 수정하지 않도록 지정하려면 soc_b: {}을(를) 설정하십시오.

변수의 값은 제품의 BoardConfig.mk 파일에서 설정할 수 있다.

$(call soong_config_set,acme,board,soc_a)
$(call soong_config_set,acme,feature,true)
$(call soong_config_set,acme,width,200)

acme_cc_defaults 모듈 유형은 정의된 파일의 정의 이후 어디서나 사용할 수 있으며 다음과 같은 기능을 가진 다른 파일로 가져올 수 있습니다.

soong_config_module_type_import {
    from: "device/acme/Android.bp",
    module_types: ["acme_cc_defaults"],
}

다른 모듈 유형처럼 사용할 수 있습니다.

acme_cc_defaults {
    name: "acme_defaults",
    cflags: ["-DGENERIC"],
    soong_config_variables: {
        board: {
            soc_a: {
                cflags: ["-DSOC_A"],
            },
            soc_b: {
                cflags: ["-DSOC_B"],
            },
            conditions_default: {
                cflags: ["-DSOC_DEFAULT"],
            },
        },
        feature: {
            cflags: ["-DFEATURE"],
            conditions_default: {
                cflags: ["-DFEATURE_DEFAULT"],
            },
        },
        width: {
            cflags: ["-DWIDTH=%s"],
            conditions_default: {
                cflags: ["-DWIDTH=DEFAULT"],
            },
        },
    },
}

cc_library {
    name: "libacme_foo",
    defaults: ["acme_defaults"],
    srcs: ["*.cpp"],
}

위의 BoardConfig.mk를 사용하여 libacme_foo는 cflags: "-DGENERIC -DSOC_A -DFEATURE -DWIDE=200"을 사용하여 빌드할 수 있다.

또는 DefaultBoardConfig.mk에서 다음을 수행합니다.

SOONG_CONFIG_NAMESPACES += acme
SOONG_CONFIG_acme += \
    board \
    feature \
    width \

SOONG_CONFIG_acme_feature := false

그런 다음 libacme_foo는 cflags "-DGENERIC -DSOC_DEFAULT -DFEATure_DEFAULT -DSIZE=DEFAULT"를 사용하여 빌드합니다.

또는 DefaultBoardConfig.mk에서 다음을 수행합니다.

SOONG_CONFIG_NAMESPACES += acme
SOONG_CONFIG_acme += \
    board \
    feature \
    width \

SOONG_CONFIG_acme_board := soc_c

그런 다음 libacme_foo는 cflags "-DGENERIC -DSOC_DEFAULT -DFEATure_DEFAULT -DSIZE=DEFAULT"를 사용하여 빌드합니다.

song_config_config_type 모듈은 기본 모듈(cc_config, java_type 등)을 래핑하는 데 사용할 때 가장 잘 작동하며 일반 네임스페이스 및 가시성 규칙을 사용하여 공급업체의 다른 모든 모듈에서 이 모듈을 참조할 수 있습니다.

Build logic

빌드 로직은 blueprint 프레임워크를 사용하여 Go로 작성됩니다. 빌드 로직은 reflection을 사용하여 Go 구조로 구문 분석된 모듈 정의를 수신하고 빌드 규칙을 생성합니다. 빌드 규칙은 Blueprint에 의해 수집되어 닌자 빌드 파일에 기록됩니다.

Developing for Soong

0개의 댓글