USING THE ANDROID TOOLCHAIN AS A STANDALONECOMPILER ===============================================================


现在可以使用Android NDK提供的工具链作为独立的编译器。这会很有用,如果你已经有自己的编译系统,只需要调用交叉编译器,向Android添加支持即可。



本文档解释了如何进行操作:


1/ 选择你的工具链:

------------------------------


在任何操作之前,你必须确定你的独立工具链针对的是基于ARM的设备,x86的设备,还是MIPS的设备。每一种架构对应了不同的工具链:


* arm-linux-androideabi-4.6  => targetting ARM-based Android devices  
* x86-4.6          => targetting x86-based Android devices  
* mipsel-linux-android-4.6  => targetting MIPS-based Android devices



2/ 选择你的sysroot

------------------------------


第二件事情你需要知道的是你想针对哪个Android本地API level。每一个level对应了不同的APIs,在STABLE-APIS中有描述,同时对应了$NDK/platforms下的子目录。


允许定义你的‘sysroot’的路径,这是一个GCC的俗语:它是一个目录,包含了你目标中的系统头文件和库。通常,像这样:


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


<level>Android APIlevel number<arch>是架构(“arm”,“x86”,同时“mips”也是支持的)。例如,如果你针对Android 2.2,你将会使用:


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


重要:注意x86MIPS架构只支持android-9和以后的版本。



3/ 调用编译器(困难的方法):

---------------------------------------------


使用--sysroot选项调用编译器,指明你针对平台的系统文件的位置。例如:


exportCC="$NDK/toolchains/<name>/prebuilt/<system>/bin/<prefix>gcc--sysroot=$SYSROOT" $CC -o foo.o-c foo.c


<name>是工具链的名字,<system>是你系统的主机tag<prefix>是指定工具链的前缀。例如,你在Linux上使用NDK r5工具链,你会使用:


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


如你看到的,这是冗长的,但是能工作!


重要提示:


直接使用NDK工具链有一个严重的限制:你不能使用任何C++STLSTLportGNU libstdc++),同样不能使用异常和RTTI



4/ 调用编译器(简单的方法):

--------------------------------------------


NDK允许你创建一个“customized“的工具链使得这个过程更加简单。例如,考虑下面的命令:


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


这会创建一个叫着/tmp/my-android-toolchain 的目录,它包含了android-5/arch-arm sysroot的一份拷贝和工具链二进制文件。
  
注意默认情况下,脚本会选择基于ARMGCC 4.6 工具链。使用 ’--arch=x86’选项指定基于x86的工具链,使用‘―arch=mips’选项指定基于MIPS的工具链,或者使用‘--toolchain=<name>‘。例如:
  

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


如果你愿意,增加--llvm-version=3.1会拷贝clang/llvm 3.1
以后你可以直接这样使用:
  

export PATH=/tmp/my-android-toolchain/bin:$PATH export CC=arm-linux-androideabi-gcc # or export CC=clang export CXX=arm-linux-androideabi-g++ # or export CXX=clang++

  
注意没有--install-dir选项, make-standalone-toolchain.sh将会创建一个/tmp/ndk/<toolchain-name>.tar.bz2包。这允许你非常简单的解压和重新发布二进制文件。
  
另一个好处是独立工具链将会包含GNU libstdc++的拷贝,支持异常和RTT(只要你链接libstdc++或者libsupc++)。


使用--help 了解更多的选项和细节。


重要:工具链二进制文件不会依赖或包含host-specific路径,换句话说,它们可以安装在任何位置,甚至可以移动,如果需要的话。


注意:你依然可以在新的工具链中使用--sysroot 选项,但是它现在是可选的!



5/ 关于Clang

------------------------


在相同的独立包中,Clang/clang++ 使用相同的assembler, linker, headers, libraries  GNU libstdc++Clang/clang++ 实际上是使用“-target”的脚本,用来在创建时指定架构。例如,在ARM 独立包中,clang是一行:


`dirname $0`/clang31-target armv5te-none-linux-androideabi "$@"


clang++ 是另一行:


`dirname $0`/clang31-target armv5te-none-linux-androideabi -x c++ "$@"


注意额外的“-x c++”不是必须的,但是在编译*.c文件时会有一个警告:


clang31: warning: treating 'c' input as 'c++' when in C++ mode, thisbehavior is deprecated


对于arm也要注意,clang将会改变基于选项“-march=armv7-a”或“-mthumb”的目标。例如:


1/ With"-march=armv7-a", -target becomes armv7-none-linux-androideabi 2/ With"-mthumb", -target becomes thumb-none-linux-androideabi

3/ With both, -target becomesthumbv7-none-linux-androideabi

如果你愿意的话,你可以使用�Ctarget 覆盖它。


已经做了额外的努力使得在Makefile文件中clang/clang++更容易替代gcc/g++

当你有所怀疑的时候,使用下面的通用技术来检查:


1/ Add option "-v"to dump commands compiler driver issues

2/ Add option"-###" to dump command line options, including those implicitly predefined.

3/ Use "-x c /dev/null-dM -E" to dump predefined preprocessor definitions 4/ Addoption "-save-temps" and compare the preprocessed files *.i or *.ii


请看http://clang.llvm.org/,尤其是GCC兼容部分。



6/ ABI兼容性:

-----------------------


默认情况下,用ARM工具链生成的机器代码应该和官方的AndroidarmeabiABI(查看CPU-ARCH-ABIS相关内容)兼容。


推荐使用-mthumb编译标志强制生成16Thumb-1指令(默认是32ARM指令)。


