关于在android中移植 c/c++程序的探讨2016-03-04 19:40:36

( 2人已投票,[高质量] )
分享:
31.3K

在android的linux内核中要移植 c/c++程序,一般要编译成static的,而若要运行dynamically linked的程序,则要按照android的相关机制。    

Android 并没有采用glibc作为C库,而是采用了Google自己开发的Bionic Libc,它的官方Toolchain也是基于Bionic Libc而并非glibc的。
这使得使用或移植其他Toolchain来用于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工具。


首先是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程序:

#include <stdio.h>
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编译完成后,将在根目录中生成一个out文件夹,所有生成的内容均放置在这个文件夹中。out文件夹如下所示:

out/
-- CaseCheck.txt
-- casecheck.txt
-- host
-- common
-- linux-x86
-- target
-- common
-- product

主要的两个目录为host和target,前者表示在主机(x86)生成的工具,后者表示目标机(默认为ARMv5)运行的内容。

host目录的结构如下所示:

out/host/
-- common
-- obj (JAVA库)
-- linux-x86
-- bin (二进制程序)
-- framework (JAVA库,*.jar文件)
-- lib (共享库*.so)
-- obj (中间生成的目标文件)


host目录是一些在主机上用的工具,有一些是二进制程序,有一些是JAVA的程序。

target目录的结构如下所示:

out/target/
-- common
-- R (资源文件)
-- docs
-- obj (目标文件)
-- product
-- generic


其中common目录表示通用的内容,product中则是针对产品的内容。

  在common目录的obj中,包含两个主要的目录:
APPS 中包含了JAVA使用程序生成的目标,每个使用程序对应其中一个子目录,将结合每个使用程序的原始文件生成Android使用程序的APK包。
JAVA_LIBRARIES 中包含了JAVA的库,每个库对应其中一个子目录。
  在默认的情况下,Android编译将生成generic目录,如果选定产品还可以生成其他的目录。generic包含了以下内容:

out/target/product/generic/
-- android-info.txt
-- clean_steps.mk
-- data
-- obj
-- ramdisk.img
-- root
-- symbols
-- system
-- system.img
-- userdata-qemu.img
-- userdata.img

在generic/obj/APPS目录中包含了各种JAVA使用,与common/APPS相对应,但是已经打成了APK包。

system目录是主要的文件系统,

data目录是存放数据的文件系统。
obj/SHARED_LIBRARIES中存放所有动态库。
obj/STATIC_LIBRARIES中存放所有静态库。
  多个以img为结尾的文件是多个目标映像文件,其中ramdisk是作为内存盘的根文件系统映像,system.img是主要文件系统的映像,这是一个比较大的文件,data.img是数据内容映像。这多个image文件是模拟器运行时真实需要的文件。





头像

snowcoal
  • android
  • c/c++
  • 移植
  • c++

本文标签:

androidc/c++移植c++

收藏到我的私密空间

标题:关于在android中移植 c/c++程序的探讨

作者:小麻雀

你暂未登录,请登录后才可收藏至您的私密空间 确认取消
雪炭网

键盘操作 更便捷 -雪炭网雪中送炭-乐趣无限