d8

d8은 Android 스튜디오와 Android Gradle 플러그인에서 프로젝트의 자바 바이트 코드를 Android 기기에서 실행되는 DEX 바이트 코드로 컴파일하는 데 사용하는 명령줄 도구입니다. d8을 통해 앱 코드에서 자바 8 언어 기능을 사용할 수 있습니다.

d8은 Android 빌드 도구 28.0.1 이상에 독립형 도구로도 포함됩니다(android_sdk/build-tools/version/).

일반 사용법

d8에는 DEX 바이트 코드로 변환하려는 컴파일된 자바 바이트 코드의 경로만 필요합니다. 예를 들면 다음과 같습니다.

d8 MyProject/app/build/intermediates/classes/debug/*/*.class

입력 바이트 코드는 *.class 파일 또는 컨테이너(예: JAR, APK 또는 ZIP 파일)의 어떤 조합이든 가능합니다. d8의 DEX 파일을 포함하여 DEX 출력으로 병합할 수도 있으며 이는 증분 빌드의 출력을 포함할 때 유용합니다.

기본적으로 d8은 자바 바이트 코드를 최적화된 DEX 파일로 컴파일하고 런타임 중에 코드를 디버그하는 데 사용할 수 있는 디버그 정보를 포함합니다. 그러나 증분 빌드를 실행하고 기본 DEX 파일로 컴파일해야 하는 클래스를 지정하며 자바 8 언어 기능을 사용하는 데 필요한 추가 리소스 경로를 지정하는 작업을 위해 선택적 플래그를 포함할 수 있습니다.

d8 path-to-input-files [options]

다음 표에서는 d8과 함께 사용할 수 있는 선택적 플래그를 설명합니다.

옵션 설명
--debug

디버그 기호 표 등 디버그 정보를 포함하도록 DEX 바이트 코드를 컴파일합니다.

이 옵션은 기본적으로 사용 설정됩니다. DEX 바이트 코드에 디버그 정보를 포함하기 위해 d8은 입력 자바 바이트 코드에 디버그 정보가 포함되어 있다고 예상합니다. 예를 들어 javac를 사용하여 코드를 컴파일한다면 -g 플래그를 전달하여 출력 자바 바이트 코드에 디버그 정보를 포함해야 합니다.

앱 또는 라이브러리의 출시 버전용 DEX 파일을 컴파일할 때는 --release 플래그를 대신 사용하세요.

--release

디버그 정보 없이 DEX 바이트 코드를 컴파일합니다. 그러나 d8에는 스택 트레이스를 생성하고 예외를 로깅할 때 사용되는 정보가 포함되어 있습니다.

공개 버전의 바이트 코드를 컴파일할 때 이 플래그를 전달하세요.

--output path

원하는 DEX 출력의 경로를 지정합니다. 기본적으로 d8은 DEX 파일을 현재 작업 디렉터리에 출력합니다.

ZIP 또는 JAR 파일의 경로와 이름을 지정하면 d8은 지정된 파일을 만들고 출력 DEX 파일을 포함합니다. 기존 디렉터리의 경로를 지정하면 d8에서 그 디렉터리의 DEX 파일을 출력합니다.

--lib android_sdk/platforms/api-level/android.jar Android SDK의 android.jar 경로를 지정합니다. 이 플래그는 자바 8 언어 기능을 사용하는 바이트 코드를 컴파일할 때 필요합니다.
--classpath path d8에서 프로젝트의 DEX 파일을 컴파일하는 데 필요할 수 있는 클래스 경로 리소스를 지정합니다. 특히 d8에서는 자바 8 언어 기능을 사용하는 바이트 코드를 컴파일할 때 특정 리소스를 지정해야 합니다.
--min-api number 출력 DEX 파일이 지원할 최소 API 수준을 지정합니다.
--intermediate 이 플래그를 전달하여 프로젝트의 자바 바이트 코드 전체 세트를 컴파일하지 않는다고 d8에 알립니다. 이 플래그는 증분 빌드를 실행할 때 유용합니다. 기기에서 실행될 것으로 예상되는 최적화된 DEX 파일을 컴파일하는 대신 d8은 중간 DEX 파일을 만들어 지정된 출력 또는 기본 경로에 저장합니다.

기기에서 실행하려는 DEX 파일을 컴파일하려면 이 플래그를 제외하고 중간 DEX 클래스의 경로를 입력으로 지정하세요.

--file-per-class

각 클래스를 별도의 DEX 파일로 컴파일합니다.

이 플래그를 사용 설정하면 변경된 클래스만 다시 컴파일하여 증분 빌드를 더 실행할 수 있습니다. Android Gradle 플러그인을 사용하여 증분 빌드를 실행하는 경우 이 최적화가 기본적으로 사용 설정됩니다.

--main-dex-list도 지정하면서 이 플래그를 사용할 수는 없습니다.

--no-desugaring 자바 8 언어 기능을 사용 중지합니다. 자바 8 언어 기능을 사용하는 자바 바이트 코드를 컴파일하지 않으려는 경우에만 이 플래그를 사용하세요.
--main-dex-list path

d8에서 기본 DEX 파일에 포함해야 하는 클래스가 나열된 텍스트 파일을 지정합니다. 보통 이 파일의 이름은 classes.dex입니다. 이 플래그를 사용하여 클래스 목록을 지정하지 않으면 d8은 기본 DEX 파일에 포함되는 클래스를 보장하지 않습니다.

앱을 시작할 때 Android 시스템이 기본 DEX 파일을 먼저 로드하기 때문에 이 플래그를 사용하여 시작 시 특정 클래스를 기본 DEX 파일로 컴파일하여 우선순위를 정할 수 있습니다. 이 옵션은 기존 멀티덱스 라이브러리가 로드될 때까지 런타임에 기본 DEX 파일의 클래스만 사용할 수 있기 때문에 기존 멀티덱스를 지원하는 경우 특히 유용합니다.

각 DEX 파일은 여전히 64K 참조 제한을 충족해야 합니다. 따라서 기본 DEX 파일에 클래스를 너무 많이 지정하지 마세요. 너무 많은 클래스를 지정하면 컴파일 오류가 발생합니다. 기본적으로 --main-dex-list를 사용하여 클래스를 지정하면 d8은 기본 DEX 파일에 이러한 클래스만 포함합니다. 이는 기본 DEX 파일에서 누락된 클래스와 관련된 문제를 더 쉽게 디버그하기 위한 것입니다. --release 모드를 지정하면 d8에서는 64K 제한에 도달할 때까지 최대한 많은 다른 클래스를 기본 DEX 파일에 포함하여 앱의 출시 버전으로 패키징된 DEX 파일의 수를 줄이려고 합니다.

--file-per-class도 지정하면서 이 플래그를 사용할 수는 없습니다.

--pg-map file file을 배포용 매핑 파일로 사용합니다.
--file-per-class-file

입력 .class 파일마다 별도의 DEX 파일을 생성합니다.

합성 클래스를 원래 클래스와 함께 유지합니다.

--desugared-lib file

디슈가링된 라이브러리 구성을 지정합니다.

file은 JSON 형식의 디슈가링된 라이브러리 구성 파일입니다.

--main-dex-rules file Proguard는 기본 DEX 파일에 배치할 클래스에 관한 규칙을 유지합니다.
--main-dex-list-output file file에 결과 기본 DEX 목록을 출력합니다.

--force-enable-assertions [:class_or_package_name...]

--force-ea [:class_or_package_name...]

javac에서 생성된 어설션 코드를 강제로 사용 설정합니다.

--force-disable-assertions [:class_or_package_name...]

--force-da [:class_or_package_name...]

javac에서 생성된 어설션 코드를 강제로 사용 중지합니다. 이는 DEX 파일을 생성할 때 javac 어설션 코드에 관한 기본 처리입니다.

--force-passthrough-assertions [:class_or_package_name...]

--force-pa [:class_or_package_name...]

javac에서 생성된 어설션 코드를 변경하지 마세요. 이는 class 파일을 생성할 때 javac 어설션 코드에 관한 기본 처리입니다.

--force-assertions-handler:handler method [:class_or_package_name...]

--force-ah:handler method [:class_or_package_name...]

각 어설션 오류를 발생시키는 대신 이러한 오류와 함께 handler method 메서드를 호출하도록 javackotlinc에서 생성된 어설션 코드를 변경합니다. handler method는 클래스 이름으로 지정되며 점과 메서드 이름이 그다음에 옵니다. 핸들러 메서드는 java.lang.Throwable 유형의 단일 인수를 사용하고 반환 유형이 void여야 합니다.
--thread-count number of threads 컴파일에 사용할 스레드 수를 지정합니다. 지정하지 않으면 코어 수를 고려하여 휴리스틱을 기반으로 지정됩니다.
--map-diagnostics[ :type] from-level to-level from-level로 보고된 type(기본값)의 진단을 to-level에 매핑합니다. 여기서 from-levelto-level은 'info', 'warning', 또는 'error' 중 하나이고 선택적 type은 진단의 단순 또는 정규화된 자바 유형 이름입니다. type을 지정하지 않으면 from-level의 모든 진단이 매핑됩니다. 치명적인 컴파일러 오류는 매핑할 수 없습니다.
--version 현재 사용하는 d8의 버전을 출력합니다.
--help d8 사용을 위한 도움말 텍스트를 출력합니다.

증분 빌드 실행

지속적 통합 빌드의 경우와 같이 개발하는 동안 빌드 속도를 향상시키려면 d8에서 프로젝트의 자바 바이트 코드 하위 집합만 컴파일하도록 하세요. 예를 들어 클래스당 덱싱을 사용 설정하면 이전 빌드 이후에 수정한 클래스만 다시 컴파일할 수 있습니다.

다음 명령어는 클래스의 증분 빌드를 실행하고 클래스당 덱싱을 사용 설정합니다. 증분 빌드를 위한 출력 디렉터리도 지정합니다.

d8 MainActivity.class R.class --intermediate --file-per-class --output ~/build/intermediate/dex

d8은 증분 빌드를 실행할 때 추가 정보를 DEX 출력에 저장합니다. 나중에 d8은 이 정보를 사용하여 --main-dex-list 옵션을 올바르게 처리하고 앱을 전체 빌드하는 동안 DEX 파일을 병합합니다.

예를 들어 d8은 자바 8 람다 클래스를 처리할 때 각 입력 클래스에 어떤 람다 클래스가 생성되는지 추적합니다. 전체 빌드 중에 d8에서 기본 DEX 파일에 클래스를 포함한다면 메타데이터를 참조하여 이 클래스에 만들어진 모든 람다 클래스가 기본 DEX 파일에도 포함되어 있는지 확인합니다.

이미 여러 증분 빌드에 걸쳐 프로젝트의 모든 바이트 코드를 DEX 파일로 컴파일한 경우 다음 명령어와 같이 중간 DEX 파일의 디렉터리를 d8에 전달하여 전체 빌드를 실행합니다. 또한 --main-dex-list를 사용하여 d8이 기본 DEX 파일로 컴파일할 클래스를 지정할 수 있습니다. 이미 DEX 바이트 코드로 컴파일된 파일의 집합이 입력이므로 이 빌드는 클린 빌드보다 더 빠르게 완료됩니다.

d8 ~/build/intermediate/dex --release --main-dex-list ~/build/classes.txt --output ~/build/release/dex

자바 8 언어 기능을 사용하는 바이트 코드 컴파일

d8을 사용하면 디슈가링이라고 하는 컴파일 프로세스를 통해 코드에서 자바 8 언어 기능을 사용할 수 있습니다. 디슈가링은 이러한 유용한 언어 기능을 Android 플랫폼에서 실행할 수 있는 바이트 코드로 변환합니다.

Android 스튜디오와 Android Gradle 플러그인에는 d8에서 디슈가링을 사용 설정하는 데 필요한 클래스 경로 리소스가 포함되어 있습니다. 그러나 명령줄에서 d8을 사용할 때는 이 리소스를 직접 포함해야 합니다.

이러한 리소스 중 하나는 타겟 Android SDK의 android.jar입니다. 이 리소스에는 Android 플랫폼 API의 집합이 포함됩니다. --lib 플래그를 사용하여 경로를 지정하세요.

또 다른 리소스는 현재 DEX 바이트 코드로 컴파일하지 않지만 다른 클래스를 DEX 바이트 코드로 컴파일해야 하는 프로젝트에 컴파일된 자바 바이트 코드 집합입니다.

예를 들어 코드에서 자바 8 언어 기능인 기본 및 정적 인터페이스 메서드를 사용하는 경우 프로젝트의 모든 자바 바이트 코드를 DEX 바이트 코드로 컴파일하지 않더라도 이 플래그를 사용하여 프로젝트의 모든 자바 바이트 코드의 경로를 지정해야 합니다. d8에서 프로젝트의 코드를 이해하고 인터페이스 메서드 호출을 확인하는 데 이 정보가 필요하기 때문입니다.

다음 코드 샘플에서는 기본 인터페이스 메서드에 액세스하는 클래스의 증분 빌드를 실행합니다.

d8 MainActivity.class --intermediate --file-per-class --output ~/build/intermediate/dex
--lib android_sdk/platforms/api-level/android.jar
--classpath ~/build/javac/debug