Android编译环境

9/2/2009 11:17:21 PM
http://blog.csdn.net/vrix/archive/2009/06/23/4290616.aspxAndroid编译环境本身比较复杂,且不像普通的编译环境:只有顶层目录下才有Makefile文件,而其他的每个component都使用统一标准的Android.mk. Android.mk文件本身是比较简单的,不过它并不是我们熟悉的Makefile,而是经过了Android自身编译系统的很多处理,因此要真正理清楚其中的联系还比较复杂,不过这种方式的好处在于,编写一个新的Android.mk来给Android增加一个新的Component会比较简单。编译Java程序可以直接采用Eclipse的集成环境来完成,这里就不重复了。我们主要针对C/C++来说明,下面通过一个小例子来说明,如何在Android 中增加一个C程序的Hello World:1. 在$(YOUR_ANDROID)/ development 目录下创建hello目录,其中$(YOUR_ANDROID)指Android源代码所在的目录。
- # mkdir $(YOUR_ANDROID)/development/hello2. 在$(YOUR_ANDROID)/external/hello/目录编写hello.c文件,hello.c的内容当然就是经典的HelloWorld程序:#include <stdio.h>int main()
{
printf("Hello World!/n");return 0;
}

3. 在$(YOUR_ANDROID)/external/hello/目录编写Android.mk文件。这是Android Makefile的标准命名,不要更改。Android.mk文件的格式和内容可以参考其他已有的Android.mk文件的写法,针对helloworld程序的Android.mk文件内容如下:LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= /hello.cLOCAL_MODULE := helloworldinclude $(BUILD_EXECUTABLE)

注意上面LOCAL_SRC_FILES用来指定源文件;,LOCAL_MODULE指定要编译的模块的名字,下一步骤编译时就要用到;include $(BUILD_EXECUTABLE)表示要编译成一个可执行文件,如果想编译成动态库则可用BUILD_SHARED_LIBRARY,这些可以在$(YOUR_ANDROID)/build/core/config.mk查到。4. 回到Android源代码顶层目录进行编译:# cd $(YOUR_ANDROID) && make helloworld

注意make helloworld中的目标名helloworld就是上面Android.mk文件中由LOCAL_MODULE指定的模块名。编译结果如下:target thumb C: helloworld <= development/hello/hello.ctarget Executable: helloworld (out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld)target Non-prelinked: helloworld (out/target/product/generic/symbols/system/bin/helloworld)target Strip: helloworld (out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/helloworld)Install: out/target/product/generic/system/bin/helloworld

5.如上面的编译结果所示,编译后的可执行文件存放在out/target/product/generic/system/bin/helloworld,通过”adb push”将它传送到模拟器上,再通过”adb shell”登录到模拟器终端,就可以执行了
手工编译C模块我们来试试如何直接运用gcc命令行来编译,从而了解Android编译环境的细节。Android编译环境提供了”showcommands”选项来显示编译命令行,我们可以通过打开这个选项来查看一些编译时的细节。当然,在这之前要把上一篇中的helloworld模块clean:# make clean-helloworld

上面的“make clean-$(LOCAL_MODULE)”是Android编译环境提供的make clean的方式。接下来使用showcommands选项重新编译helloworld:# make helloworld showcommandsbuild/core/product_config.mk:229: WARNING: adding test OTA keytarget thumb C: helloworld <= development/hello/hello.cprebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-gcc -I system/core/include -I hardware/libhardware/include -I hardware/ril/include -I dalvik/libnativehelper/include -I frameworks/base/include -I external/skia/include -I out/target/product/generic/obj/include -I bionic/libc/arch-arm/include -I bionic/libc/include -I bionic/libstdc++/include -I bionic/libc/kernel/common -I bionic/libc/kernel/arch-arm -I bionic/libm/include -I bionic/libm/include/arch/arm -I bionic/libthread_db/include -I development/hello -I out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates -c -fno-exceptions -Wno-multichar -march=armv5te -mtune=xscale -msoft-float -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -include system/core/include/arch/linux-arm/AndroidConfig.h -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -DSK_RELEASE -DNDEBUG -O2 -g -Wstrict-aliasing=2 -finline-functions -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers -DNDEBUG -UDEBUG -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -MD -o out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/hello.o development/hello/hello.ctarget Executable: helloworld (out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld)prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-g++ -nostdlib -Bdynamic -Wl,-T,build/core/armelf.x -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -o out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld -Lout/target/product/generic/obj/lib -Wl,-rpath-link=out/target/product/generic/obj/lib -lc -lstdc++ -lm out/target/product/generic/obj/lib/crtbegin_dynamic.o out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/hello.o -Wl,--no-undefined prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a out/target/product/generic/obj/lib/crtend_android.otarget Non-prelinked: helloworld (out/target/product/generic/symbols/system/bin/helloworld)out/host/linux-x86/bin/acp -fpt out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld out/target/product/generic/symbols/system/bin/helloworldtarget Strip: helloworld (out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/helloworld)out/host/linux-x86/bin/soslim --strip --shady --quiet out/target/product/generic/symbols/system/bin/helloworld --outfile out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/helloworldInstall: out/target/product/generic/system/bin/helloworldout/host/linux-x86/bin/acp -fpt out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/helloworld out/target/product/generic/system/bin/helloworld

