1. 概述
Android.mk
文件是用来描述build system
(编译系统)的,更准确的说:该文件是一个微型的GNU Makefile
片段,将由build system
解析一次或者多次。
这个文件的目的是用来允许你将源文件组织成模块,这个模块中含有:一个静态库(.a文件) 或 一个动态库(.so文件)
只有动态库才会被安装/复制到你的应用程序包,尽管静态库可以被用来生成动态库。
你可以在每个模块中 都定义一个Android.mk
文件,你也可以让多个模块共用一个Android.mk
文件。build system
可以为你处理许多细节,
例如:你不需要在Android.mk
文件中列出头文件或者其他的依赖关系,这些NDK的build system会自动为你计算并处理。
这也意味着,当更新到新版本的NDK的时候,你应该得益于新的toolchain/platform
的支持,而无需修改你的Android.mk
文件。
注意:
这些语法非常接近于分布在完整的开源的Android源代码中的Android.mk
文件,尽管是build system实现的,但是它们的用法是不同的。这样故意设计的决定是为了让应用程序开发者重用“外部”库的源代码更容易。
2. 实例分析
jni/Android.mk
文件描述了如何生成一个共享库,它的内容是:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
1. LOCAL_PATH:=$(call my-dir) ----------必须
Android.mk
文件必须以LOCAL_PATH
变量开始,它用于在树中定位文件。
宏功能my-dir
是由build system
提供的,用于返回当前目录路径(包括Android.mk
文件本身)
2. include $(CLEAR_VARS) ----------必须
CLEAR_VARS
变量是由build system
提供的,并且指明了一个GNU makefile
文件,这个功能会清理掉所有以LOCAL_
开头的内容(例如 LOCAL_MODULE
,LOCAL_SRC_FILES
,LOCAL_STATIC_LIBRARIES
等),除了LOCAL_PATH
,这句话是必须的,因为如果所有的变量都是全局变量的话,所有的可控的编译文件都需要在一个单独的GNU中被解析并执行
3. LOCAL_MODULE :=hello-jni
LOCAL_MODULE
变量必须被定义,用来区分Android.mk
中的每一个模块。文件名必须是唯一的,不能有空格。
注意:
这里编译器会为你自动加上一些前缀 lib
和后缀.so
,来保证文件是一致的,
比如:这里表明一个动态连接库模块被命名为hello-jni
,但是最后会生成为libhello-jni.so
文件。
但是在Java中装载这个库的时候还是使用"hello-jni"名称。当然如果我们使用"IMPORTANT NOTE:" 编译系统就不会为你加上前缀
但是为了支持Android平台源码中的Android.mk
文件,也同样会生成libhello-jni.so
这样的文件。
如果你将你的模块命名为libfoo
,编译系统将不会将前缀lib
加上去,并且也会生成libfoo.so
文件。
4. LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES
变量被需包括一个C
和C++
源文件的列表,这些会编译并聚合到一个模块中。
注意:
- 这里并不需要你列出
头文件
和被包含
的文件,因为编译系统会自动为你计算相关的属性,源代码中的列表会直接传递给编译器。C++
默认文件的扩展名是.cpp
,我们可以通过定义一个LOCAL_DEFAULT_CPP_EXTENSION
变量来定义一个不同的C
文件。
不要忘记在初始化前面的.
点(也就是说.cpp
可以正常工作,但是cpp
不能正常工作)
5. include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY
这个变量是由系统提供的,并且指定给GNU Makefile
的脚本,
它可以收集所有你定义的include $(CLEAR_VARS)
中以LOCAL_
开头的变量,并且决定哪些要被编译,哪些应该做的更加准确。
编译生成的是以lib<module_name>.so
的文件,这个就是共享库了。
我们同样也可以使用BUILD_STATIC_LIBRARY
编译系统便会生成一个以lib<module_name>.a
的文件来供动态库调用。
6. LOCAL_SHORT_COMMANDS := true /flase
当你的module
有很多的源文件,或者依赖很多的静态或动态库。这会强制编译系统使用一个中间的列表文件,并通过@$(listfile)
语法和library archiver
或者 static linker
一起使用。
这在Windows上是非常有用的,因为它的命令行只接收最大8191个字符,这对于复杂的工程来说太小了。 这同样也会影响单个源文件的编译,如果将所有的编译器选项放在列表文件里面。
注意:
- 如果设置了
true
以外的值,都会恢复成默认行为。
你也可以在Android.mk文件中定义APP_SHORT_COMMANDS来强制使你的工程中的所有modules使用这项功能- 默认我们不推荐启用这个功能,因为它会使得编译变慢。
该变量可以解决如下编译问题:make: execvp: /home/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++: Argument list too long
特别注意:
APP_SHORT_COMMANDS
,LOCAL_SHORT_COMMANDS
可以解决链接时参数太长的问题(生成*.a *.so时中间文件过多)然而,编译,生成libcrypto.so
时,- 在
libcrypto
模块中采用LOCAL_SHORT_COMMANDS:=true
来指定会导致编译错误 - 在
Application.mk
中指定APP_SHORT_COMMANDS:=true
可以顺利编译链接
- 在