Android NDK와 함께 제공되는 도구 모음을 독립적으로 사용하거나 기존 IDE와 함께 플러그인으로 사용할 수 있습니다. 이러한 유연성은 자체 빌드 시스템이 이미 있는 상태에서 크로스 컴파일러 호출 기능 지원을 Android에 추가하려는 경우에 유용합니다.
도구 모음 선택
먼저 독립 실행형 도구 모음에서 타겟팅할 프로세서 아키텍처를 결정해야 합니다. --arch
플래그를 사용하면 됩니다.
sysroot 선택
다음으로 해야 할 일은 sysroot를 정의하는 것입니다. sysroot는 타겟의 시스템 헤더 및 라이브러리가 포함된 디렉터리입니다. sysroot를 정의하려면 네이티브 지원의 타겟이 될 Android API 수준을 알아야 합니다. 사용 가능한 네이티브 API는 Android API 수준에 따라 다릅니다.
각 Android API 수준의 네이티브 API 라이브러리는 $NDK/platforms/
아래에 있고 각 API 수준 디렉터리에는 여러 CPU 및 아키텍처용 하위 디렉터리가 포함되어 있습니다. 헤더는 $NDK/sysroot
에 있습니다.
Android API 수준 및 이러한 수준에서 지원하는 각 네이티브 API에 관한 자세한 내용은 네이티브 API를 참조하세요.
도구 모음 만들기
NDK는 명령줄에서 맞춤형으로 도구 모음을 설치할 수 있는 make_standalone_toolchain.py
스크립트를 제공합니다.
이 스크립트는 이전 make-standalone-toolchain.sh
를 대체하는 새로운 도구입니다. Windows 사용자가 이 도구를 실행하기 위해 Cygwin 또는 MSYS를 설치할 필요가 없도록 Python으로 다시 구현되었습니다.
스크립트는 $NDK/build/tools/
디렉터리에 있습니다. 여기서 $NDK
는 NDK의 설치 루트입니다.
이 스크립트는 다음 예와 같이 사용합니다.
$NDK/build/tools/make_standalone_toolchain.py \
--arch arm --api 21 --install-dir /tmp/my-android-toolchain
이 명령어를 실행하면 /tmp/my-android-toolchain/
이라는 디렉터리가 만들어지고, 이 디렉터리에 android-21/arch-arm
sysroot 사본과 32비트 ARM 타겟 도구 모음 바이너리 사본이 포함됩니다.
도구 모음 바이너리는 호스트별 경로에 종속되거나 호스트별 경로를 포함하지 않습니다. 즉, 이 바이너리를 어느 위치에나 설치할 수 있으며 필요한 경우 이동할 수도 있습니다.
--arch
인수는 필수이지만 API 수준은 지정된 아키텍처에 지원되는 최소 수준으로 기본 설정됩니다(현재 32비트 아키텍처의 경우 16, 64비트 아키텍처의 경우 21).
r18부터 모든 독립 실행형 도구 모음은 Clang 및 libc++를 사용합니다. 정적 실행 파일을 빌드하지 않는 경우 기본적으로 libc++ 공유 라이브러리가 사용됩니다. 정적 라이브러리 사용을 강제 적용하려면 연결할 때 -static-libstdc++
를 전달하세요. 이 동작은 일반 호스트 도구 모음의 동작과 일치합니다.
C++ 라이브러리 지원에서 언급한 대로 libc++에 연결할 때는 종종 -latomic
를 전달해야 합니다.
--install-dir
옵션을 생략하는 경우 도구는 이름이 $TOOLCHAIN_NAME.tar.bz2
인 현재 디렉터리에 tarball을 만듭니다. tarball은 --package-dir
을 사용하여 다른 디렉터리에 배치할 수 있습니다.
더 많은 옵션 및 세부정보를 보려면 --help
를 사용합니다.
Clang 사용하기
Clang 바이너리는 자동으로 독립 실행형 도구 모음에 포함됩니다.
또한 <install-dir>/bin
아래에 이름이 clang
및 clang++
인 2개의 래퍼 스크립트가 있습니다. 이러한 스크립트는 올바른 타겟 아키텍처 플래그가 있는 clang
바이너리를 호출합니다. 다시 말해, 이 두 스크립트는 어떤 수정 없이도 작동해야 하며 이 스크립트를 가리키도록 CC
및 CXX
환경 변수를 설정하기만 하면 자체 빌드에서 이 스크립트를 사용할 수 있어야 합니다.
또한 Clang을 호출하는 gcc
및 g++
라는 래퍼 스크립트가 있습니다.
NDK에 GCC가 없더라도 GCC를 명시적으로 참조하는 빌드 파일에 일정 수준의 호환성을 제공하기 위한 것입니다. 물론 빌드 파일이 Clang에서 지원되지 않는 명령줄 옵션을 사용하는 경우 옵션을 삭제하거나 바꿔야 합니다.
ARM을 사용한 Clang 타겟
ARM용으로 빌드할 때 Clang은 -march=armv7-a
또는 -mthumb
컴파일러 플래그가 있는지에 따라 타겟을 변경합니다.
표 1. 지정할 수 있는 -march
값 및 결과 타겟
-march 값 |
결과 타겟 |
---|---|
-march=armv7-a |
armv7-none-linux-androideabi |
-mthumb |
thumb-none-linux-androideabi |
-march=armv7-a 및 -mthumb 모두 |
thumbv7-none-linux-androideabi |
원한다면 자체 -target
을 사용하여 재정의할 수도 있습니다.
clang
및 clang++
는 makefile에서 gcc
및 g++
드롭인 교체여야 합니다. 확실하지 않다면 컴파일러를 호출할 때 다음 옵션을 사용하여 올바르게 작동하는지 확인합니다.
-v
: 컴파일러 드라이버 문제와 연결된 명령어 덤프하기-###
: 암시적으로 사전 정의된 옵션을 포함한 명령줄 옵션 덤프하기-x c < /dev/null -dM -E
: 사전 정의된 전처리기 정의 덤프하기-save-temps
:*.i
또는*.ii
전처리된 파일 비교하기
ABI 호환성
기본적으로 ARM Clang 독립 실행형 도구 모음은 armeabi-v7a ABI를 타겟팅합니다.
이 타겟은 적절한 -march
또는 -target
옵션을 전달하여 재정의할 수 있습니다.
-mthumb
컴파일러 플래그를 사용하여 16비트 Thumb-2 명령 생성을 강제 적용하는 것이 좋습니다. 생략하는 경우 도구 모음에서 32비트 ARM 명령을 내보냅니다.
NEON 명령을 사용하려면 -mfpu
컴파일러 플래그인 -mfpu=neon
을 사용해야 합니다.
이렇게 설정하면 ARM 사양에 따라 VFPv3-D32
사용이 강제 적용됩니다.
또한 다음 두 플래그 -march=armv7-a -Wl,--fix-cortex-a8
도 링커에 제공해야 합니다.
첫 번째 플래그는 링커가 armv7-a에 맞춤화된 도구 모음 라이브러리를 선택하도록 지시합니다. 두 번째 플래그는 일부 Cortex-A8 구현의 CPU 버그 해결 방법으로 필요합니다.
다른 ABI를 타겟팅할 때는 특정 컴파일러 플래그를 사용할 필요가 없습니다.
ABI 지원에 관해 자세히 알아보려면 Android ABI를 참고하세요.
경고 및 제한사항
Windows 지원
Windows 바이너리는 Cygwin에 의존하지 않습니다. 이러한 종속 항목이 없으므로 속도가 더 빠릅니다. 하지만 C:/foo/bar
와는 반대로 cygdrive/c/foo/bar
같은 Cygwin 경로 사양을 파악할 수 없다는 단점이 있습니다.
예외, RTTI, STL
도구 모음 바이너리는 기본적으로 C++ 예외 및 RTTI를 지원합니다. 소스를 빌드할 때(예를 들어 좀 더 가벼운 기계어 코드를 생성하기 위해) C++ 예외 및 RTTI를 사용 중지하려면 -fno-exceptions
및 -fno-rtti
를 사용합니다.
C++ STL 지원
독립 실행형 도구 모음에는 C++ 표준 템플릿 라이브러리(STL) 구현이 포함되어 있습니다.
-static-libstdc++
를 사용하여 libc++의 정적 라이브러리 버전을 가져옵니다. 이렇게 하면 필요한 모든 C++ STL 코드가 최종 바이너리에 포함됩니다. 이 방법은 단일 공유 라이브러리나 실행 파일만 생성하려는 경우에 적합하며 권장되는 방법입니다.기본적으로 libc++의 공유 라이브러리 버전이 사용됩니다. 이 공유 라이브러리에 연결하기 위해 추가 플래그는 필요하지 않습니다.
libc++_shared.so
를 앱에 패키징해야 합니다. 그러지 않으면 코드가 로드되지 않습니다.표 2는 아키텍처별로 이 파일의 위치를 보여줍니다.
표 2. 지정할 수 있는
-march
값 및 결과 타겟도구 모음 위치 arm $TOOLCHAIN/arm-linux-androideabi/lib/
arm64 $TOOLCHAIN/aarch64-linux-android/lib/
x86 $TOOLCHAIN/i686-linux-android/lib/
x86_64 $TOOLCHAIN/x86_64-linux-android/lib/
독립 실행형 도구 모음을 사용하여 오픈소스 프로젝트 빌드
다음 도구 모음을 예로 들겠습니다.
# Create an arm64 API 26 libc++ toolchain.
$NDK/build/tools/make_standalone_toolchain.py \
--arch arm64 \
--api 26 \
--install-dir=my-toolchain
이 도구 모음을 사용하여 기존 오픈소스 프로젝트를 빌드하도록 환경을 설정하는 방법은 다음과 같습니다.
# Add the standalone toolchain to the search path.
export PATH=$PATH:`pwd`/my-toolchain/bin
# Tell configure what tools to use.
target_host=aarch64-linux-android
export AR=$target_host-ar
export AS=$target_host-clang
export CC=$target_host-clang
export CXX=$target_host-clang++
export LD=$target_host-ld
export STRIP=$target_host-strip
# Tell configure what flags Android requires.
export CFLAGS="-fPIE -fPIC"
export LDFLAGS="-pie"
맞춤 빌드 시스템을 사용하는 프로젝트
예를 들어 이전 단계를 진행한 후 toybox를 빌드하는 방법은 다음과 같습니다.
git clone https://github.com/landley/toybox.git
cd toybox
make defconfig && make
autoconf를 사용하는 프로젝트
autoconf 기반 프로젝트는 다음과 같이 표시됩니다.
tar zxvf make-4.2.tar.gz
cd make-4.2
./configure --host=$target_host && make
autoconf 기반 프로젝트는 크로스 컴파일 지원이 매우 다양합니다. 또한 autoconf 기반 프로젝트를 git clone
처리한다면 체크인된 configure
스크립트가 있을 가능성이 낮습니다. 따라서 프로젝트의 문서에 따라 부트스트랩해야 합니다.