从上面的命令行可以看到,Android编译环境所用的交叉编译工具链是prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-gcc,-I和-L参数指定了所用的C库头文件和动态库文件路径分别是bionic/libc/include 和out/target/product/generic/obj/lib,其他还包括很多编译选项以及-D所定义的预编译宏。我们可以利用上面的编译命令,稍加简化来手工编译helloworld程序。先手工删除上次编译得到的helloworld程序:# rm out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/hello.o# rm out/target/product/generic/system/bin/helloworld

再用gcc编译,生成目标文件:# prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-gcc -I bionic/libc/arch-arm/include -I bionic/libc/include -I bionic/libc/kernel/common -I bionic/libc/kernel/arch-arm -c -fno-exceptions -Wno-multichar -march=armv5te -mtune=xscale -msoft-float -fpic -mthumb-interwork -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -include system/core/include/arch/linux-arm/AndroidConfig.h -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -DSK_RELEASE -DNDEBUG -O2 -g -Wstrict-aliasing=2 -finline-functions -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers -DNDEBUG -UDEBUG -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -MD -o out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/hello.o development/hello/hello.c

与Android.mk编译参数比较,上面主要减少了不必要的-I参数。接下来生成可执行文件:# prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-gcc -nostdlib -Bdynamic -Wl,-T,build/core/armelf.x -Wl,-dynamic-linker,/system/bin/linker -Wl,--gc-sections -Wl,-z,nocopyreloc -o out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld -Lout/target/product/generic/obj/lib -Wl,-rpath-link=out/target/product/generic/obj/lib -lc -lm out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/hello.o out/target/product/generic/obj/lib/crtbegin_dynamic.o -Wl,--no-undefined ./prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/../lib/gcc/arm-eabi/4.2.1/interwork/libgcc.a out/target/product/generic/obj/lib/crtend_android.o

这里值得留意的是参数“-Wl,-dynamic-linker,/system/bin/linker”,它指定了Android专用的动态链接器/system/bin/linker,而不是通常所用的ld.so。生成的可执行程序可用file和readelf命令来查看一下:# file out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworldout/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped# readelf -d out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld |grep NEEDED0x00000001 (NEEDED) Shared library: [libc.so]0x00000001 (NEEDED) Shared library: [libm.so]

这是ARM格式的动态链接可执行文件,运行时需要libc.so和libm.so。“not stripped”表示它还没被STRIP。嵌入式系统中为节省空间通常将编译完成的可执行文件或动态库进行STRIP,即去掉其中多余的符号表信息。在前面“make helloworld showcommands”命令的最后我们也可以看到,Android编译环境中使用了out/host/linux-x86/bin/soslim工具进行STRIP。Android Toolchain与Bionic Libc
Android所用的Toolchain(即交叉编译工具链)可从下面的网址下载:http://android.kernel.org/pub/android-toolchain-20081019.tar.bz2。如果下载了完整的Android项目的源代码,则可以在“<your_android>/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”目录下找到交叉编译工具,比如Android所用的arm-eabi-gcc-4.2.1。Android并没有采用glibc作为C库,而是采用了Google自己开发的Bionic Libc,它的官方Toolchain也是基于Bionic Libc而并非glibc的。这使得使用或移植其他Toolchain来用于Android要比较麻烦:在Google公布用于Android的官方Toolchain之前,多数的Android爱好者使用的Toolchain是在http://www.codesourcery.com/gnu_toolchains/arm/download.html 下载的一个通用的Toolchain,它用来编译和移植Android 的Linux内核是可行的,因为内核并不需要C库,但是开发Android的应用程序时,直接采用或者移植其他的Toolchain都比较麻烦,其他Toolchain编译的应用程序只能采用静态编译的方式才能运行于Android模拟器中,这显然是实际开发中所不能接受的方式。目前尚没有看到说明成功移植其他交叉编译器来编译Android应用程序的资料。与glibc相比,Bionic Libc有如下一些特点:- 采用BSD License,而不是glibc的GPL License;- 大小只有大约200k,比glibc差不多小一半,且比glibc更快;- 实现了一个更小、更快的pthread;- 提供了一些Android所需要的重要函数,如”getprop”, “LOGI”等;- 不完全支持POSIX标准,比如C++ exceptions,wide chars等;- 不提供libthread_db 和 libm的实现另外,Android中所用的其他一些二进制工具也比较特殊:- 加载动态库时使用的是/system/bin/linker而不是常用的/lib/ld.so;- prelink工具不是常用的prelink而是apriori,其源代码位于” <your_android>/build/tools/apriori”- strip工具也没有采用常用的strip,即“<your_android>/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin”目录下的arm-eabi-strip,而是位于<your_android>/out/host/linux-x86/bin/的soslim工具。本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/vrix/archive/2009/06/23/4290616.aspx

更多相关文章

  1. Android处理9.png文件流程
  2. Attribute is missing the Android namespace prefix——android
  3. dx 工具的使用
  4. Android文件系统的结构及目录用途、操作方法 整理
  5. 用ndk-build 工具手动生成编译android原生程序
  6. Android NDK开发之Android.mk文件

随机推荐

  1. android中wifi原理及流程分析
  2. Android存储权限
  3. JS与Android交互之html页面跳转到Android
  4. android 在surface上显示YUV 笔记
  5. 解决Could not find method android() fo
  6. selector
  7. 系出名门Android(6) - 控件(View)之DateP
  8. android的Notification折叠
  9. 横竖屏切换时不销毁当前activity 和 锁定
  10. Android(安卓)Network Resources