如果你想针对‘armeabi-v7aABI,你必须确保下面的这些标志被使用:


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


注意:第一个标志启用Thumb-2指令,第二个指令启用 H/W FPU 指令(确保浮点参数传递给内部的寄存器),这对于兼容性来说是至关重要的。不要单独的使用这些标志。


如果你想使用Meon指令,你必须修改-mfpu编译器标志:


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


注意这会按照ARM指定,强制使用VFPv3-D32


同时,确保下面的两个标志提供给链接器:


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


注意:第一个标志通知链接器为armv7-a选择libgcc.a, libgcov.a和特定的crt*.o。第二个标志是必须的,用来绕过在一些Cortex-A8实现的CPU中的bug
  
如果上面的这些对你来说都没啥用,最好不要使用独立的工具链,那么就使用NDK编译系统,它会帮你处理很多细节。


当针对x86 ABIMIPS ABI,你不必使用任何特定的编译器标志。



7/ 警告和限制:

-----------------------------


7.1/ Windows支持:

------------------------------


Windows二进制文件不依赖于Cygwin。好消息是它们更快,坏消息是它们不认识Cygwin指定的路径,类似/cygdrive/c/foo/bar(取而代之的是C:/foo/bar)。


NDK编译系统确保从Cygwin传递给编译器的所有路径都被解释翻译,同时替你处理一些其他的错误。如果是你自己的编译系统,你必须自己处理这些问题。


注意:目前并不打算支持Cygwin / MSys,但是欢迎大家为此做出贡献,联系android-ndk论坛了解更多细节。



7.2/ wchar_t支持:

------------------------------


如前面所诉,在Android2.3之前,Android平台实际上并不支持wchar_t。实际上这意味着:


-如果你针对android-9或更高的版本,wchar_t的大小为4个字节,并且C库(多字节encoding/decoding函数和wsprintf/wsscanf除外)中的大部分wide-char函数都是可用的。
  
-如果你针对之前的APIwchar_t的大小为1个字节,大部分的wide-char函数是不能工作的。
  

我们建议开发人员摆脱对wchar_t类型的任何依赖,并切换到更好的办法。Android提供的支持只是帮助你迁移已经存在的代码。


  
7.3/ 异常,RTTISTL
-------------------------------------
  
默认情况下,工具链二进制库是支持c++异常和RTTI。它们默认是被启用的,当用它们编译源代码(例如为了生成更小的机器代码)时,如果你想禁用它们,可用使用-fno-exceptions and -fno-rtti
  
注意:如果你想使用这些功能,你必须显示的链接libsupc++。当链接二进制库的时候,像下面这样使用-lsupc++
  
arm-linux-androideabi-g++ .... -lsupc++
7.4/ c++ STL支持:
-----------------------------
  
独立的工具链还附带一份GNU libstdc++库的拷贝,它提供了一个c++标准模板库的实现。为了使用它,你必须链接合适的库:
  
* 使用�Clstdc++ 来链接 _static_ 版本库。这样能够确保所有c++ STL需要的代码都被导入到你最终的二进制文件中。这是非常理想的,如果你只是想生成一个单一的动态库或可执行文件。
  
这是那样做的推荐方式。
  
* 使用�Clgnustl_shared 来链接_shared_ 版本库。这是必须的,如果你有多个相关的动态库或可执行文件需要运行在同样的地址空间中(一些全局变量必须唯一定义,这是不可能的,如果你针对每一个可执行文件链接一个staticlibstdc++)。
  
如果你使用这个选项,你需要确保libgnustl_shared.so同样被拷贝到你的设备中,这样你的代码在适当的时候加载它。The file is at:
  
$TOOLCHAIN/arm-linux-androideabi/lib/ for ARM toolchains.    $TOOLCHAIN/i686-linux-android/lib/   for x86 ones.    $TOOLCHAIN/mipsel-linux-android/lib/  for MIPS toolchains.
  
重要:在GPLv3下授权的GNU libstdc++ 有一个链接异常。请查看下面的URL来了解更多的细节:
  
 http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk1px01ch01s02.html
  
如果你不能满足它的条件,例如你不能再一次的贡献出你的动态库,那么在你的项目中不要使用它。
  
GNU libstdc++ 的共享版本没有被libstdc++调用的原因是:使用系统自己最小版本的c++ runtime(即/system/lib/libstdc++),在运行是会有冲突。这样就强制GNU ELF库使用一个新的名字。这对于静态库来说并不是一个问题。


更多相关文章

  1. Python3原生编写月份计算工具
  2. 一款常用的 Squid 日志分析工具
  3. GitHub 标星 8K+!一款开源替代 ls 的工具你值得拥有!
  4. Linux 环境下实战 Rsync 备份工具及配置 rsync+inotify 实时同步
  5. 全网最全Android开发工具,Android开发框架大全
  6. Android(安卓)dumpstate 工具解析
  7. Android组件TextView细节
  8. Android开源项目发现--- 工具类依赖注入DI篇(持续更新)
  9. Android之WebView总结

随机推荐

  1. Android(安卓)进阶到高级 - 突破篇
  2. Android(安卓)Studio 定制快速生成Jni 头
  3. android 全局dialog的实现
  4. Android开发 APP进程启动原理
  5. dex分包
  6. android的edittext默认不获得焦点
  7. Could not find method runProguard() fo
  8. android中基本的加密方法
  9. Android稳定性问题分析时获取手机状态的A
  10. android 实现圆形imageView,Circle image