在android的linux内核中要移植 c/c++程序,一般要编译成static的,而若要运行dynamically linked的程序,则要按照android的相关机制。
Android并没有采用glibc作为C库,而是采用了Google自己开发的Bionic Libc,它的官方Toolchain也是基于Bionic Libc而并非glibc的。
这使得使用或移植其他Toolchain来用于Android要比较麻烦:
与glibc相比,Bionic Libc有如下一些特点:
- 采用BSDLicense,而不是glibc的GPL License;
- 大小只有大约200k,比glibc差不多小一半,且比glibc更快;
- 实现了一个更小、更快的pthread;
- 提供了一些Android所需要的重要函数,如”getprop”,“LOGI”等;
- 不完全支持POSIX标准,比如C++ exceptions,widechars等;
- 不提供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工具。
===================================================================
Android编译环境 -编译Native C的helloworld模块
Android编译环境本身比较复杂,且不像普通的编译环境:只有顶层目录下才有Makefile文件,而其他的每个component都使用统一标准的 Android.mk.
Android.mk文件本身是比较简单的,不过它并不是我们熟悉的Makefile,而是经过了Android自身编译系统的很多处理,编写一个新的Android.mk来给
Android增加一个新的Component会比较简单。
在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程序:
1 #include <stdio.h>
2 int main()
3 {
4 printf("Hello World!/n");
5 return 0;
6 }
复制代码
3. 在$(YOUR_ANDROID)/development/hello/目录编写Android.mk文件。这是Android Makefile的标准命名,不要更改。
Android.mk文件的格式和内容可以参考其他已有的Android.mk文件的写法,针对 helloworld程序的Android.mk文件内容如下:
7 LOCAL_PATH:= $(call my-dir)
8 include $(CLEAR_VARS)
9 LOCAL_SRC_FILES:= /
10 hello.c
11 LOCAL_MODULE := helloworld
12 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指定的模块名。编译结果如下:
13 target thumb C: helloworld <=development/hello/hello.c
14 target Executable: helloworld(out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/LINKED/helloworld)
15 target Non-prelinked: helloworld(out/target/product/generic/symbols/system/bin/helloworld)
16 target Strip: helloworld(out/target/product/generic/obj/EXECUTABLES/helloworld_intermediates/helloworld)
17 Install: out/target/product/generic/system/bin/helloworld
复制代码
5.如上面的编译结果所示,编译后的可执行文件存放在out/target/product/generic/system/bin/helloworld,
通过”adb push”将它传送到模拟器上,再通过”adb shell”登录到模拟器终端,就可以执行了
===================================================================
Android编译完成后,将在根目录中生成一个out文件夹,所有生成的内容均放置在这个文件夹中。out文件夹如下所示:
18 out/
19 --CaseCheck.txt
20 --casecheck.txt
21 -- host
22 -- common
23 -- linux-x86
24 -- target
25 -- common
26 -- product
复制代码
主要的两个目录为host和target,前者表示在主机(x86)生成的工具,后者表示目标机(默认为ARMv5)运行的内容。
host目录的结构如下所示:
27 out/host/
28 -- common
29 -- obj (JAVA库)
30 -- linux-x86
31 -- bin (二进制程序)
32 -- framework (JAVA库,*.jar文件)
33 -- lib (共享库*.so)
34 -- obj (中间生成的目标文件)
复制代码
host目录是一些在主机上用的工具,有一些是二进制程序,有一些是JAVA的程序。
target目录的结构如下所示:
35 out/target/
36 -- common
37 -- R (资源文件)
38 -- docs
39 -- obj (目标文件)
40 -- product
41 -- generic
复制代码
其中common目录表示通用的内容,product中则是针对产品的内容。
在common目录的obj中,包含两个主要的目录:
APPS 中包含了JAVA使用程序生成的目标,每个使用程序对应其中一个子目录,将结合每个使用程序的原始文件生成Android使用程序的APK包。
JAVA_LIBRARIES 中包含了JAVA的库,每个库对应其中一个子目录。
在默认的情况下,Android编译将生成generic目录,如果选定产品还可以生成其他的目录。generic包含了以下内容:
42 out/target/product/generic/
43 --android-info.txt
44 --clean_steps.mk
45 -- data
46 -- obj
47 --ramdisk.img
48 -- root
49 -- symbols
50 -- system
51 --system.img
52 --userdata-qemu.img
53 --userdata.img
复制代码
在generic/obj/APPS目录中包含了各种JAVA使用,与common/APPS相对应,但是已经打成了APK包。
system目录是主要的文件系统,
data目录是存放数据的文件系统。
obj/SHARED_LIBRARIES中存放所有动态库。
obj/STATIC_LIBRARIES中存放所有静态库。
多个以img为结尾的文件是多个目标映像文件,其中ramdisk是作为内存盘的根文件系统映像,system.img是主要文件系统的映像,这是一个比较大的文件,data.img是数据内容映像。这多个image文件是模拟器运行时真实需要的文件。
今天的学习交流分享就到这里了,有什么不懂的问题,小编在和大家一起讨论交流,谢谢大家!
来源:汇道科技