64비트 빌드 이해

빌드 시스템은 동일한 빌드에서 두 개의 타겟 CPU 아키텍처(64비트 및 32비트)에 관한 바이너리 빌드를 지원하며, 이를 multilib 빌드라고 합니다.

네이티브 정적 라이브러리와 공유 라이브러리의 경우 빌드 시스템에서 두 아키텍처를 위한 바이너리를 빌드합니다. 제품 구성(PRODUCT_PACKAGES)은 종속성 그래프와 함께 어떤 바이너리를 시스템 이미지에 빌드하고 설치할지 결정합니다.

실행 파일 및 앱의 경우 빌드 시스템은 기본적으로 64비트 버전만 빌드하지만, 전역 BoardConfig.mk 변수 또는 모듈 범위 변수로 이 설정을 재정의할 수 있습니다.

제품 구성

BoardConfig.mk에는 두 번째 CPU 아키텍처 및 ABI를 구성하기 위한 다음 변수가 포함되어 있습니다.

  • TARGET_2ND_ARCH
  • TARGET_2ND_ARCH_VARIANT
  • TARGET_2ND_CPU_VARIANT
  • TARGET_2ND_CPU_ABI
  • TARGET_2ND_CPU_ABI2

build/target/board/generic_arm64/BoardConfig.mk에서 예시를 확인할 수 있습니다.

빌드 시스템에서 32비트 실행 파일과 앱을 기본으로 빌드하고 싶은 경우 다음 변수를 설정합니다.

TARGET_PREFER_32_BIT := true

Android.mk에서 모듈별 변수를 사용하여 이 설정을 재정의할 수 있습니다.

빌드 시스템에 의해 정의된 이상 multilib 빌드에서는 PRODUCT_PACKAGES의 모듈 이름이 32비트 및 64비트 바이너리 둘 다에 적용됩니다. 종속성에 의해 풀링된 라이브러리의 경우 다른 32비트 라이브러리 또는 실행 파일에서 요구하는 경우에만 32비트 라이브러리가 설치됩니다. 이는 64비트 라이브러리의 경우에도 마찬가지입니다.

하지만 make 명령줄의 모듈 이름은 64비트 버전에만 적용됩니다. 예를 들어 lunch aosp_arm64-eng를 실행한 후 make libc는 64비트 libc만 빌드합니다. 32비트 libc를 빌드하려면 make libc_32를 실행해야 합니다.

Android.mk의 모듈 정의

LOCAL_MULTILIB 변수를 사용하여 32비트/64비트용 빌드를 구성하고 전역 TARGET_PREFER_32_BIT 변수를 재정의할 수 있습니다.

LOCAL_MULTILIB를 다음 중 하나로 설정합니다.

  • "both"는 32비트와 64비트를 모두 빌드합니다.
  • "32"는 32비트만 빌드합니다.
  • "64"는 64비트만 빌드합니다.
  • "first"는 첫 번째 아키텍처(32비트 기기의 32비트 및 64비트 기기의 64비트)에 대해서만 빌드됩니다.
  • 기본값은 ""입니다. 빌드 시스템은 모듈 클래스 및 LOCAL_MODULE_TARGET_ARCH, LOCAL_32_BIT_ONLY와 같은 기타 LOCAL_ 변수를 기준으로 어떤 아키텍처를 빌드할지 결정합니다.

특정 아키텍처용 모듈을 빌드하려면 다음 변수를 사용합니다.

  • LOCAL_MODULE_TARGET_ARCH
    이 변수를 arm x86 arm64와 같은 아키텍처 목록으로 설정합니다. 빌드 중인 아키텍처가 목록에 있으면 현재 모듈이 빌드 시스템에 포함됩니다.
  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH
    이 변수는 LOCAL_MODULE_TARGET_ARCH의 반대입니다. 빌드 중인 아키텍처가 목록에 없으면 현재 모듈이 빌드 시스템에 포함됩니다.

이러한 두 변수의 보조 변형이 있습니다.

  • LOCAL_MODULE_TARGET_ARCH_WARN
  • LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH_WARN

나열된 아키텍처로 인해 현재 모듈을 건너뛰면 빌드 시스템이 경고를 표시합니다.

