一个Android.mk文件可以编译多个模块,每个模块属下列类型之一:
- APK程序-- 一般的Android程序,编译打包生成apk文件
- JAVA库 -- java类库,编译打包生成jar文件
- C\C++应用程序-- 可执行的C\C++应用程序
- C\C++静态库-- 编译生成C\C++静态库,并打包成.a文件
- C\C++共享库-- 编译生成共享库(动态链接库),并打包成.so文,有且只有共享库才能被安装/复制到您的应用软件(APK)包中。
可以在每一个Android.mk file 中定义一个或多个模块,你也可以在几个模块中使用同一个源代码文件。 编译系统为你处理许多细节问题。例如,你不需要在你的 Android.mk 中列出头文件和依赖文件。编译系统将会为你自动处理这些问题。这也意味着,在升级 NDK 后,你应该得到新的toolchain/platform支持,而且不需要改变你的 Android.mk 文件。
‘:=’是赋值的意思;'+='是追加的意思;‘$’表示引用某变量的值
自定义变量:
以下是在 Android.mk中依赖或定义的变量列表, 可以定义其他变量为自己使用,但是NDK编译系统保留下列变量名:
-以 LOCAL_开头的名字(例如 LOCAL_MODULE)
-以 PRIVATE_, NDK_ 或 APP_开头的名字(内部使用)
-小写名字(内部使用,例如‘my-dir’)
如果为了方便在 Android.mk 中定义自己的变量,建议使用 MY_前缀,一个小例子:
MY_SOURCES := foo.c
ifneq ($(MY_CONFIG_BAR),)
MY_SOURCES += bar.c
endif
LOCAL_SRC_FILES += $(MY_SOURCES)
GNU Make系统变量
include $( CLEAR_VARS) CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等...),除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的;
include $(BUILD_EXECUTABLE)编译应用程序;
include $(BUILD_STATIC_LIBRARY)编译静态库,静态库不会被复制到APK包中,但是能够用于编译共享库。这将会生成一个名为 lib$(LOCAL_MODULE).a的文件;
include $(BUILD_SHARED_LIBRARY)编译动态库,根据所有的在 LOCAL_XXX 变量把列出的源代码文件编译成一个共享库。注意,必须至少在包含这个文件之前定义 LOCAL_MODULE 和 LOCAL_SRC_FILES;
include $(BUILD_PACKAGE)编译应用程序APK;
include $(BUILD_PREBUILT)预编译应用程序;
TARGET_ARCH: 目标 CPU平台的名字;
TARGET_PLATFORM: Android.mk 解析的时候,目标 Android 平台的名字;
TARGET_ARCH_ABI: 暂时只支持两个 value,armeabi 和 armeabi-v7a;
TARGET_ABI: 目标平台和 ABI 的组合。
NDK提供的函数宏:
GNU Make函数宏,必须通过使用'$(call )'来调用,返回值是文本化的信息。
my-dir:返回当前 Android.mk 所在的目录的路径,相对于 NDK 编译系统的顶层。这是有用的,在 Android.mk 文件的开头如此定义:
LOCAL_PATH := $(call my-dir)
all-subdir-makefiles: 返回一个位于当前'my-dir'路径的子目录中的所有Android.mk的列表。
例如,某一子项目的目录层次如下:
src/foo/Android.mk
src/foo/lib1/Android.mk
src/foo/lib2/Android.mk
如果 src/foo/Android.mk 包含一行:include $(call all-subdir-makefiles) 那么它就会自动包含 src/foo/lib1/Android.mk 和 src/foo/lib2/Android.mk。
这项功能用于向编译系统提供深层次嵌套的代码目录层次。
注意,在默认情况下,NDK 将会只搜索在 src/*/Android.mk 中的文件。
- all-makefiles-under: 获取某个目录下及子目录的所有Android.mk。$(1):需要提取Android.mk的目录
- this-makefile: 返回当前Makefile 的路径(即这个函数调用的地方)
- parent-makefile: 返回调用树中父 Makefile 路径。即包含当前Makefile的Makefile 路径。
- grand-parent-makefile:返回调用树中父Makefile的父Makefile的路径
注意:在写Android.mk文件时,call all-subdir-makefiles和call all-makefiles-under,$(LOCAL_PATH)是有区别的。前者表示“当前目录下没有需要编译的文件,请向子目录深入”,是告诉编译器继续向目录深处递归的一种规定写法。后者从字面上理解也应该是同一个意思。
但是,请考虑这样一种情况:如果当前目录下有文件需要编译,而且在当前目录下还有子目录,子目录中也有文件需要编译,那么当前目录下的Android.mk除了要包含编译当前目录下文件的语句,同样也要包含告诉编译器在编译完当前目录下的文件后,继续向子目录深入的语句。这里就有一个问题,后面这个语句该如何写呢?是call all-subdir-makefiles,还是call all-makefiles-under,$(LOCAL_PATH)呢?写前者是不行的,编译器会在编译完当前目录下的文件后不再进入子目录编译,而写成后者则可以达到我们的期望。
常用模块描述变量:
每个模块都是以include $(CLEAR_VARS)开始,并且以include $(BUILD_XXX)结束(应用程序,静态库,动态库等)。
每个Android.mk文件以定义LOCAL_PATH为开始,它用于在开发tree中查找源文件LOCAL_PATH := $(call my-dir) my-dir宏是系统用来返回包含当前Android.mk的目录路径;
如果有多个module需要编译,可以放置多个目录,在每个目录编写一个Android.mk,然后在根目录的Android.mk中添加一行include $(call all-subdir-makefiles);
LOCAL_PATH:=当前文件的路径
LOCAL_MODULE:=这个模块的名字,LOCAL_MODULE变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。注意编译系统会自动产生合适的前缀和后缀,换句话说,一个被命名为'xxx'的共享库模块,将会生成'libxxx.so'文件。
LOCAL_MODULE_CLASS:=决定编译时的中间文件存放的位置;
LOCAL_MODULE_SUFFIX:=预编译程序模块的后缀;
LOCAL_MODULE_TAGS:= user/eng/tests/optional默认为optional:
- user: 指该模块只在user版本下才编译
- eng: 指该模块只在eng版本下才编译
- tests: 指该模块只在tests版本下才编译
- optional:指该模块在所有版本下都编译
如果两次make之间选了不同的编译模式,则需要运行一下make installclean,确保本次make不会用到上次install的文件,也可以运行make clean,不过耗时较长。
LOCAL_SRC_FILES:=要编译的源代码文件列表,多个文件见用空格或Tab间隔,换行用\,追加用LOCAL_SRC_FILES+=.变量必须包含将要编译打包进模块中的C或C++源代码文件。注意,你不用在这里列出头文件和包含文件,因为编译系统将会自动为你找出依赖型的文件;仅仅列出直接传递给编译器的源代码文件就好。可以LOCAL_SRC_FILES := $(call all-subdir-java-files)这种形式来包含LOCAL_PATH目录下的所有java文件;
LOCAL_PRELINK_MODULE:= 是否需要预连接处理(默认需要,用来做动态库优化);
LOCAL_REQUIRED_MODULES:= 指定模块运行所依赖的模块(模块安装时将会同步安装它所依赖的模块);
LOCAL_CERTIFICATE:=签名认证类型,默认为testkey。如果需要系统签名就等于platform,如果不需要就等于PRESIGNED;
LOCAL_C_INCLUDES: 可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录;
LOCAL_STATIC_LIBRARIES:= 该模块需要使用的静态链接库(*.a)的名字;
LOCAL_SHARED_LIBRARIES:= 模块在运行时需要用到的动态链接库(*.so)的名称;
LOCAL_COPY_HEADERS:= 安装应用程序时需要复制的头文件,必须同时定义LOCAL_COPY_HEADERS_TO;
LOCAL_COPY_HEADERS_TO:= 安装应用程序时复制头文件的目的路径;
LOCAL_OVERRIDES_PACKAGES:=使其他的模块不加入编译:
如:DeskClock模块的源码中的android.mk有
LOCAL_OVERRIDES_PACKAGES := AlarmClock
使AlarmClock不会加入到编译系统中,不会生成 AlarmClock.apk。(如果两个模块互相override对方,结果会怎样?应该是先编译到的模块屏蔽另一个模块);
LOCAL_BUILT_MODULE :=表示编译链接后的目标文件(文件路径+文件名);
LOCAL_BUILT_MODULE := $(built_module_path)/$(LOCAL_BUILT_MODULE_STEM);
LOCAL_BUILT_MODULE_STEM:= 表示编译链接后的目标文件的文件名,带后缀;
LOCAL_PACKAGE_NAME :=应用程序APK的名字;
LOCAL_MODULE_PATH和LOCAL_UNSTRIPPED_PATH来指定最后的目标安装路径。不同的文件系统路径用以下的宏进行选择:
1. TARGET_ROOT_OUT:表示根文件系统out/target/product/xxxxx/root。
2. TARGET_OUT:表示system文件系统out/target/product/xxxx/system。
3. TARGET_OUT_DATA:表示data文件系统out/target/product/xxxx/data。
4. TARGET_OUT_SHARED_LIBRARIES:表示out/target/product/xxxx/system/lib
5. TARGET_OUT_APPS:表示out/target/product/xxxx/system/app
6. ANDROID_PRODUCT_OUT:out/target/product/xxxx/
7. TARGET_OUT_JAVA_LIBRARIES:out/target/product/xxxx/system/framework
用法如:
LOCAL_MODULE_PATH:=$(TARGET_ROOT_OUT)
- LOCAL_JNI_SHARED_LIBRARIES:定义了要包含的so库文件的名字,如果程序没有采用jni,不需要
LOCAL_JNI_SHARED_LIBRARIES := libxxx
- LOCAL_CFLAGS:= 可选的编译器选项,在编译 C 代码文件的时候使用。这可能是有用的,指定一个附加的包含路径(相对于NDK的顶层目录),宏定义,或者编译选项。注意:不要在 Android.mk 中改变 optimization/debugging 级别,只要在 Application.mk 中指定合适的信息,就会自动地为你处理这个问题,在调试期间,会让NDK自动生成有用的数据文件。LOCAL_CFLAGS += -Dxxx这个就是你在源码定义的宏,需要定义的话就在这个参数上加上-Dxxx,前面加"-D",后面就是宏的名称了。
- LOCAL_LDLIBS:= 编译模块时要使用的附加的链接器选项。这对于使用‘-l’前缀传递指定库的名字是有用的。
例如,LOCAL_LDLIBS := -lz表示告诉链接器生成的模块要在加载时刻链接到/system/lib/libz.so(z是mk中定义的module name)
- LOCAL_INSTALLED_MODULE:= 表示模块的安装路径+文件名,存放的安装目录
- LOCAL_PRIVILEGED_MODULE := true,以声明app需要放在/system/priv-app下。
示例:
#编译静态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE = libhellos
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = hellos.c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_COPY_HEADERS_TO := libhellos
LOCAL_COPY_HEADERS := hellos.h
include $(BUILD_STATIC_LIBRARY)
#编译动态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE = libhellod
LOCAL_CFLAGS = $(L_CFLAGS)
LOCAL_SRC_FILES = hellod.c
LOCAL_C_INCLUDES = $(INCLUDES)
LOCAL_SHARED_LIBRARIES := libcutils
LOCAL_COPY_HEADERS_TO := libhellod
LOCAL_COPY_HEADERS := hellod.h
include $(BUILD_SHARED_LIBRARY)
#使用静态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hellos
LOCAL_STATIC_LIBRARIES := libhellos
LOCAL_LDLIBS += -ldl
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := mains.c
LOCAL_C_INCLUDES := $(INCLUDES)
include $(BUILD_EXECUTABLE)
#使用动态库
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hellod
LOCAL_MODULE_TAGS := debug
LOCAL_SHARED_LIBRARIES := libc libcutils libhellod
LOCAL_LDLIBS += -ldl
LOCAL_CFLAGS := $(L_CFLAGS)
LOCAL_SRC_FILES := maind.c
LOCAL_C_INCLUDES := $(INCLUDES)
include $(BUILD_EXECUTABLE)