我們經常需將一些C/C++源碼編譯成本地二進制,直接在android的linux內核上運行,這是就需要進行交叉編譯。由於Android的運行環境核普通Linux又區別,所以常規方式針對ARM進行交叉編譯得到的二進制,無法直接運行在Android環境上。我們需要機遇Android環境進行交叉編譯,這時有兩種方式:一種是編寫Android.mk,在安卓源碼結構下依靠安卓的編譯系統搞定;另一種方式是脫離android源碼體系,利用獨立的android交叉編譯工具鏈,並適當修改目標代碼的Makefile(必要時還要修改源碼)完成交叉編譯。第一種方式適用於編譯目標源碼結構簡單的情況;當目標源碼的Makefile組織非常複雜的時候,第二種方式則是更好的選擇。本文介紹第二種方式,即搭建Android獨立交叉編譯環境,編譯出可以在Android(默認基於ARM64)上運行的二進制(ELF)程序。
1、NDK下載
https://developer.android.google.cn/ndk/downloads/index.html
https://developer.android.google.cn/ndk/downloads/
本文以宿主機系統MacOS爲例,所以下載MacOSX版本的ndk包
2、利用NDK安裝android交叉編譯工具鏈
解壓NDK後,進入buildtools目錄
NickPro:android-ndk-r14b nickyang$ cd build/tools/
NickPro:tools nickyang$ pwd
/Users/nickyang/android-ndk-r14b/build/tools
NDK提供了兩個腳步用於一鍵化構建gcc工具鏈:
make-standalone-toolchain.sh
make_standalone_toolchain.py
我們使用py版本的,按照官方說明,sh版本將被淘汰
./make_standalone_toolchain.py --arch arm64 --api 24 --unified-headers --install-dir ~/android-build
參數解釋:
—arch : 交叉編譯目標平臺
--unified-header: 使用libc頭文件,相關解釋可參考:
Https://android.googlesource.com/platform/ndk.git/+/ndk-r14-release/docs/UnifiedHearders.md
—api: Android系統版本
--install-dir:生成的交叉編譯工具鏈輸出位置,可自行設置
3、編譯方法
通常類Unix系統下,C/C++源碼都是通過Makefile組織的(或者通過一個configure腳本生成Makefile),所以我們要閱讀其Makefile(或configure腳步),將其編譯器指定爲我們的android交叉編譯器,然後在編譯過程中會遇到一下函數爲定義等錯誤,這是因爲andorid的bionic C庫和純Linux的C庫差別導致的,比如某些函數在bionic中不支持,對這些函數,將其幹掉或者替換,或者自己重寫,等等。下面總結下通常要做的幾點:
1)查看目標源碼的Makefile文件,將交叉編譯器指定爲咱們安裝的交叉編譯器
通常是修改CC環境變量
CC= /path_to_your_cross_compiler/you_cross_compiler_xxx_gcc
2)CFLAGS加上“-pie -fPIE”選項,否則報錯:
error: only position independent executables (PIE) are supported
3) 一下編譯參數不支持,要去掉
#PTHREAD_LIBS= -lpthread -lrt
4、小試牛刀
新建一個hello.c文件:
#include <stdio.h>
int main(void)
{
printf("Hello, this is a program compiled by ndk-cross-compiler!\n");
}
編譯:
/Users/nickyang/android-build/bin/aarch64-linux-android-gcc -pie -fPIE hello.c -o hello
推送到android設備並執行(默認是ARM64架構):
NickPro:tmp nickyang$ adb push hello /data
hello: 1 file pushed. 0.1 MB/s (7808 bytes in 0.112s)
NickPro:tmp nickyang$ adb shell
generic_arm64:/ # cd data
generic_arm64:/data # ls -l | grep hello
-rwxrwxrwx 1 root root 7808 2018-02-18 16:20 hello
generic_arm64:/data # ./hello
Hello, this is a program compiled by ndk-cross-compiler!
10|generic_arm64:/data #
執行成功,順利輸出打印!