특정 아키텍처에 관해 빌드 플래그를 설정하려면 아키텍처별 LOCAL_ 변수를 사용하세요. 아키텍처별 LOCAL_ 변수는 아키텍처 접미사가 있는 일반적인 LOCAL_ 변수입니다. 예를 들면 다음과 같습니다.

  • LOCAL_SRC_FILES_arm, LOCAL_SRC_FILES_x86,
  • LOCAL_CFLAGS_arm, LOCAL_CFLAGS_arm64,
  • LOCAL_LDFLAGS_arm, LOCAL_LDFLAGS_arm64,

이러한 변수는 아키텍처에 관해 현재 바이너리를 빌드 중인 경우에만 적용됩니다.

빌드 중인 바이너리가 32비트용인지 64비트용인지에 따라 플래그를 설정하는 것이 더 쉬운 경우도 있습니다. LOCAL_ 변수를 _32 또는 _64 접미사와 함께 사용하세요. 예를 들면 다음과 같습니다.

  • LOCAL_SRC_FILES_32, LOCAL_SRC_FILES_64,
  • LOCAL_CFLAGS_32, LOCAL_CFLAGS_64,
  • LOCAL_LDFLAGS_32, LOCAL_LDFLAGS_64,

경로 설치

전에는 LOCAL_MODULE_PATH를 사용하여 라이브러리를 기본 위치가 아닌 곳에 설치할 수 있었습니다. 예: LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw

Multilib 빌드에서는 대신 LOCAL_MODULE_RELATIVE_PATH를 사용합니다.

LOCAL_MODULE_RELATIVE_PATH := hw

이 형식에서는 64비트 및 32비트 라이브러리가 모두 올바른 위치에 설치됩니다.

실행 파일을 32비트와 64비트 둘 다로 빌드하는 경우 다음 변수 중 하나를 사용하여 설치 경로를 구별합니다.

  • LOCAL_MODULE_STEM_32, LOCAL_MODULE_STEM_64
    설치된 파일 이름을 지정합니다.
  • LOCAL_MODULE_PATH_32, LOCAL_MODULE_PATH_64
    설치 경로를 지정합니다.

생성된 소스

Multilib 빌드에서 $(local-intermediates-dir)(또는 명시적 변수를 사용하여 $(intermediates-dir-for))에 소스 파일을 생성하면 안정적으로 작동하지 않습니다. 중간에 생성된 소스가 32비트 및 64비트 빌드 모두에 필요하지만 $(local-intermediates-dir)은 두 중간 디렉터리 중 하나만 가리키기 때문입니다.

빌드 시스템은 소스를 생성하기 위한 multilib 친화적인 전용 중간 디렉터리를 제공합니다. $(local-generated-sources-dir) 또는 $(generated-sources-dir-for)를 호출하여 디렉터리 경로를 가져올 수 있습니다. 사용 방식은 $(local-intermediates-dir)$(intermediates-dir-for)와 유사합니다.

소스 파일이 이 전용 디렉터리에 생성되고 LOCAL_GENERATED_SOURCES에 의해 선택되면 multilib 빌드에서 32비트와 64비트 모두에 대해 빌드됩니다.

사전 빌드

multilib 빌드에서는 사전 빌드된 바이너리가 타겟팅하는 아키텍처가 무엇인지를 빌드 시스템에 알려주기 위해 TARGET_ARCH(또는 TARGET_2ND_ARCH와 함께)를 사용할 수 없습니다. 대신 LOCAL_ 변수인 LOCAL_MODULE_TARGET_ARCH 또는 LOCAL_MODULE_UNSUPPORTED_TARGET_ARCH를 사용하세요.

이러한 변수가 있으면 64비트 multilib 빌드를 진행 중인 경우에도 빌드 시스템에서 해당하는 32비트 사전 빌드된 바이너리를 선택할 수 있습니다.

선택한 아키텍처를 사용하여 사전 빌드된 바이너리의 소스 경로를 계산하려면 $(get-prebuilt-src-arch)를 호출하세요.

ODEX 파일 생성

64비트 기기의 경우 기본적으로 부팅 이미지 및 모든 자바 라이브러리를 위한 32비트 및 64비트 ODEX 파일이 생성됩니다. APK의 경우 기본적으로 주 64비트 아키텍처용 ODEX만 생성됩니다. 앱이 32비트 및 64비트 프로세스 모두에서 실행되는 경우 LOCAL_MULTILIB := both를 사용하여 32비트 및 64비트 ODEX 파일이 모두 생성되었는지 확인합니다. 앱에 32비트 또는 64비트 JNI 라이브러리가 있는 경우 플래그는 빌드 시스템에 이러한 라이브러리를 포함하도록 지시합니다.