Android NDK Standalone Toolchain(中文翻译)
英文原版: Android NDK Standalone Toolchain
独立工具链
你可以在 Android NDK 中单独的使用此工具链,也可以在IDE中以插件的方式使用。如果你已经拥有编译系统,并且只需要一个跨平台的编译器来增加对 Andrid 系统的支持,这种方式是非常方便的。
一种常见的用法是,调用开源项目库的 configure 脚本中时,设置跨平台编译环境变量 CC 为 Toolchain 的路径。
注:本文的主要目的是理解编译,链接,和低层架构。除此之外,一般这些技术是用不到的。多数情况下,我们推荐使用独立工具链的方式代替直接使用NDK编译系统。
选择工具链
在开始之前,你需要知道目标独立工具链要兼容哪一种处理器架构。每一种架构对应一个工具链名字,如下表所示:
表1:不同指令集下的 APP_ABI 设置
架构 | 工具链名字 |
---|---|
ARM-based | arm-linux-androideabi-<gcc-version> |
x86-based | x86-<gcc-version> |
MIPS-based | mipsel-linux-android-<gcc-version> |
ARM64-based | aarch64-linux-android-<gcc-version> |
X86-64-based | x86_64-<gcc-version> |
MIPS64-based | mips64el-linux-android–<gcc-version> |
选择根目录
接下来,需要定义 sysroot 变量(sysroot是包含了目标操作系统头文件和库文件的目录)。在定义 sysroot 之前,你必须确认要支持的目标API版本,本地API是随着Android API级别变化的。
本地API接口位于 $NDK/platforms/ 目录;每一个API接口目录,依次包含了各种CPU和架构的子目录。接下来的示例展示了如何为一个 Android 5.0 (API level 21),ARM架构的系统定义 sysroot 变量:
SYSROOT=$NDK/platforms/android-21/arch-arm |
关于 Android API 级别和各自支持的本地API接口的详细信息,参见 Android NDK Native APIs。
调用编译器
有两种调用编译器的方法。一种简单的方法,更多的借助于编译系统。另一种复杂的方法,可以提供更大的灵活性。
简单的方法
最简单的编译方法是在命令行下直接调用合适的编译器,使用 –sysroot 选项来标明目标平台的系统文件位置。例如:
export CC="$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/ \ |
这种方法尽管简单,但缺少了一定的灵活性:不支持使用任何 C++标准库(STLport, libc++, GNU libstdc++),也不支持RTTI异常处理。
如果使用 Clang 编译器,需要额外两步:
1.增加合适的 -target 选项,如下表所示:
表2: CPU架构和合适的 -target 取值
架构 | 取值 |
---|---|
armeabi | -target armv5te-none-linux-androideabi |
armeabi-v7a | -target armv7-none-linux-androideabi |
arm64-v8a | -target aarch64-none-linux-android |
x86 | -target i686-none-linux-android |
x86_64 | -target x86_64-none-linux-android |
mips | -target mipsel-none-linux-android |
2.增加汇编工具和链接支持选项 -gcc-toolchain ,示例如下:
-gcc-toolchain $NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64 |
最终,使用 Clang 编译器的完整命令如下:
export CC="$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/ \ |
复杂的方法
NDK 提供了 make-standalone-toolchain.sh 脚本,用来在命令行下来生成本地工具链。这种方法比上一种方法提供了更多的灵活性。
此工具链脚本位于 $NDK/build/tools/ 目录内,$NDK 代表 Android NDK 安装根目录。脚本的使用示例如下:
$NDK/build/tools/make-standalone-toolchain.sh \ |
上面的命令创建了一个名为 /tmp/my-android-toolchain/ 的目录,目录内包含了一份 android-21/arch-arm 的系统拷贝,和32位 ARM 架构的二进制工具链。
注,上面的二进制工具链不依赖于路径和宿主机,这意味着工具链可以安装在任何位置,也可以任意移动。
默认情况下,编译系统使用32位ARM架构的GCC-4.8工具链。你可以使用 –arch=
表3: 工具链和合适的 –arch 取值
工具链 | 取值 |
---|---|
mips64 compiler | –arch=mips64 |
mips GCC 4.8 compiler | –arch=mips |
x86 GCC 4.8 compiler | –arch=x86 |
x86_64 GCC 4.8 compiler | –arch=x86_64 |
arm GCC 4.8 compiler | –arch=arm |
另外,你可以使用 –toolchain=
表4: 工具链和合适的 –toolchian 取值
工具链 | 取值 |
---|---|
arm | –toolchain=arm-linux-androideabi-4.8 |
arm | –toolchain=arm-linux-androideabi-4.9 |
arm | –toolchain=arm-linux-android-clang3.5 |
arm | –toolchain=arm-linux-android-clang3.6 |
x86 | –toolchain=x86-linux-android-4.8 |
x86 | –toolchain=x86-linux-android-4.9 |
x86 | –toolchain=x86-linux-android-clang3.5 |
x86 | –toolchain=x86-linux-android-clang3.6 |
mips | –toolchain=mips-linux-android-4.8 |
mips | –toolchain=mips-linux-android-4.9 |
mips | –toolchain=mips-linux-android-clang3.5 |
mips | –toolchain=mips-linux-android-clang3.6 |
arm64 | –toolchain=aarch64-linux-android-4.9 |
arm64 | –toolchain=aarch64-linux-android-clang3.5 |
arm64 | –toolchain=aarch64-linux-android-clang3.6 |
x86_64 | –toolchain=x86_64-linux-android-4.9 |
x86_64 | –toolchain=x86_64-linux-android-clang3.5 |
x86_64 | –toolchain=x86_64-linux-android-clang3.6 |
mips64 | –toolchain=mips64el-linux-android-4.9 |
mips64 | –toolchain=mips64el-linux-android-clang3.5 |
mips64 | –toolchain=mips64el-linux-android-clang3.6 |
注:表4并不包含所有的可用选项。还有其他未确认的选项。
你也可以使用下面两个方法拷贝 Clang/LLVM 3.6:在 –toolchain 选项后添加 -clang3.6 值,示例如下:
--toolchain=arm-linux-androideabi-clang3.6 |
也可以使用 -llvm-version=3.6 作为命令行中单独的附加选项。
注:你可以使用
默认情况下,编译系统使用32位的主机工具链。你可以指定使用64位的主机工具链。下表显示了 –system 选项的不同取值。
表5: 主机工具链和合适的 –system 取值
工具链 | 取值 |
---|---|
64-bit Linux | –system=linux-x86_64 |
64-bit MacOSX | –system=darwin-x86_64 |
64-bit Windows | –system=windows-x86_64 |
有关32位或64位结构主机工具链的更多信息,请参照 64-Bit and 32-Bit Toolchains
你可以使用 –stl=stlport 选项来拷贝 libstlport 代替默认的 libgnustl。同时,必须使用 -lstlport_shared 选项来指定动态链接库。这种用法与使用 -lgnustl_shared 来指定 GNU libstdc++ 道理是一样的。
当然,你可以使用 –stl=libc++ 选项来拷贝 LLVM libc++ 的头文件和库文件。链接动态库需要使用 -lc++_shared 选项指定。
你可以使用系统变量的方式来直接设置这些选项,例如:
export PATH=/tmp/my-android-toolchain/bin:$PATH |
注:如果你使用了 -install-dir 选项,make-standalone-toolchain.sh 脚本会创建一个 tmp/ndk/
这种独立工具链提供了额外的优势,它包含了 C++ STL 库的拷贝,用来支持异常处理和RTTI操作。
关于工具链的更多选项和信息,可以使用 –help 选项查看。
使用 Clang
你可以使用 –llvm-version=
build/tools/make-standalone-toolchain.sh \ |
注: Clang工具链包含了GCC工具,因此他们使用同样的汇编器、链接器、头文件、库文件、以及C++ STL实现。
上面的命令在
调用Clang
在Unix系统平台下,使用命令行的方式调用Clang生成ARM工具链。示例如下:
`dirname $0`/clang36 -target armv5te-none-linux-androideabi "$@" |
clang++使用同样的方式调用clang++31。
Clang
当生成ARM架构的工具链时,Clang使用 -march=armv7-a 和/或 -mthumb 选项来生成不同的工具链:
表6: -march取值和目标结果
-march取值 | 目标结果 |
---|---|
-march=armv7-a | armv7-none-linux-androideabi |
-mthumb | thumb-none-linux-androideabi |
-march=armv7-a -mthumb | thumbv7-none-linux-androideabi |
你可以使用其他 -target 来生成想要的结果。
在Clang版本的独立工具链里面已经包含了as和ld工具,因此-gcc-toolchain选项可以省略。
在Makefile脚本里,clang和clang++应该很容易的更换为gcc和g++。如果有疑问,可以使用下面的选项来验证:
- -v 输出命令与编译器相关的驱动程序问题
- -### 输出命令行选项,包括预定义的
- -x c < /dev/null -dM -E 输出预定义的预处理器定义
- -save-temps 对比*.i或*.ii预处理文件
关于Clang的更多消息,请查看 http://clang.llvm.org/ 网站的GCC兼容性章节。
ABI兼容性
未完待续。。。