【转】Android C程序也可自己手动用交叉编译器编译 (

原文网址:http://blog.sina.com.cn/s/blog_533074eb0101ez5q.html

Android 编译环境 本身比较复杂,且不像普通的编译环境:只有顶层目录下才有 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/hello

2. 在 $(YOUR_ANDROID)/development /hello/ 目录编写 hello.c 文件, hello.c 的内容当然就是经典的 HelloWorld 程序:

#include

int main()
{
    printf("Hello World!/n");

return 0;
}

3. 在 $(YOUR_ANDROID)/development /hello/ 目录编写 Android.mk 文件。这是 Android Makefile 的标准命名,不要更改。Android.mk 文件的格式和内容可以参考其他已有的 Android.mk 文件的写法,针对 helloworld 程序的 Android.mk 文件内容如下:


LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= /

hello.c

LOCAL_MODULE := helloworld

include $(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.c

target 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” 登录到模拟器终端,就可以执行了

============================================

上一篇中(即《 Android编译环境 (1) - 编译 Native C的 helloworld模块 》),我们试用了通过标准的 Android.mk 文件来编译 C 模块,下面我们来试试如何直接运用 gcc 命令行来编译,从而了解 Android 编译环境的细节。

Android 编译环境提供了 ”showcommands” 选项来显示编译命令行, 我们可以通过打开这个选项来查看一些编译时的细节。当然,在这之前要把上一篇中的 helloworld 模块 clean:


# make clean-helloworld

上面的 “make clean-$(LOCAL_MODULE)” 是 Android 编译环境提供的 make clean 的方式。

接下来使用 showcommands 选项 重新编译 helloworld:


# make helloworld showcommands

build/core/product_config.mk:229: WARNING: adding test OTA key

target thumb C: helloworld <= development/hello/hello.c

prebuilt/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.c

target 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.o

target 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/helloworld

target 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/helloworld

Install: out/target/product/generic/system/bin/helloworld

out/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/helloworld

out/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 NEEDED

0x00000001 (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 (即交叉编译工具链)可从下面的网址下载:

http://android.kernel.org/pub/android-toolchain-20081019.tar.bz2 。如果下载了完整的 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 ,其源代码位于 ” /build/tools/apriori”

-          strip 工具也没有采用常用的 strip ,即“ /prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin ”目录下的 arm-eabi-strip,而是位于 / out/host/linux-x86/bin/ 的soslim 工具。

时间: 2024-08-28 07:44:36

【转】Android C程序也可自己手动用交叉编译器编译 (的相关文章

Android应用程序组成部分

引言 为了后面的例子做准备,本篇及接下来几篇将介绍Android应用程序的原理及术语,这些也是作为一个Android的开发人员必须要了解,且深刻理解的东西.本篇的主题如下: 1.应用程序基础 2.应用程序组件 2.1.活动(Activities) 2.2.服务(Services) 2.3.Intent 2.4.广播接收者(Broadcast receivers) 2.5.Notification 2.6.内容提供者(Content providers) 因为这些内容比较理论,且没有用例子来说明,

android应用程序签名(转)

概述 Android系统要求,所有的程序经过数字签名后才能安装.Android系统使用这个证书来识别应用程序的作者,并且建立程序间的信任关系.证书不是用于用户控制哪些程序可以安装.证书不需要授权中心来签名:Android应用程序上使用自己签名的证书是完全允许且普遍的. 理解Android应用程序签名有以下几个重要点: 所有的应用程序都必须签名.系统不会安装任何一个不签名的程序. 你可以使用自己的证书来签名.不需要任何授权中心. 当你要为最终用户发布你的应用程序的时候,你必须签入一个合适的密钥.你

Android学习笔记-Android应用程序初步认识

一直觉得自己的技术没有一门专长,似乎什么都会一点,但是却一点都不深入.决定学习Android的开发,说不出的理由,希望自己能够坚持下去. 其实之前已经搭建好了Android的开发环境eclipse+ADT+SDK,这里就不做具体介绍了,个人觉得还是非常有必要把这3个软件单独安装一下, 这样对开发工具能有个系统的认识.Eclipse是一个IDE,针对多门开发语言都能够使用,SDK是针对Android应用开发提供的一个框架,其中有开发 过程中使用到的包和一些集成的工具,ADT是安装在eclipse上

[转载]如何使Android应用程序获取系统权限来修改系统时间

在 android 的API中有提供 SystemClock.setCurrentTimeMillis()函数来修改系统时间,可惜无论你怎么调用这个函数都是没用的,无论模拟器还是真机,在logcat中总会得到"Unable to open alarm driver: Permission denied ".这个函数需要root权限或者运行与系统进程中才可以用. 本来以为就没有办法在应用程序这一层改系统时间了,后来在网上搜了好久,知道这个目的还是可以达到的. 第一个方法简单点,不过需要在

android 卸载程序、清除数据、停止服务用法

要实现卸载程序.清除数据.停止正在执行的服务这几大模块,如今将代码粗略总结例如以下: 主要运用到的类有 PackageManager ActivityManager ApplicationInfo RunningServiceInfo Method 还有两个android.pm下的源文件用于生成桩,IPackageStatsObserver.java 和 IPackageDataObserver.java,由名字能够看出,他们是跟包的状态和大小有关的,在网上找到这两个文件的源代码后,把他们放在p

Android应用程序进程启动过程的源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址: http://blog.csdn.net/luoshengyang/article/details/6747696 Android 应用程序框架层创建的应用程序进程具有两个特点,一是进程的入口函数是ActivityThread.main,二是进程天然支持Binder进程间通信 机制:这两个特点都是在进程的初始化过程中实现的,本文将详细分析Android应用程序进程创建过程中是如何实现这两个特点的. Android应用程序框架层创建的应用程序进程

Android应用程序内存泄漏介绍

Android应用程序内存泄漏介绍 内存泄漏和内存溢出的区别 内存溢出(out of memory)是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory.比如在我们每个Android程序在运行时系统都会给程序分配一个一定的内存空间,当程序在运行中需要的内存超出这个限制就会报内存溢出(out of memory). 内存泄漏(memory leak)是指程序在申请内存后,无法释放已申请的内存空间.多次内存无法被释放,程序占用的内存会一直增加,直到超过系统的内存限制报内存

【电子书下载】《Android应用程序开发与典型案例》完整版!!

图书简介: <android应用程序开发与典型案例>共23章,内容包含两大部分.第一部分是android程序设计基础,在介绍android环境搭建以及android系统基本控件和组件后,详细介绍了android系统应用编程中典型的技术,比如,android中的图形图像.多媒体编程.gps定位与地图编程等:第二部分是android程序ui设计,从手机软件的交互设计谈起,介绍了android用户界面设计原则和方法.android用户界面设计哲学等,并给出了具体建议. <android应用程序

【转】android应用程序签名

概述 Android系统要求,所有的程序经过数字签名后才能安装.Android系统使用这个证书来识别应用程序的作者,并且建立程序间的信任关系.证书不是用于用户控制哪些程序可以安装.证书不需要授权中心来签名:Android应用程序上使用自己签名的证书是完全允许且普遍的. 理解Android应用程序签名有以下几个重要点: 所有的应用程序都必须签名.系统不会安装任何一个不签名的程序. 你可以使用自己的证书来签名.不需要任何授权中心. 当你要为最终用户发布你的应用程序的时候,你必须签入一个合适的密钥.你