详解如何将android工具链作为独立编译器使用

 

现在已经可以把Android NDK提供的工具链以独立编译器的方式使用了!如果你已经有了自己的构建系统,这就很有用了。

一个典型的应用场景是调用一个依赖于CC环境变量开源库的'configure'脚本进行跨平台编译。

 

本文档将解释如何那样做。

1 选择你的工具链:

首先 ,你需要确定你的独立工具链所面向的目标CPU加构,是ARM-based设备、x86-based设备,还是MIPS-based设备。每个架构对应不同的工具链名字:

 

  * arm-linux-androideabi-4.6   => 面向ARM-based Android设备

  * x86-4.6                     => 面向x86-based Android设备

  * mipsel-linux-android-4.6    => 面向MIPS-based Android设备

 

2 选择你的sysroot:

你应该了解的第二项事情是你想面向那一级Android nativeAPI 。每一级都提供了不同的API,它们被文档doc/STABLE-APIS.html所描述,并对应于$NDK/platforms的子文件夹。这使得你可以定义指向你的'sysroot'的路径 ,GCC路径下包含系统头文件和库。通常看起来像这样:

 

  SYSROOT=$NDK/platforms/android-<level>/arch-<arch>/

 

<level> 是API level 数,<arch> 是体系结构("arm", "x86", 和"mips" 都可以作为值)。例如,如果你面向 Android2.2 (a.k.a. Froyo),你应使用:

 

   SYSROOT=$NDK/platforms/android-8/arch-arm

 

注意:X86 和MIPS体系仅在android-9才开始支持。

3调用编译器(笨办法):

使用--sysroot选项调用编译器,以表明你所面向的平台的系统文件的路径。例如:

export CC="$NDK/toolchains/<name>/prebuilt/<system>/bin/<prefix>gcc--sysroot=$SYSROOT"

$CC -o foo.o -c foo.c

 

<name> 是工具链的名字,<system> 是宿主系统,<prefix> 是特定工具链的前缀。例如,如果你在Linux上使用NDK r5 工具链,你将使用:

 

exportCC="$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc--sysroot=$SYSROOT"

 

就像你看到的,这很啰嗦,但的确能工作!

 

注意:

    直接使用NDK 工具链具有很多限制:

    你不能使用任何C++ STL (无论是STLport 或GNU libstdc++) 。也不能使用异常和RTTI。

 

4调用编译器(容易的办法):

NDK 允许你创建一个"自定义的" 工具链并安装以使生活更简单。例如,下面的命令:

 

$NDK/build/tools/make-standalone-toolchain.sh --platform=android-5--install-dir=/tmp/my-android-toolchain

 

这将创建一个文件夹,名为 /tmp/my-android-toolchain,包含一个android-5/arch-armsysroot的考贝和工具链的执行文件。

 

注意,默认下,ARM-based GCC 4.6 工具链将被脚本所选择。使用'--arch=x86' 来指定x86-based 的GCC,使用'--arch=mips' 来指定MIPS-based 的GCC,或使用

'--toolchain=<name>'来指定。例如:

 

  --toolchain=x86-4.4.3               # select x86 GCC 4.4.3 compiler

 --toolchain=mipsel-linux-android-4.6  # select MIPS GCC 4.6compiler, same as --arch=mips

 

如果你想,可以通过添加 --llvm-version=3.1 来把clang/llvm3.1也考贝过去。你可以在之后直接使用它。就像:

 

   exportPATH=/tmp/my-android-toolchain/bin:$PATH

   exportCC=arm-linux-androideabi-gcc   # or export CC=clang

   exportCXX=arm-linux-androideabi-g++  # or export CXX=clang++

 

注意,不使用 --install-dir 选项,make-standalone-toolchain.sh将创建一个名为/tmp/ndk/<toolchain-name>.tar.bz2的tarball。这使你可以很容易的存储并重新发布二进制工具包。

另一个重要的好处是这个独立的工具链将包含一个GNU libstdc++的考贝,它能支持异常和RTTI (当你链接到libstdc++ 或 libsupc++)。

 

重点:工具链执行文件不依赖于或包含宿主上的特点路径,换句话说,它们可以被安装于任何位置,或移动到另外位置。

 

