您可以單獨使用 Android NDK 提供的工具鏈,也可以將此工具鏈做為外掛程式與現有 IDE 搭配使用。如果您已經有自己的建構系統,而且只需要叫用跨平台程式碼編譯器,以便為其新增對 Android 的支援,這樣的靈活彈性便對您很有幫助。
選取您的工具鏈
首先,您需要決定獨立工具鏈的目標處理器架構。您可以使用 --arch
旗標完成這項操作。
選取您的 sysroot
接下來,您需要定義 sysroot。sysroot 是包含目標系統標頭和程式庫的目錄。如要定義 sysroot,您必須知道原生支援的目標 Android API 級別;具體可用的原生 API 會因 Android API 級別而異。
$NDK/platforms/
下有不同 Android API 級別的原生 API 程式庫;每個 API 級別目錄包含不同 CPU 和架構的子目錄。標頭位於 $NDK/sysroot
中。
如要進一步瞭解 Android API 級別,以及各級別支援的對應原生 API,請參閱原生 API。
建立工具鏈
NDK 提供 make_standalone_toolchain.py
指令碼,可讓您透過指令列執行自訂工具鏈的安裝作業。
這是用於取代舊版 make-standalone-toolchain.sh
的新工具。此工具已在 Python 中重新實作,因此 Windows 使用者不需安裝 Cygwin 或 MSYS,即可使用這個工具。
指令碼位於 $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。您可以使用 --package-dir
將 tarball 放入其他目錄。
如需瞭解更多選項和相關詳細資訊,請使用 --help
。
使用 Clang
獨立工具鏈中會自動加入 Clang 二進位檔。
在 <install-dir>/bin
下另有兩個名為 clang
和 clang++
的包裝函式指令碼。這些指令碼會叫用具有正確目標架構旗標的 clang
二進位檔。也就是說,這些指令碼不需要任何修改就能運作,而且只要設定它們的 CC
和 CXX
環境變數,應該就能在建構作業中使用這些指令碼。
此外,名為 gcc
和 g++
的包裝函式指令碼也會呼叫 Clang。
雖然 NDK 不再包含 GCC,但是這些指令碼還是會在一定程度上與明確參照 GCC 的建構檔案相容。很明顯地,如果建構檔案使用 Clang 不支援的指令列選項,您必須移除或替換這些選項。
Clang 以 ARM 為目標
為 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。這種沒有依附元件的特性讓此類檔案的執行速度更快。然而,代價是 Windows 二進位檔無法像理解 C:/foo/bar
一樣,理解 Cygwin 路徑規範 (例如 cygdrive/c/foo/bar
)。
例外狀況、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 為基礎的專案在支援跨平台程式碼編譯方面有極大的差異。另請注意,如果您 git clone
以 autoconf 為基礎的專案,則這個專案中不太可能有已簽入的 configure
指令碼,因此,請參閱專案的說明文件,以便瞭解如何啟動。