上一篇只是谈到了大方向。有些具体的东西还是没有讲清楚,这次专门讲讲android ndk.
先看看android ndk的目录layout大概长的怎么样.
root
|------apps,所有你要编译的C和c++co de都放到这个目录下。
|------build
| |----platforms 下面目前为止放了3个sub fold,里面分别放了android 需要的include , library(提供的library有限)
| |------android 3 代表android 1.5
| |------android 4 代表android 1.6
| |------android 5 代表android 2.0
| |----prebuilt 该目录下存放toolchain的可执行档案,以及include & library.对于arm-eabi-4.4.0了解不多.
| |------arm-eabi-4.2.1
| |------------bin 所有的toolchain的excute file
| |------------arm-eabi
| |------include
| |------lib
| |----tools 这个目录下存放了很多有用的工具,包括下载,build toolchain
|------docs必须仔细读的文档
|------out生成的所有临时文件
先从docs开始谈,这个也是非常重要的一步。
1.纠正Android-mk.txt 中写的 ndk 只能编译出static library 和shared library,实际上他还提供了命令编译可执行程序.
a.include $(BUILD_SHARED_LIBRARY)
b.include $(BUILD_STATIC_LIBRARY)
c.include $(BUILD_EXECUTABLE)
理论上能编译出so文件,当然能编译出execute文件.只是ndk是否提供这个接口。
2.在apps目录下,新建一个目录,再建立project目录,这一级目录下建立Application.mk, 再建立一个sub fold “jni”, jni里面放的都是c和c++源代码,还有Android.mk.Android.mk就必须仔细写了.
常用的有LOCAL_PATH:=$(call my-dir)//访问当前path下的所有子目录,
<1>.LOCAL_DEBUG:=no|yes
<2>.LOCAL_OS:= linux //目标平台
<3>.LOCAL_ARCH:=arm //目标平台cpu
<4>.LOCAL_ARM_MODE:=arm //CPU指令集
<5>.COMMON_DEFINES += ISP=isp_arm9 -D_ARM_//这里通常会把要移植的library中的各种flag写在这里.(从待移植中的Configure或者Makefile中拷贝过来)
<6>.ifeq($(DEBUG),no)
COMMON_FLAGS += -s -O2 -fno-strict-aliasing -DNDEBUG -fno-rtti//好像都采用O2优化,fno-rtti 告诉C++不要runtime 中的一些support.
<7>.COMMON_COMPILE_FLAGS += -fPIC += -msoft-float +=march=armv5t
相对应的有了COMMON_XXX就有了LOCAL_XXX,
我们可以定义相关的
<1>.LOCAL_MODULE := libxxx //定义要编译的moule
<2>.LOCAL_CFLAGS := -I$(LOCAL_PATH)/xxx/include以及局部FLAG(从Configure或者Makefile中拷贝过来)//定义search .h fold
<3>.LOCAL_CXXFILES := //和上面是相同的,只是这个是C++的,上面的是C
<4>.LOCAL_SRC_FILES := XXX.c XXX.cpp XXX.hpp //定义源代码
<5>.include $(BUILD_STATIC_LIBRARY) 定义该模块是静态的
要编译到android上运行的excutable,还会依赖
<1>.LOCAL_LDLIBS := -L library_path -lxx //定义库的路径,以及要的library, 这里其实用的都是动态库.
在android中,有一个参数是:-dynamic-linker,/system/bin/linker ,采用的不是标准的linux下的ld.so.6(好像是这个数字,具体的不清楚了) ,而是/system/bin/linker来链接.这也是为什么我们用其他编译器(比如codesourcery)编译出来的东西不能在android上直接跑的原因,而一定要加上-static参数,也就是说用codesourcery编译出来的东西必须不依赖android的调度,而是靠编译时把所有的库全部加入.所以这时候写出来的helloworld都可能会有1~2Mb.提到了liner,就不得不提到android bionic,这个C runtime library设计并不是功能特别强大,并且有些gnu glic中的函数没有实现,这是移植时会碰到的问题.而且,这个C runtime library也并没有采用crt0.o,crt1.o,crti.o crtn.o,crtbegin.o crtend.o,而是采用了android自己的crtBegin_dynamic.o, crtBegin_static.o 和crtEnd_android.o。crt1.o是crt0.o的后续演进版本,crt1.o中会非常重要的.init段和.fini段以及_start函数的入口..init段和.fini段实际上是靠crti.o以及crtn.o来实现的. init段是main函数之前的初始化工作代码, 比如全局变量的构造. fini段则负责main函数之后的清理工作.crti.o crtn.o是负责C的初始化,而C++则必须依赖crtbegin.o和crtend.o来帮助实现.
So,在标准的linux平台下,link的顺序是:ld crt1.o crti.o [user_objects] [system_libraries] crtn.o
而在android下,link的顺序是:arm-eabi-g++ crtBegin_dynamic.o [user_objects] [system_libraries] crtEnd_android.o
所以这就是从另一个方面说明为什么不适合codesourcery之类编译来开发android底层东西的原因了,这里我不包括BSP之类.
<2>.LOCAL_STATIC_LIBRARIES := //excute file 依赖的库
<3>.include $(BUILD_EXCUTEABLE)
在谈谈platform目录下的东西,这里面要说的是可能include和library中包含的头文件和library文件不太够,我们可以使用busybox for android把我们要的资料都给pull出来.或者编译android 源代码,需要的都东西都会有.
prebuilt目录下,有我们编译器的可执行文件,但是很不幸android toolchain不支持STL.目前支持STL有两种方法:
1.使用STLPort(据说这种方式不是太好)
2.重新编译使android toolchain 支持STL.
先看看android ndk的目录layout大概长的怎么样.
root
|------apps,所有你要编译的C和c++co
|------build
| |----platforms 下面目前为止放了3个sub fold,里面分别放了android 需要的include , library(提供的library有限)
| |------android 3 代表android 1.5
| |------android 4 代表android 1.6
| |------android 5 代表android 2.0
| |----prebuilt 该目录下存放toolchain的可执行档案,以及include & library.对于arm-eabi-4.4.0了解不多.
| |------arm-eabi-4.2.1
| |------------bin 所有的toolchain的excute file
| |------------arm-eabi
| |------include
| |------lib
| |----tools 这个目录下存放了很多有用的工具,包括下载,build toolchain
|------docs必须仔细读的文档
|------out生成的所有临时文件
先从docs开始谈,这个也是非常重要的一步。
1.纠正Android-mk.txt 中写的 ndk 只能编译出static library 和shared library,实际上他还提供了命令编译可执行程序.
a.include $(BUILD_SHARED_LIBRARY)
b.include $(BUILD_STATIC_LIBRARY)
c.include $(BUILD_EXECUTABLE)
理论上能编译出so文件,当然能编译出execute文件.只是ndk是否提供这个接口。
2.在apps目录下,新建一个目录,再建立project目录,这一级目录下建立Application.mk, 再建立一个sub fold “jni”, jni里面放的都是c和c++源代码,还有Android.mk.Android.mk就必须仔细写了.
常用的有LOCAL_PATH:=$(call my-dir)//访问当前path下的所有子目录,
<1>.LOCAL_DEBUG:=no|yes
<2>.LOCAL_OS:= linux //目标平台
<3>.LOCAL_ARCH:=arm //目标平台cpu
<4>.LOCAL_ARM_MODE:=arm //CPU指令集
<5>.COMMON_DEFINES += ISP=isp_arm9 -D_ARM_//这里通常会把要移植的library中的各种flag写在这里.(从待移植中的Configure或者Makefile中拷贝过来)
<6>.ifeq($(DEBUG),no)
COMMON_FLAGS += -s -O2 -fno-strict-aliasing -DNDEBUG -fno-rtti//好像都采用O2优化,fno-rtti 告诉C++不要runtime 中的一些support.
<7>.COMMON_COMPILE_FLAGS += -fPIC += -msoft-float +=march=armv5t
相对应的有了COMMON_XXX就有了LOCAL_XXX,
我们可以定义相关的
<1>.LOCAL_MODULE := libxxx //定义要编译的moule
<2>.LOCAL_CFLAGS := -I$(LOCAL_PATH)/xxx/include以及局部FLAG(从Configure或者Makefile中拷贝过来)//定义search .h fold
<3>.LOCAL_CXXFILES := //和上面是相同的,只是这个是C++的,上面的是C
<4>.LOCAL_SRC_FILES := XXX.c XXX.cpp XXX.hpp //定义源代码
<5>.include $(BUILD_STATIC_LIBRARY) 定义该模块是静态的
要编译到android上运行的excutable,还会依赖
<1>.LOCAL_LDLIBS := -L library_path -lxx //定义库的路径,以及要的library, 这里其实用的都是动态库.
在android中,有一个参数是:-dynamic-linker,/system/bin/linker ,采用的不是标准的linux下的ld.so.6(好像是这个数字,具体的不清楚了) ,而是/system/bin/linker来链接.这也是为什么我们用其他编译器(比如codesourcery)编译出来的东西不能在android上直接跑的原因,而一定要加上-static参数,也就是说用codesourcery编译出来的东西必须不依赖android的调度,而是靠编译时把所有的库全部加入.所以这时候写出来的helloworld都可能会有1~2Mb.提到了liner,就不得不提到android bionic,这个C runtime library设计并不是功能特别强大,并且有些gnu glic中的函数没有实现,这是移植时会碰到的问题.而且,这个C runtime library也并没有采用crt0.o,crt1.o,crti.o crtn.o,crtbegin.o crtend.o,而是采用了android自己的crtBegin_dynamic.o, crtBegin_static.o 和crtEnd_android.o。crt1.o是crt0.o的后续演进版本,crt1.o中会非常重要的.init段和.fini段以及_start函数的入口..init段和.fini段实际上是靠crti.o以及crtn.o来实现的. init段是main函数之前的初始化工作代码, 比如全局变量的构造. fini段则负责main函数之后的清理工作.crti.o crtn.o是负责C的初始化,而C++则必须依赖crtbegin.o和crtend.o来帮助实现.
So,在标准的linux平台下,link的顺序是:ld crt1.o crti.o [user_objects] [system_libraries] crtn.o
而在android下,link的顺序是:arm-eabi-g++ crtBegin_dynamic.o [user_objects] [system_libraries] crtEnd_android.o
所以这就是从另一个方面说明为什么不适合codesourcery之类编译来开发android底层东西的原因了,这里我不包括BSP之类.
<2>.LOCAL_STATIC_LIBRARIES := //excute file 依赖的库
<3>.include $(BUILD_EXCUTEABLE)
在谈谈platform目录下的东西,这里面要说的是可能include和library中包含的头文件和library文件不太够,我们可以使用busybox for android把我们要的资料都给pull出来.或者编译android 源代码,需要的都东西都会有.
prebuilt目录下,有我们编译器的可执行文件,但是很不幸android toolchain不支持STL.目前支持STL有两种方法:
1.使用STLPort(据说这种方式不是太好)
2.重新编译使android toolchain 支持STL.
关于如何使android toolchain 支持STL,我后续在谈.