注意:你依然可以对新的工具链使用—sysroot选项,但是现在变简单了!

5 ABI 兼容性:

通过ARM 工具链产生的机器码应该与官方的Android 'armeabi' ABI兼容。推荐使用-mthumb 编译标志来强制产生16位Thumb-1指令 (默认是32-bit 的)。

 

如果你想面向'armeabi-v7a' ABI,你应该确保下面的标志被使用:

 

  CFLAGS='-march=armv7-a-mfloat-abi=softfp -mfpu=vfpv3-d16'

 

注:第一个标志启用Thumb-2指令,第二个启用H/W FPU指令同时确保浮点参数被传入核心寄存器,这是ABI兼容的关键。*不要*分开使用这些标志!

 

如果你想使用Neon指令,你需要改变-mfpu编译标志:

 

  CFLAGS='-march=armv7-a-mfloat-abi=softfp -mfpu=neon'

 

注意这会强制使用VFPv3-D32。

还要确保下面两个标志也提供给链接器:

 

  LDFLAGS='-march=armv7-a-Wl,--fix-cortex-a8'

 

注:第一个标志指示链接器为armv7-a选择合适的libgcc.a、libgcov.a和crt*.o。第二个标志用于在某些Cortex-A8装置中绕过一个CPU bug。

 

如果上面这些还不能满足你,那么你最好不要用独立的工具链了,而是坚守NDK构建系统,它将为你处理所有细节。

 

当你面向x86 ABI 或MIPS ABI时你不需要使用任何特定的编译器标志。

 

6 警告和限制:


Windows support:

Windows下的二进制文件*不*依赖于Cygwin。好消息是它们因此会运行快,坏消息是它们不明白Cygwin的路径形式,比如/cygdrive/c/foo/bar (而不是 C:/foo/bar)。

 

NDK构建系统保证所有从Cygwin传给编译器的路径都被自动转换,并且为你应付那些难搞的事情。如果有一个自定义构建系统,你需要自己应付所有的问题。

 

注:当前没有支持Cygwin / MSys的计划。

 

wchar_t 支持:

 

在Android 2.3之前,Android平台并不真的支持wchar_t。这表示:

l  如果你面向android-9 或更高平台,wchar_t的大小是4bytes,并且大多数C库中的宽字节函数都可用(例外是多字节编解码函数和wsprintf/wsscanf函数)。

l  如果你面向任何更低的API level,wchar_t 只有一个字节并且任何宽字节函数都 不能用。

 

我们建议所有开发者都移除对wchar_t的任何依赖,并且转换到更好的方式。Android所提供的支持仅仅是为了帮助整合已存在的代码。

 

异常、RTTI和STL:

 

工具链执行文件默入是支持C++异常和RTTI的。所以当你不需要时,使用-fno-exceptions和-fno-rtti来禁止它们 (产生更少的机器码)。

 

注:如果你想使用这些特性,你将需要明确的链接到libsupc++。要这样做,在要在链接成二进制文件时使用-lsupc++ :

 

    arm-linux-androideabi-g++ .... -lsupc++

 

C++ STL 支持:

 

独立工具链也带有一个GNU libstdc++ 库的考贝,它提供了C++标准模版库的一个实现。要使用它,你还需要链接到正确的库:

 

l  使用-lstdc++ 来链接静态库版。这保证了所有需要的C++ STL代码都包含到了你的最终文件中。这是推荐的方式。

使用-lgnustl_shared 来链接动态库版。如果你使用此方式,你需要确保libgnustl_shared.so也被复制到你的设备中。此文件位于:

 $TOOLCHAIN/arm-linux-androideabi/lib/ for ARM toolchains.

 $TOOLCHAIN/i686-linux-android/lib/    for x86 ones.

 $TOOLCHAIN/mipsel-linux-android/lib/  for MIPS toolchains.

 

动态库版的GNU libstdc++不叫libstdc++.so的原因是这将导致在运行时与系统自己的最小C++运行时(/system/lib/libstdc++.so)冲突。这对静态库就没影响了。

 

你可能感兴趣的:(android)