上一篇只是谈到了大方向。有些具体的东西还是没有讲清楚,这次专门讲讲
android
ndk
.
先看看
android
ndk
的目录
layout
大概长的怎么样
.
root
|------
apps
,
所有你要编译的
C
和
c
++
code
都放到这个目录下。
|------
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
~
2
Mb
.
提到了
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
,
我后续在谈
.