一.基础知识
1.Android.mk文件可以将源码打包成模块,模块可以是apk,jar包,c/c++应用程序,静态库和动态库。动态库可以被以到应用程序包apk,静态库可以被连接入动态库。
2.Android.mk中可以定义一个或者多个模块,一个源文件也可以打包进入多个模块中。
二.变量
1.LOCAL_ASSET_FILES
编译APK文件时用于指定资源列表,通常写成LOCAL_ASSET_FILES+= $(call find-subdir-assets).
2.LOCAL_CC
自定义C编译器来代替缺省的编译器.
3.LOCAL_CXX
自定义C++编译器来代替缺省的编译器.
4.LOCAL_CFLAGS
定义额外的C/C++编译器的参数.
5.LOCAL_CPPFLAGS
仅定义额外的C/C++编译器的参数,不用在C编译器中.
6.LOCAL_CPP_EXTENSION
自定义C++源文件的后缀。例如:LOCAL_CPP_EXTENSION:=.cc
接着用LOCAL_SRC_FILES:=*.cc
7.LOCAL_C_INCLUDES
指定头文件的搜索路径
8.LOCAL_FORCE_STATIC_EXECUTABLE
如果编译时候需要链接的库有共享和静态两者共存的情况。设定
此变量为true将会优先链接静态库。通常这种情况只会在编译root/sbin目录
的应用才会用到,因为他们执行的时间比较早,文件系统的其他部分有加载。
9.LOCAL_GENERATED_SOURCES
指定由系统自动生成的文件列表
10.LOCAL_MODULE_TAGS
定义模块标签,Build系统根据标签决定哪些模块被安装。
user: 指该模块只在user版本下才编译
eng: 指该模块只在eng版本下才编译
tests: 指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译
11.LOCAL_REQUIRED_MODULES
指定依赖的模块,一旦本模块被安装,通过此变量指定的模块也将被安装
12.LOCAL_JAVACFLAGS
定义额外的javac编译器的参数
13.LOCAL_JAVA_LIBRARIES
指定模块依赖的java共享库
14.LOCAL_LDFLAGS
定义链接器ld的参数
15.LOCAL_LDLIBS
指定模块链接时依赖的库。如果这些库文件不存在,并不会引发对她的编译,
这是此变量和LOCAL_SHARED_LIBRARIES的主要区别。
如果某一个库既有动态库又有静态库,那么默认情况下是链接的动态库而非静态库。
LOCAL_LDLIBS += -lm -lz -llog
对比LOCAL_SHARED_LIBRARIES会生成依赖关系,当库不存在时会去编译这个库。
16.LOCAL_NO_MANIFEST
在一个资源apk中可以指定此变量为true,表示此apk文件没有AndroidManifest.xml文件。
17.LOCAL_PACKAGE_NAME
指定APP应用名称
18.LOCAL_PATH
指定Android.mk文件所在的目录
LOCAL_PATH := $(call my-dir)
指定当前模块的目录
19.LOCAL_POST_PROCESS_COMMAND
在编译host相关的模块时,可以用此变量定义一条命令在link完成后执行
20.LOCAL_PREBUILT_LIBS
指定预编译c/c++动态和静态库列表,用于预编译模块定义中
21.LOCAL_PREBUILT_JAVA_LIBRARIES
指定预编译java库列表,用于预编译模块定义中
22.LOCAL_SHARED_LIBRARIES
指定模块依赖的c/c++共享库列表
23.LOCAL_MODULE
除应用(apk)以LOCAL_PACKAGE_NAME指定模块名以外,其余的
都以LOCAL_MODULE指定模块名
24.LOCAL_MODULE_PATH
指定模块在目标系统的安装路径
25.LOCAL_UNSTRIPPED_PATH
指定模块的unstripped版本在out目录下的保存路径
26.LOCAL_WHOLE_STATIC_LIBRARIES
这个变量也是定义了模块依赖的静态库列表,和LOCAL_STATIC_LIBRARIES类似
但是通过这个变量定义,链接时链接器不会将静态库中国无人调用的代码去掉
27.LOCAL_YACCFLAGS
指定yacc的参数
28.LOCAL_ADDITIONAL_DEPENDENCIES
指定本模块的依赖,用在不方便使用别的方法来指定依赖关系时
29.LOCAL_BUILT_MODULE
指定编译时存放中间文件的目录
30.LOCAL_INSTALLED_MODULE
指定模块的安装路径
31.LOCAL_MODULE_CLASS
定义模块的分类,根据分类,生成的模块文件会安装到目标系统相应目录下,
例如:
APPS: 安装到/system/app下;
SHARED_LIBRARIE:安装到/system/lib下;
EXECUTABLES:安装到/system/bin下;
ETC:安装到/system/etc/下;
但是如果同时用LOCAL_MODULE_PATH定义了路径,则安装到该路径。
32.LOCAL_MODULE_NAME
指定模块的名称。但是目前系统中用到它的实例;
33.LOCAL_MODULE_SUFFIX
指定当前模块的后缀,一旦指定,系统在产生目标文件时,会以模块后缀来创建目标文件
34.LOCAL_STRIP_MODULE
指定模块是否需要被strip,该模块是可执行文件或动态库才能使用该变量
35.LOCAL_STRIPPABLE_MODULE
此变量的值通常由build系统设置,一般可执行文件和动态库被设为true
36.LOCAL_SYSTEM_SHARED_LIBRARIES
此变量在编译系统的基本库,如libc, libm.libdl时,用来定义这个库的依赖库,
通常在应用模块定义中不应使用该变量
37.LOCAL_PRELINK_MODULE
编译.so模块时,定义是否需要prelink,prelink是通过预链接的方式加快程序启动速度
如果要设置此值为true,要现在build/core/prelink-linux-arm.map文件中定义该
库的地址和大小,否则报错,但是在Android4.2以后的代码中找不到文件prelink-linux-arm.map
在build目录下也搜索不到这个变量,可能android已经取消了prelink的功能。
38.include $(CLEAR_VARS)
清除LOCAL_PATH以外的所有LOCAL_XXX,除LOCAL_PATH之外.
39.LOCAL_STATIC_LIBRARIES
指定使用的C/C++静态库列表
40.LOCAL_STATIC_JAVA_LIBRARIES
指定依赖的静态java类库
41.LOCAL_CERTIFICATE
指定签名认证
42.LOCAL_SDK_VERSION
指定编译Android应用程序时的SDK版本
43.条件编译
ifeq ($(SIM_COUNT), 2)
LOCAL_CFLAGS += -DANDROID_SIM_COUNT_2
else ifeq($(SIM_COUNT), 3)
LOCAL_CFLAGS += -DANDROID_SIM_COUNT_3=3
endif
44.在Android Build系统中声明了很多编译类型:Java 库,C/C++ 库,APK 应用,以及可执行文件等,并且Java 或者 C/C++ 库还可以分为静态的或者动态的,库或可执行文件既可能是针对设备的也可能是针对主机的或者模拟器的,不同的模块的编译声明和方法是不一样的,在config.mk中声明了模块类型,如下:
include ($BUILD_EXECUTABLE)
指定编译方法
BUILD_HOST_STATIC_LIBRARY 编译静态库(适用于主机)
BUILD_HOST_SHARED_LIBRARY 编译动态库(适用于主机)
BUILD_HOST_EXECUTABLE 编译可执行程序(适用于主机)
BUILD_HOST_PREBUILT 预编译(适用于主机)
BUILD_HOST_JAVA_LIBRARY 编译java包(适用于主机)
BUILD_STATIC_LIBRARY 编译静态库
BUILD_SHARED_LIBRARY 编译动态库
BUILD_EXECUTABLE 编译为可执行程序
BUILD_JAVA_LIBRARY 编译为java包
BUILD_STATIC_JAVA_LIBRARY 编译java静态包
BUILD_PACKAGE 编译为Android应用程序apk
BUILD_PREBUILT 预编译(针对单个预编译文件)
BUILD_MULTI_PREBUILT 预编译(针对多个预编译文件)
45.LOCAL_INIT_RC
用于将服务相关的RC文件编译到相应位置。
例如drmserver的Android.mk中,通过LOCAL_INIT_RC将drmserver对应的drmserver.rc编译到/system/etc/init目录中.
46.call命令
$(call my-dir):获取当前文件夹路径。
$(call all-java-files-under, <src>):获取指定目录下的所有 Java 文件。
$(call all-c-files-under, <src>):获取指定目录下的所有 C 语言文件。
$(call all-Iaidl-files-under, <src>) :获取指定目录下的所有 AIDL 文件。
$(call all-makefiles-under, <folder>):获取指定目录下的所有 Make 文件。
$(call intermediates-dir-for, <class>, <app_name>, <host or target>, <common?> ):获取 Build 输出的目标文件夹路径。
47.LOCAL_AAPT_FLAGS
AAPT(Android Asset Packaging Tool)在SDK的tools/目录下. 该工具可以查看, 创建, 更新ZIP格式的文档附件(zip, jar, apk). 也可将资源文件编译成二进制文件,尽管你可能没有直接使用过aapt工具, 但是build scripts和IDE插件会使用这个工具打包apk文件构成一个Android 应用程序.
48.LOCAL_JNI_SHARED_LIBRARIES:
LOCAL_JNI_SHARED_LIBRARIES变量主要是用在JNI的编译中,如果你要在你的Java代码中引用JNI中的共享库*.so,此变量就是共享库的名字。
那么你要注意的一点是:在你的Project根目录下的Android.mk中要定义此变量用来引用你要使用的JNI中的共享库*.so。
定义了要包含的so库文件的名字,如果程序没有采用jni,不需要LOCAL_JNI_SHARED_LIBRARIES := libxxx 这样在编译的时候,NDK自动会把这个libxxx打包进apk; 放在youapk/lib/目录下LOCAL_REQUIRED_MODULES 指定模块运行所依赖的模块(模块安装时将会同步安装它所依赖的模块)
49.LOCAL_AIDL_INCLUDES
用声明aidl文件所在目录(不包括包名!)
LOCAL_SRC_FILES声明aidl文件
注意:有对应.java文件的aidl文件不需要声明,这里声明的是需要在build目录生成.java文件的aidl文件.
50.LOCAL_PROTOC_OPTIMIZE_TYPE
protocol相关配置
三.使用预编译动态库模块
使用一个编译好的库来使编译过程加快,并且开发人员向外不用提供源码,而是以动态库的形式提供。
1.声明预编译模块
使用预编译库必须声明为一个独立的模块。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libc
LOCAL_SRC_FILES := libc.so
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/libc
include $(PREBUILT_SHARED_LIBRARY)
注意:LOCAL_EXPORT_C_INCLUDES定义确保了任何依赖这个预编译库的模块会自动在自己的LOCAL_C_INCLUDES 变量中增加到这个预编译库的include目录的路径,从而能够找到其中的头文件。预编译模块不需要编译,因此可以打打减少编译耗时。
2.引用预编译模块
通过第一步声明了预编译模块之后,如果test.c依赖于libc.so,即可以使用LOCAL_SHARED_LIBRARIES列出当前模块的依赖列表。
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES:= test.c
LOCAL_SHARED_LIBRARIES := libc
include $(BUILD_EXECUTABLE)
3.BUILD_PREBUILT
这种方式把文件当成编译项目,在Android.mk中copy一个file:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) \
LOCAL_MODULE := usb_modeswitch.conf \
LOCAL_MODULE_CLASS := ETC \
LOCAL_MODULE_PATH := $(TARGET_OUT)/etc \
LOCAL_SRC_FILES :=$(LOCAL_MODULE) \
include $(BUILD_PREBUILT)
上面的就是copy usb_modeswitch.conf 文件到 OUT 下面的 etc目录,这个目录常用来存放配置相关文件。
四.构建动态库模块
include $(CLEAR_VARS)
LOCAL_C_INCLUDES:=$(LOCAL_PATH)/include #定义源文件所需的头文件所需的目录
LOCAL_MODULE:=libhello-android #定义编译出来的模块名
LOCAL_SHARED_LIBRARIES := liblog #编译此模块需要依赖的动态库
LOCAL_SRC_FILES := src/hello-android.c #定义编译模块所需的源文件
include $(BUILD_SHARED_LIBRARY)
五.android.mk中的嵌套
include $(call all-subdir-makefiles) 用于向编译系统提供深层次嵌套的代码目录层次。
include $(call all-makefiles-under, $(LOCAL_PATH)) 一般使用这种方式
include $(addprefix $(LOCAL_PATH)/, 1/Andriod.mk 2/Android.mk 3/Android.mk)
六.LOCAL_PROGUARD_ENABLE的使用
在我们编译Android系统的user版本的时候,有时候会出现proguard的错误,在解决这个错误之着,我们需要了解一些知识:
1.proguard是用来干什么的?
用来做JAVA代码混淆的一个工具。
2.这个东西在哪里实现的?
我们一般会在Android.mk文件中对其进行支持,比如:
1>指定不需要混淆的native方法和变量的proguard.flags文件 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
2>对使用与不使用进行设定:
<1>.制定编译的工程,不需要使用代码混淆的工具进行代码混淆:LOCAL_PROGUARD_ENABLE := disable.
<2>.如果不设置,我们默认使用LOCAL_PROGUARD_ENABLE := full 意思就是将该工程代码全部混淆.
3.怎么解决?
比如,我们在 Android 的项目中使用了JNI,当使用了proguard后,会发现native方法有很多变量找不到,仔细分析后你会发现,原因是被progurad优化掉了,所以,我们建议在JNI应用中应该慎用progurad。既然发现了,可我们想用progurad啊,怎么办呢?
1>在Android.mk中加入如下代码:
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
2>在proguard.flags文件中加入不需要proguard优化的类和方法,比如Browser中:
-keep class com.android.browser.preferences.*
七.android系统中的编译和clean
1.编译
make 编译的模块名 -jn
2.clean
make clean-编译的模块名 -jn
八.Android.mk中信息的打印
直接打印变量
1.$(info $(var))
$(info "output message")
利用shell echo重定向到文件
2.$(shell echo $(var)) > $(LOCAL_PATH)/log.txt
九.实例
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test
LOCAL_SRC_FILES := test.c
include $(BUILD_EXECUTABLE)