NDK(10)Android.mk
1.官方文档
https://developer.android.google.cn/ndk/guides/android_mk
2. Android.mk简介
Android.mk文件是GNU Makefile的一小部分,它用来对Android程序进行编译.一个Android.mk文件可以编译多个模块,
每个模块属下列类型之一.[APK程序, JAVA库, C\C++应用程序, C\C++静态库(.a) , C\C++共享库(.so)]
示例
1 LOCAL_PATH := $(call my-dir) 2 include $(CLEAR_VARS) 3 LOCAL_MODULE := helloworld 4 LOCAL_SRC_FILES := helloworld.c 5 include $(BUILD_SHARED_LIBRARY)
3.对照讲解
1 LOCAL_PATH := $(call my-dir) 2 { 3 首先需要指定LOCAL_PATH变量,用于查找源文件 4 上面的语句的意思是将LOCAL_PATH变量定义成本文件所在目录路径 5 } 6 7 #Android.mk中可以定义多个编译模块,每个编译模块都是以include $(CLEAR_VARS)开始 8 #以include $(BUILD_XXX)结束。 9 include $(CLEAR_VARS) //开始 10 { 11 问: CLEAR_VARS是什么?? 12 答: CLEAR_VARS由编译系统提供,指定让GNU MAKEFILE为你清除除LOCAL_PATH以外的所有LOCAL_XXX变量, 13 如LOCAL_MODULE,LOCAL_SRC_FILES,LOCAL_SHARED_LIBRARIES,LOCAL_STATIC_LIBRARIES等。 14 } 15 #包含的头文件 16 LOCAL_C_INCLUDES += \ 17 hardware/led/include/ 18 19 LOCAL_PRELINK_MODULE := false // :=是赋值的意思 20 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw 21 { 22 //LOCAL_MODULE_PATH: 最后的目标安装路径 23 24 问: TARGET_OUT_SHARED_LIBRARIES是什么? 25 答: 在build/core/envsetup.mk中定义。TARGET_OUT_SHARED_LIBRARIES:= $(TARGET_OUT)/lib 26 TARGET_ROOT_OUT:表示根文件系统。 27 TARGET_OUT:表示system文件系统。 28 TARGET_OUT_DATA:表示data文件系统。 29 30 } 31 LOCAL_SHARED_LIBRARIES := liblog //LOCAL_SHARED_LIBRARIES中加入所需要链接的动态库(*.so)的名称 32 LOCAL_SRC_FILES := led.cpp 33 LOCAL_MODULE :=led.default //LOCAL_MODULE表示模块最终的名称 34 #LOCAL_MODULE的定义规则,led后面跟有default,led.default能够保证我们的模块总能被硬象抽象层加载到 35 LOCAL_MODULE_TAGS := eng 36 include $(BUILD_SHARED_LIBRARY) // 结束 37 { 38 include $(BUILD_STATIC_LIBRARY)表示编译成静态库 39 include $(BUILD_SHARED_LIBRARY)表示编译成动态库。 40 include $(BUILD_EXECUTABLE)表示编译成可执行程序 41 } 42 43 LOCAL_SRC_FILES中加入源文件路径,LOCAL_C_INCLUDES 中加入所需要包含的头文件路径, 44 LOCAL_STATIC_LIBRARIES加入所需要链接的静态库(*.a)的名称, 45 LOCAL_SHARED_LIBRARIES中加入所需要链接的动态库(*.so)的名称, 46 LOCAL_MODULE表示模块最终的名称,BUILD_EXECUTABLE表示以一个可执行程序的方式进行编译。 47 48 49 50 hardware\led\Android.mk 51 include $(call all-subdir-makefiles) 52 53 54 frameworks\base\services\forlinx_led_jni\LedService.cpp 55 frameworks\base\services\forlinx_led_jni\Android.mk 56 { 57 58 LOCAL_PATH:= $(call my-dir) //LOCAL_PATH变量定义成本文件所在目录路径 59 include $(CLEAR_VARS) 60 61 # [optional, user, eng] 62 # eng = required 63 # optinal = no install on target 64 LOCAL_MODULE_TAGS := eng 65 { 66 LOCAL_MODULE_TAGS :=optional -->> out/target/product/OK6410/symbols/system/ 67 LOCAL_MODULE_TAGS :=eng -->> out/target/product/Ok6410/system/ 68 } 69 70 # This is the target being built. 71 LOCAL_MODULE:= libforlinx_runtime 72 73 # Target install path. 74 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) 75 76 # All of the source files that we will compile. 77 LOCAL_SRC_FILES:= \ 78 LedService.cpp 79 80 # All of the shared libraries we link against. 81 LOCAL_SHARED_LIBRARIES := \ 82 libandroid_runtime \ 83 libcutils \ 84 libhardware \ 85 libhardware_legacy \ 86 libnativehelper \ 87 libsystem_server \ 88 libutils \ 89 libui \ 90 libsurfaceflinger_client 91 92 93 # Also need the JNI headers. 94 LOCAL_C_INCLUDES += \ 95 $(JNI_H_INCLUDE) \ 96 hardware/led/include 97 98 99 # No specia compiler flags. 100 LOCAL_CFLAGS += 101 { 102 LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays 103 通过设定编译器操作,优化级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高 104 LOCAL_CFLAGS += -W -Wall 105 LOCAL_CFLAGS += -fPIC -DPIC 106 LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter 107 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY 108 LOCAL_CFLAGS += -DUSEOVERLAY2 109 根据条件选择相应的编译参数 110 } 111 112 # Don't prelink this library. For more efficient code, you may want 113 # to add this library to the prelink map and set this to true. 114 LOCAL_PRELINK_MODULE := false 115 { 116 Prelink利用事先链接代替运行时链接的方法来加速共享库的加载,它不仅可以加快起动速度,还可以减少部分内存开销, 117 是各种Linux架构上用于减少程序加载时间、缩短系统启动时间和加快应用程序启动的很受欢迎的一个工具。程序运行时的 118 动态链接尤其是重定位(relocation)的开销对于大型系统来说是很大的。 119 动态链接和加载的过程开销很大,并且在大多数的系统上, 函数库并不会常常被更动, 每次程序被执行时所进行的链接 120 动作都是完全相同的,对于嵌入式系统来说尤其如此。因此,这一过程可以改在运行时之前就可以预先处理好,即花一些时间 121 利用Prelink工具对动态共享库和可执行文件进行处理,修改这些二进制文件并加入相应的重定位等信息,节约了本来在程序 122 启动时的比较耗时的查询函数地址等工作,这样可以减少程序启动的时间,同时也减少了内存的耗用。 123 Prelink的这种做法当然也有代价:每次更新动态共享库时,相关的可执行文件都需要重新执行一遍Prelink才能保 124 证有效,因为新的共享库中的符号信息、地址等很可能与原来的已经不同了,这就是为什么 android framework代码一改动, 125 这时候就会导致相关的应用程序重新被编译。 126 这种代价对于嵌入式系统的开发者来说可能稍微带来一些复杂度,不过好在对用户来说几乎是可以忽略的。 127 } 128 129 include $(BUILD_SHARED_LIBRARY) 130 }
4.各属性或变量介绍
详细请参看 :源码目录 build/core/build-system.html 搜索 Android.mk variables ,从它向下看。
模块描述变量 | |
LOCAL_PATH * |
一个Android.mk file首先必须定义好LOCAL_PATH变量。它用于在开发树中查找源文件。在这个例子中,宏函数’my-dir’, 由编译系统提供,用于返回当前路径(即包含Android.mk file文件的目录). 这个变量用于给出当前文件的路径。必须在 Android.mk 的开头定义,可以这样使用: LOCAL_PATH := $(call my-dir) 这个变量不会被$(CLEAR_VARS)清除,因此每个 Android.mk 只需要定义一次(即使在一个文件中定义了几个模块的情况下) |
CLEAR_VARS |
由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量 (例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等.), 除LOCAL_PATH 。这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的 |
LOCAL_MODULE * |
变量必须定义,以标识你在Android.mk文件中描述的每个模块。名称必须是唯一的,而且不包含任何空格。 注意编译系统会自动产生合适的前缀和后缀,一个被命名为'foo'的共享库模块,将会生成'libfoo.so'文件 |
LOCAL_SRC_FILES |
这是要编译的源代码文件列表。只要列出要传递给编译器的文件,因为编译系统自动计算依赖。
注意源代码文件名称都是相对于 LOCAL_PATH的,你可以使用路径部分,例如:
LOCAL_SRC_FILES := foo.c toto/bar.c Hello.c
如果是追加源代码文件的话,请用LOCAL_SRC_FILES +=
注意:可以LOCAL_SRC_FILES := $(call all-subdir-java-files)这种形式来包含local_path目录下的所有java文件
|
LOCAL_CPP_EXTENSION |
这是一个可选变量, 用来指定C++代码文件的扩展名,默认是'.cpp',但是可以改变它,比如:
LOCAL_CPP_EXTENSION := .cxx
|
LOCAL_C_INCLUDES |
可选变量,表示头文件的搜索路径。默认的头文件的搜索路径是LOCAL_PATH目录。示例:
LOCAL_C_INCLUDES := sources/foo 或 LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo
LOCAL_C_INCLUDES需要在任何包含LOCAL_CFLAGS/LOCAL_CPPFLAGS标志之前进行设置
|
LOCAL_CFLAGS | 可选的编译器选项,在编译 C 代码文件的时候使用。这可能是有
用的,指定一个附加的包含路径(相对于NDK的顶层目录),宏定义,或者编译选项.
注意:不要在 Android.mk 中改变 optimization/debugging 级别,只要在 Application.mk 中指定合适的信息,
就会自动地为你处理这个问题,在调试期间,会让 NDK自动生成有用的数据文件。
|
LOCAL_CXXFLAGS | 与 LOCAL_CFLAGS同理,针对 C++源文件 |
LOCAL_CPPFLAGS | 与 LOCAL_CFLAGS同理,但是对 C 和 C++ source files都适用 |
LOCAL_STATIC_LIBRARIES | 表示该模块需要使用哪些静态库,以便在编译时进行链接 |
LOCAL_SHARED_LIBRARIES |
表示模块在运行时要依赖的共享库(动态库),在链接时就需要,以便在生成文件时嵌入其相应的信息。 注意:它不会附加列出的模块到编译图,也就是仍然需要在Application.mk 中把它们添加到程序要求的模块中 |
LOCAL_LDLIBS | 编译模块时要使用的附加的链接器选项。这对于使用‘-l’前缀传递指定库的名字是有用的
例如,LOCAL_LDLIBS := -lz表示告诉链接器生成的模块要在加载时刻链接到/system/lib/libz.so
可查看 docs/STABLE-APIS.TXT 获取使用 NDK发行版能链接到的开放的系统库列表
|
LOCAL_ALLOW_UNDEFINED_SYMBOLS | 默认情况下, 在试图编译一个共享库时,任何未定义的引用将导致一个“未定义的符号”错误。
这对于在源代码文件中捕捉错误会有很大的帮助。然而,如果因为某些原因,需要不启动这项检查,
可把这个变量设为‘true’。注意相应的共享库可能在运行时加载失败。(这个一般尽量不要去设为 true)
|
LOCAL_ARM_MODE |
默认情况下, arm目标二进制会以 thumb 的形式生成(16 位),你可以通过设置这个变量为 arm, 如果你希望你的 module 是以 32 位指令的形式。'arm' (32-bit instructions) mode. E.g.: LOCAL_ARM_MODE := arm
注意:可以在编译的时候告诉系统针对某个源码文件进行特定的类型的编译,比如;
LOCAL_SRC_FILES := foo.c bar.c.arm
|
LOCAL_MODULE_PATH |
用LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH指定最后的目标安装路径.
TARGET_ROOT_OUT:表示根文件系统。
TARGET_OUT:表示 system文件系统
TARGET_OUT_DATA:表示 data文件系统。
如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT)
|
LOCAL_UNSTRIPPED_PATH |
用LOCAL_MODULE_PATH 和LOCAL_UNSTRIPPED_PATH指定最后的目标安装路径 如:LOCAL_MODULE_PATH :=$(TARGET_ROOT_OUT) |
自定义变量 | |
可以定义变量为自己使用,如: MY_SOURCES := foo.c |
可以定义变量为自己使用,但是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‘功能’宏 | |
my-dir |
返回当前 Android.mk 所在的目录的路径,相对于 NDK 编译系统的顶层。这是有用的, 在 Android.mk 文件的开头如此定义 LOCAL_PATH := $(call my-dir)
|
all-subdir-makefiles |
返回一个位于当前'my-dir'路径的子目录中的所有Android.mk的列表 例如,看下面的目录层次:
sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk
如果 sources/foo/Android.mk 包含一行:
include $(call all-subdir-makefiles)
那么它就会自动包含 sources/foo/lib1/Android.mk 和 sources/foo/lib2/Android.mk。
这项功能用于向编译系统提供深层次嵌套的代码目录层次。
注意,在默认情况下,NDK 将会只搜索在 sources/*/Android.mk 中的文件
|
this-makefile | 返回当前Makefile 的路径(即这个函数调用的地方) |
parent-makefile | 返回调用树中父 Makefile 路径。即包含当前Makefile的Makefile 路径 |
grand-parent-makefile | 返回调用树中父Makefile的父Makefile的路径 |
5.Android.mk 常用模板
5.1编译APK应用程序模板
目标文件夹为 XXX_intermediates
关于编译APK应用程序的模板请参照《Android.mk编译APK模板》
5.2 编译JAVA库模板
1 LOCAL_PATH := $(call my-dir) 2 include $(CLEAR_VARS) 3 # Build all java files in the java subdirectory 4 LOCAL_SRC_FILES := $(call all-subdir-java-files) 5 # Any libraries that this library depends on 6 LOCAL_JAVA_LIBRARIES := android.test.runner 7 # The name of the jar file to create 8 LOCAL_MODULE := sample 9 # Build a static jar file. 10 include $(BUILD_STATIC_JAVA_LIBRARY)
注:LOCAL_JAVA_LIBRARIES := android.test.runner表示生成的JAVA库的jar文件名
5.3 编译C/C++应用程序模板
1 LOCAL_PATH := $(call my-dir) 2 #include $(CLEAR_VARS) 3 LOCAL_SRC_FILES := main.c 4 LOCAL_MODULE := test_exe 5 #LOCAL_C_INCLUDES := 6 #LOCAL_STATIC_LIBRARIES := 7 #LOCAL_SHARED_LIBRARIES := 8 include $(BUILD_EXECUTABLE)
5.4 编译C\C++静态库模板
1 LOCAL_PATH := $(call my-dir) 2 include $(CLEAR_VARS) 3 LOCAL_SRC_FILES := \ 4 helloworld.c 5 LOCAL_MODULE:= libtest_static 6 #LOCAL_C_INCLUDES := 7 #LOCAL_STATIC_LIBRARIES := 8 #LOCAL_SHARED_LIBRARIES := 9 include $(BUILD_STATIC_LIBRARY)
5.5 编译C\C++动态库的模板
1 LOCAL_PATH := $(call my-dir) 2 include $(CLEAR_VARS) 3 LOCAL_SRC_FILES := helloworld.c 4 LOCAL_MODULE := libtest_shared 5 TARGET_PRELINK_MODULES := false 6 #LOCAL_C_INCLUDES := 7 #LOCAL_STATIC_LIBRARIES := 8 #LOCAL_SHARED_LIBRARIES := 9 include $(BUILD_SHARED_LIBRARY)