LOCAL_MULTILIB
可以指定特定模块编译32bit或64bit或都编译。
其值可选择:
“both”: build both 32-bit and 64-bit.
“32”: build only 32-bit.
“64”: build only 64-bit.
“first”: build for only the first arch (32-bit in 32-bit devices and 64-bit in 64-bit devices).
“”: the default; the build system decides what arch to build based on the module class and other LOCAL_ variables, such as LOCAL_MODULE_TARGET_ARCH, LOCAL_32_BIT_ONLY, etc.
Android.mk支持通过下面变量配置仅编译32位。
LOCAL_32_BIT_ONLY := true
或者使用下面配置
TARGET_PREFER_32_BIT := true
all-subdir-makefiles
查找当前目录及子目录下的所有Android.mk,返回位于当前 my-dir
路径所有子目录中的 Android.mk
文件列表。
利用此函数,您可以为构建系统提供深度嵌套的源目录层次结构。默认情况下,NDK 只在 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,这项功能用于向编译系统提供深层次嵌套的代码目录层次。
my-dir
返回当前makefile所在目录,这个宏返回最后包括的 makefile 的路径,通常是当前 Android.mk 的目录。
my-dir 可用于在 Android.mk 文件开头定义 LOCAL_PATH。例如:
LOCAL_PATH := $(call my-dir)
由于 GNU Make 的工作方式,这个宏实际返回的是构建系统解析构建脚本时包含的最后一个 makefile 的路径。因此,包括其他文件后就不应调用 my-dir。
例如:
LOCAL_PATH := $(call my-dir) # ... declare one module include $(LOCAL_PATH)/foo/Android.mk LOCAL_PATH := $(call my-dir) # ... declare another module
这里的问题在于,对 my-dir 的第二次调用将 LOCAL_PATH 定义为 $PATH/foo,而不是 $PATH,因为这是其最近的 include 所指向的位置。
在 Android.mk 文件中的任何其他内容后指定额外的 include 可避免此问题。例如:
LOCAL_PATH := $(call my-dir) # ... declare one module LOCAL_PATH := $(call my-dir) # ... declare another module # extra includes at the end of the Android.mk file include $(LOCAL_PATH)/foo/Android.mk
如果以这种方式构造文件不可行,请将第一个 my-dir 调用的值保存到另一个变量中。例如:
MY_LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(MY_LOCAL_PATH) # ... declare one module include $(LOCAL_PATH)/foo/Android.mk LOCAL_PATH := $(MY_LOCAL_PATH) # ... declare another module
LOCAL_ARM_MODE
默认情况下,构建系统会以 thumb 模式生成 ARM 目标二进制文件,其中每条指令都是 16 位宽,并与 thumb/ 目录中的 STL 库链接。
将此变量定义为 arm 会强制构建系统以 32 位 arm 模式生成模块的对象文件。以下示例演示了如何执行此操作:
LOCAL_ARM_MODE := arm
您也可以对源文件名附加 .arm 后缀,指示构建系统仅以 arm 模式构建特定的源文件。例如,以下示例指示构建系统始终以 ARM 模式编译 bar.c,但根据 LOCAL_ARM_MODE 的值构建 foo.c。
LOCAL_SRC_FILES := foo.c bar.c.arm
您也可以在 Application.mk 文件中将 APP_OPTIM 设置为 debug,强制构建系统生成 ARM 二进制文件。指定 debug 会强制构建 ARM,因为工具链调试程序无法正确处理 Thumb 代码。
LOCAL_ALLOW_UNDEFINED_SYMBOLS
忽略链接错误,但是在运行中可能会出现错误,因为库文件找不到依赖的文件就会报错。
默认情况下,如果构建系统在尝试构建共享库时遇到未定义的引用,将会抛出“未定义的符号”错误。此错误可帮助您捕获源代码中的错误。
如需停用此检查,请将此变量设置为 true。请注意,此设置可能会导致共享库在运行时加载。
如果您为静态库定义此变量,构建系统会忽略此变量,并且 ndk-build 会显示一则警告。
LOCAL_LDFLAGS
表示链接时用的参数,此变量列出了构建系统在构建共享库或可执行文件时使用的其他链接器标记。
例如,若要在 ARM/X86 上使用 ld.bfd 链接器:
LOCAL_LDFLAGS += -fuse-ld=bfd
如果您为静态库定义此变量,构建系统会忽略此变量,并且 ndk-build 会显示一则警告。
LOCAL_LDLIBS
此变量列出了在构建共享库或可执行文件时使用的额外链接器标记。
利用此变量,您可使用 -l 前缀传递特定系统库的名称。例如,以下示例指示链接器生成在加载时链接到 /system/lib/libz.so 的模块:
LOCAL_LDLIBS := -lz
如需查看此 NDK 版本中可以链接的公开系统库列表,请参阅原生 API。
如果您为静态库定义此变量,构建系统会忽略此变量,并且 ndk-build 显示一则警告。
LOCAL_WHOLE_STATIC_LIBRARIES
此变量是 LOCAL_STATIC_LIBRARIES
的变体,表示链接器应将相关的库模块视为完整归档。如需详细了解完整归档,请参阅有关 --whole-archive
标记的 GNU Id 文档。
多个静态库之间存在循环依赖关系时,此变量十分有用。使用此变量构建共享库时,它将强制构建系统将静态库中的所有对象文件添加到最终二进制文件。但是,生成可执行文件时不会发生这种情况。
LOCAL_STATIC_LIBRARIES与LOCAL_WHOLE_STATIC_LIBRARIES的区别
LOCAL_STATIC_LIBRARIES
These are the static libraries that you want to include in your module. Mostly, we use shared libraries, but there are a couple of places, like executables in sbin and host executables where we use static libraries instead.
LOCAL_WHOLE_STATIC_LIBRARIES
These are the static libraries that you want to include in your module without allowing the linker to remove dead code from them. This is mostly useful if you want to add a static library to a shared library and have the static library’s content exposed from the shared library.
总的来说LOCAL_WHOLE_STATIC_LIBRARIES在连接静态连接库的时候不会移除”daed code”,何谓dead code呢,就是调用者模块永远都不会用到的代码段和变量。
可以得到如下的结论:
是否链接到调用者模块 | 使用了静态库的global变量 | 不使用 |
---|---|---|
LOCAL_STATIC_LIBRARIES | Y | N |
LOCAL_WHOLE_STATIC_LIBRARIES | Y | Y |
LOCAL_SHARED_LIBRARIES
此变量会列出此模块在运行时依赖的共享库模块。
此信息是链接时必需的信息,用于将相应的信息嵌入到生成的文件中。
LOCAL_STATIC_LIBRARIES
此变量用于存储当前模块依赖的静态库模块列表。
如果当前模块是共享库或可执行文件,此变量将强制这些库链接到生成的二进制文件。
如果当前模块是静态库,此变量只是指出依赖于当前模块的其他模块也会依赖于列出的库。
LOCAL_CPPFLAGS
只构建 C++ 源文件时将传递的一组可选编译器标记。
它们将出现在编译器命令行中的 LOCAL_CFLAGS
后面。使用 LOCAL_CFLAGS
为 C 和 C++ 指定标记。
LOCAL_CFLAGS
此可选变量用于设置在构建 C 和 C++ 源文件时构建系统要传递的编译器标记。这样,您就可以指定额外的宏定义或编译选项。可以使用 LOCAL_CPPFLAGS
仅为 C++ 指定标记。
请勿尝试在 Android.mk
文件中更改优化/调试级别。构建系统可以使用 Application.mk
文件中的相关信息自动处理此设置。这样,构建系统就可以生成供调试期间使用的有用数据文件。
您可通过输入以下代码指定额外的 include 路径:
LOCAL_CFLAGS += -I<path>,
但是,最好使用 LOCAL_C_INCLUDES
,因为这样也可以使用可用于 ndk-gdb 原生调试的路径。
LOCAL_C_INCLUDES
您可使用此可选变量指定相对于 NDK root
目录的路径列表,以便在编译所有源文件(C、C++ 和 Assembly)时添加到 include 搜索路径中。
例如:
LOCAL_C_INCLUDES := sources/foo
或者甚至:
LOCAL_C_INCLUDES := $(LOCAL_PATH)/<subdirectory>/foo
请在通过 LOCAL_CFLAGS
或 LOCAL_CPPFLAGS
设置任何对应的包含标记前定义此变量。
在使用 ndk-gdb 启动原生调试时,构建系统也会自动使用 LOCAL_C_INCLUDES
路径。
LOCAL_CPP_FEATURES
您可使用此可选变量指明您的代码依赖于特定 C++ 功能。
它会在构建过程中启用正确的编译器标记和链接器标记。
对于预构建的二进制文件,此变量还会声明二进制文件依赖于哪些功能,从而确保最终链接正常运行。
我们建议您使用此变量,而不要直接在 LOCAL_CPPFLAGS
定义中启用 -frtti
和 -fexceptions
。
使用此变量可让构建系统对每个模块使用适当的标记。使用 LOCAL_CPPFLAGS
会导致编译器将所有指定的标记用于所有模块,而不管实际需求如何。
例如,如需指明您的代码使用 RTTI(运行时类型信息),请写入:
LOCAL_CPP_FEATURES := rtti
如需指明您的代码使用 C++ 异常,请输入:
LOCAL_CPP_FEATURES := exceptions
您还可以为此变量指定多个值。例如:
LOCAL_CPP_FEATURES := rtti features
描述值的顺序无关紧要。
.cpp
以外的文件扩展名。例如,以下行将扩展名更改为 .cxx
(设置必须包含点)。
LOCAL_CPP_EXTENSION := .cxx
您可以使用此变量指定多个扩展名。例如:
LOCAL_CPP_EXTENSION := .cxx .cpp .cc
LOCAL_MODULE_RELATIVE_PATH
指定动态库的相对路径,以各自编译对象放置的目录为参考。
通知编译系统来将一个模块放置到它的类型通常需要放到的目录的子目录下。
举例:比如V4L2实现的Camera HAL3,代码路径:hardware/libhardware/modules/camera/3_4/Android.mk
LOCAL_MODULE_RELATIVE_PATH示例
LOCAL_MODULE_RELATIVE_PATH :=hw
将产生的库文件放在:vendor/lib64/hw下面。
LOCAL_SRC_FILES
此变量包含构建系统生成模块时所用的源文件列表。
只列出构建系统实际传递到编译器的文件,因为构建系统会自动计算所有相关的依赖项。
请注意,您可以使用相对(相对于 LOCAL_PATH
)和绝对文件路径。
建议您避免使用绝对文件路径;相对路径可以提高 Android.mk 文件的移植性。
务必在构建文件中使用 Unix 样式的正斜杠 (/)。构建系统无法正确处理 Windows 样式的反斜杠 (\)。
LOCAL_MODULE_PATH
表示模块生成的目标将最终存放的目录,也即目标的安装路径。
LOCAL_MODULE_CLASS用于制定LOCAL_MODULE_PATH的路径所在。
如果在Android.mk没有直接明确LOCAL_MODULE_PATH 的话,需要通过以下规则来自动生成base_rules.mk:
LOCAL_MODULE_PATH := $(strip $(LOCAL_MODULE_PATH)) ifeq ($(LOCAL_MODULE_PATH),) #LOCAL_MODULE_CLASS := LOCAL_MODULE_PATH := $($(my_prefix)OUT$(partition_tag)_$(LOCAL_MODULE_CLASS)) $(info *******//$(LOCAL_MODULE_PATH)) ifeq ($(strip $(LOCAL_MODULE_PATH)),) $(error $(LOCAL_PATH): unhandled LOCAL_MODULE_CLASS "$(LOCAL_MODULE_CLASS)") endif endif
在不同的Android.mk文件中,对于模块include()不同的编译类型选项,比如对于Library或者app,execut等在调用对应的处理mk文件时,会默认就指定当前的LOCAL_MODULE_CLASS的值,比如EXECUTABLES、SHARED_LIBRARIES等。所以在自己编写的Android.mk可不显示的指定LOCAL_MODULE_CLASS的值。
但当遇到 include $(BUILD_PREBUILT)
的预编译选项时不会指定模块模块编译输出的类型CLASS,需要在自己编写的Android.mk中明确指定LOCAL_MODULE_CLASS的值如ETC/APP等,使其值为非空,从而帮助系统确定LOCAL_MODULE_PATH的路径,比如最终编译输出 LOCAL_MODULE_PATH := $(TARGRT_OUT_ETC)
。
LOCAL_MODULE_PATH常用的取值
TARGET_OUT_INTERMEDIATES
TARGET_OUT_INTERMEDIATES := $(PRODUCT_OUT)/obj
示例:out/target/product/i9100/obj
TARGET_OUT_HEADERS
TARGET_OUT_HEADERS:= $(TARGET_OUT_INTERMEDIATES)/include
示例:out/target/product/i9100/obj/include
TARGET_OUT_INTERMEDIATE_LIBRARIES
TARGET_OUT_INTERMEDIATE_LIBRARIES := $(TARGET_OUT_INTERMEDIATES)/lib
示例:out/target/product/i9100/obj/lib
TARGET_OUT_COMMON_INTERMEDIATES
TARGET_OUT_COMMON_INTERMEDIATES := $(TARGET_COMMON_OUT_ROOT)/obj
示例:out/target/common/obj
TARGET_OUT
TARGET_OUT := (PRODUCT_OUT)/(TARGET_COPY_OUT_SYSTEM)
示例:out/target/product/i9100/system
TARGET_OUT_EXECUTABLES
TARGET_OUT_EXECUTABLES:= $(TARGET_OUT)/bin
示例:out/target/product/i9100/system/bin
TARGET_OUT_OPTIONAL_EXECUTABLES
TARGET_OUT_OPTIONAL_EXECUTABLES:= $(TARGET_OUT)/xbin
示例:out/target/product/i9100/system/xbin
TARGET_OUT_SHARED_LIBRARIES
TARGET_OUT_SHARED_LIBRARIES:= $(TARGET_OUT)/lib
示例:out/target/product/i9100/system/lib
TARGET_OUT_JAVA_LIBRARIES
TARGET_OUT_JAVA_LIBRARIES:= $(TARGET_OUT)/framework
示例:out/target/product/i9100/system/framework
TARGET_OUT_APPS
TARGET_OUT_APPS:= $(TARGET_OUT)/app
示例:out/target/product/i9100/system/app
TARGET_OUT_KEYLAYOUT
TARGET_OUT_KEYLAYOUT := $(TARGET_OUT)/usr/keylayout
示例:out/target/product/i9100/system/usr/keylayout
TARGET_OUT_KEYCHARS
TARGET_OUT_KEYCHARS := $(TARGET_OUT)/usr/keychars
示例:out/target/product/i9100/system/usr/keychars
TARGET_OUT_ETC
TARGET_OUT_ETC := $(TARGET_OUT)/etc
示例:out/target/product/i9100/system/etc
TARGET_OUT_NOTICE_FILES
TARGET_OUT_NOTICE_FILES:=$(TARGET_OUT_INTERMEDIATES)/NOTICE_FILES
示例:out/target/product/i9100/obj/NOTICE_FILES
TARGET_OUT_FAKE
TARGET_OUT_FAKE := $(PRODUCT_OUT)/fake_packages
示例:out/target/product/i9100/fake_packages
TARGET_OUT_DATA
TARGET_OUT_DATA := (PRODUCT_OUT)/(TARGET_COPY_OUT_DATA)
示例:out/target/product/i9100/data
TARGET_OUT_DATA_EXECUTABLES
TARGET_OUT_DATA_EXECUTABLES:= $(TARGET_OUT_EXECUTABLES)
示例:out/target/product/i9100/system/bin
TARGET_OUT_DATA_SHARED_LIBRARIES
TARGET_OUT_DATA_SHARED_LIBRARIES:= $(TARGET_OUT_SHARED_LIBRARIES)
示例:out/target/product/i9100/system/lib
TARGET_OUT_DATA_JAVA_LIBRARIES
TARGET_OUT_DATA_JAVA_LIBRARIES:= $(TARGET_OUT_JAVA_LIBRARIES)
示例:out/target/product/i9100/system/framework
TARGET_OUT_DATA_APPS
TARGET_OUT_DATA_APPS:= $(TARGET_OUT_DATA)/app
示例:out/target/product/i9100/data/app
TARGET_OUT_DATA_KEYLAYOUT
TARGET_OUT_DATA_KEYLAYOUT := $(TARGET_OUT_KEYLAYOUT)
示例:out/target/product/i9100/system/usr/keylayout
TARGET_OUT_DATA_KEYCHARS
TARGET_OUT_DATA_KEYCHARS := $(TARGET_OUT_KEYCHARS)
示例:out/target/product/i9100/system/usr/keychars
TARGET_OUT_DATA_ETC
TARGET_OUT_DATA_ETC := $(TARGET_OUT_ETC)
示例:out/target/product/i9100/system/etc
TARGET_OUT_DATA_NATIVE_TESTS
TARGET_OUT_DATA_NATIVE_TESTS := $(TARGET_OUT_DATA)/nativetest
示例:out/target/product/i9100/data/nativetest
TARGET_OUT_CACHE
TARGET_OUT_CACHE := $(PRODUCT_OUT)/cache
示例:out/target/product/i9100/cache
TARGET_OUT_VENDOR
TARGET_OUT_VENDOR := (PRODUCT_OUT)/(TARGET_COPY_OUT_VENDOR)
示例:out/target/product/i9100/system/vendor
TARGET_OUT_VENDOR_EXECUTABLES
TARGET_OUT_VENDOR_EXECUTABLES:= $(TARGET_OUT_VENDOR)/bin
示例:out/target/product/i9100/system/vendor/bin
TARGET_OUT_VENDOR_OPTIONAL_EXECUTABLES
TARGET_OUT_VENDOR_OPTIONAL_EXECUTABLES:= $(TARGET_OUT_VENDOR)/xbin
示例:out/target/product/i9100/system/vendor/xbin
TARGET_OUT_VENDOR_SHARED_LIBRARIES
TARGET_OUT_VENDOR_SHARED_LIBRARIES:= $(TARGET_OUT_VENDOR)/lib
示例:out/target/product/i9100/system/vendor/lib
TARGET_OUT_VENDOR_JAVA_LIBRARIES
TARGET_OUT_VENDOR_JAVA_LIBRARIES:= $(TARGET_OUT_VENDOR)/framework
示例:out/target/product/i9100/system/vendor/framework
TARGET_OUT_VENDOR_APPS
TARGET_OUT_VENDOR_APPS:= $(TARGET_OUT_VENDOR)/app
示例:out/target/product/i9100/system/vendor/app
TARGET_OUT_VENDOR_ETC
TARGET_OUT_VENDOR_ETC := $(TARGET_OUT_VENDOR)/etc
示例:out/target/product/i9100/system/vendor/etc
TARGET_OUT_UNSTRIPPED
TARGET_OUT_UNSTRIPPED := $(PRODUCT_OUT)/symbols
示例:out/target/product/i9100/system/symbols
TARGET_OUT_EXECUTABLES_UNSTRIPPED
TARGET_OUT_EXECUTABLES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/bin
示例:out/target/product/i9100/sysmbols/system/bin
TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED
TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED := $(TARGET_OUT_UNSTRIPPED)/system/lib
示例:out/target/product/i9100/sysmbols/system/lib
LOCAL_PROPRIETARY_MODULE
是否是Vendor专有模块。
Vendor模块是特定于供应商的可执行文件或共享库(必须将这些模块安装到供应商分区中)。
在 Android.bp
文件中,供应商模块必须将 vendor 或 proprietary 属性设为 true
。
在 Android.mk
文件中,供应商模块必须将 LOCAL_VENDOR_MODULE
或 LOCAL_PROPRIETARY_MODULE
设为 true
。
LOCAL_MODULE_CLASS 将用于决定编译时的中间文件存放的位置。
LOCAL_MODULE_CLASS在定义目标生成方式的makefile文件里定义,比如
- executable.mk里定义
LOCAL_MODULE_CLASS := EXECUTABLES
- 在recovery模块的Android.mk里定义的LOCAL_MODULE_CLASS有:
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES
其它的LOCAL_MODULE_CLASS有:
- LOCAL_MODULE_CLASS := ETC
- LOCAL_MODULE_CLASS := STATIC_LIBRARIES
- LOCAL_MODULE_CLASS := EXECUTABLES
- LOCAL_MODULE_CLASS := FAKE
- LOCAL_MODULE_CLASS := JAVA_LIBRARIES
- LOCAL_MODULE_CLASS := SHARED_LIBRARIES
- LOCAL_MODULE_CLASS := APPS
举例:比如说若 LOCAL_MODULE_CLASS := ETC ,那么该模块编译的中间文件将存放于 Cyanogenmod/target/product/m7ul/obj/ETC
LOCAL_MODULE_TAGS
模块的tag,为debug eng tests optional samples shell_ash shell_mksh等tag的组合,一个模块可有多个Tag。
user:指该模块只在user版本下才编译
eng:指该模块只在eng版本下才编译
tests:指该模块只在tests版本下才编译
optional:指该模块在所有版本下都编译
注意现在模块现在不能使用user作为模块的Tag,以前如果使用user做为tag,那么这个模块将被自动安装。
如果想定义自动安装的模块,需要在PRODUCT_PACKAGES变量里添加该模块。
该变量在build/target/product/base.mk和build/target/product/core.mk里有赋值,这是所有产品都将继承的基础配置, 另外每个设备可在自己的产品配置文件device_*.mk里设置该变量,添加更多的模块。
如果当前目录或者父目录有*_GPL*的文件,那么将自动添加gnu的tag。
示例,Camera2的Test模块
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_FILENAME
此可选变量使您能够替换构建系统为其生成的文件默认使用的名称。
例如,如果 LOCAL_MODULE
的名称为 foo
,您可以强制系统将其生成的文件命名为 libnewfoo
。以下示例演示了如何完成此操作:
LOCAL_MODULE := foo LOCAL_MODULE_FILENAME := libnewfoo
对于共享库模块,此示例将生成一个名为 libnewfoo.so
的文件。
无法替换文件路径或文件扩展名。
LOCAL_MODULE
此变量用于存储模块名称。LOCAL_MODULE将在每个模块的makefile里定义,如果未定义,编译系统会报错。
指定的名称在所有模块名称中必须唯一,并且不得包含任何空格。
您必须先定义该名称,然后才能添加任何脚本(CLEAR_VARS
的脚本除外)。
无需添加 lib
前缀或 .so
或 .a
文件扩展名;构建系统会自动执行这些修改。
在整个 Android.mk
和 Application.mk
文件中,请用未经修改的名称引用模块。例如,以下行会导致生成名为 libfoo.so
的共享库模块:
LOCAL_MODULE := "foo"
如果您希望生成的模块使用除“lib
+ LOCAL_MODULE
的值”以外的名称,可以使用 LOCAL_MODULE_FILENAME 变量为生成的模块指定自己选择的名称。
LOCAL_PATH
每个模块都在Android.mk里定义,表示模块所在目录。
此变量用于指定当前文件的路径。必须在 Android.mk
文件开头定义此变量。以下示例演示了如何定义此变量:
LOCAL_PATH的作用
有人就问了,在本Android.mk中又没有使用到LOCAL_PATH,为什么先 要定义这么一个变量呢?为什么规定必须放在所有的include $(CLEAR_VARS)之前呢?
哪里在使用LOCAL_PATH
在Android.mk中我们发现有LOCAL_SRC_FILES := acp.的定义,NDK文件中对LOCAL_SRC_FILES 的说明如下:
This is a list of source files that will be built for your module. Only list the files that will be passed to a compiler, since the build system automatically computes dependencies for you.
Note that source files names are all relative to LOCAL_PATH and you can use path components.
因此在定义LOCAL_SRC_FILES 时已经间接的使用到了LOCAL_PATH变量,即定义LOCAL_SRC_FILES是用的基于当前路径的相对路径。
为什么必须在$(CLEAR_VARS)之前
我们接着看看为什么LOCAL_PATH的定义必须要放到所有的include $(CLEAR_VARS)之前。
LOCAL_PATH通过调用my-dir函数来获取当前的路径,my-dir函数的定义位于core/definitions.mk文件:
请注意,这里明确的说明了LOCAL_PATH的定义必须要放在任何include (CLEAR_VARS)语句之前,如果不这么做的话,编译就直接报错,停止不干了。
可是它是怎么判断LOCAL_PATH的定义是在任何include(CLEAR_VARS)语句之前呢,我们看到有这么一句话:
$(if $(filter $(CLEAR_VARS),$(md_file_))
这个判断语句是个关键,我们先看看CLEAR_VARS变量的定义,在build/core/config.mk中有如下明确的定义:
CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk
而BUILD_SYSTEM的定义在build/core/main.mk文件中:
BUILD_SYSTEM := $(TOPDIR)build/core
紧接着:
TOPDIR :=
即TOPDIR为android源码的根目录, BUILD_SYSTEM= build/core, 所以CLEAR_VARS变量的值就为build/core/clear_vars.mk,当然这个也是相对于Android源码根路径。
得到了CLEAR_VARS变量的值,我们再回到my-dir函数中。
根据gnu make定义,gnu make 会自动将所有读取的makefile路径都会加入到MAKEFILE_LIST变量中,而且是按照读取的先后顺序添加。
那么,在运行本makefile文件时,$(MAKEFILE_LIST) 字符串中最后一个makefile肯定是最后读取的makefile,即(lastword(MAKEFILE_LIST))
则会返回build/tools/acp/Android.mk,此字符串经过$(eval md_file_ := (lastword(MAKEFILE_LIST))
运算,赋值给了临时变量md_file_。
判断md_file_中是否包含CLEAR_VARS变量的值(if(filter (CLEAR_VARS),(md_file_))
,肯定也就会返回失败,再通过(patsubst %/,%,(dir $(md_file_)))
函数,则会得到当前路径,即build/tools/acp
如果我们在include $(CLEAR_VARS)之后,再调用my-dir函数,那么(lastword(MAKEFILE_LIST))
肯定就会返回$(BUILD_SYSTEM)/clear_vars.mk,同时,(patsubst %/,%,(dir $(md_file_)))
也就会返回$(BUILD_SYSTEM)的值build/core,而不是当前的路径build/tools/acp。
这么一来得到的LOCAL_PATH的值就是错误的值,依赖LOCAL_PATH的其他变量也就更加不可能是正确的了!所以说 ,LOCAL_PATH必须要在任何including $(CLEAR_VARS))之前定义 。
BUILD_NATIVE_TEST
用于本地代码测试,会自动包含 gtest 依赖项。
BUILD_NATIVE_TEST := $(BUILD_SYSTEM)/native_test.mk
使用语法:
include $(BUILD_NATIVE_TEST)
BUILD_HOST_JAVA_LIBRARY
编译为主机上运行的java库。
BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk 使用语法:
include $(BUILD_HOST_JAVA_LIBRARY)
BUILD_STATIC_JAVA_LIBRARY
编译为java库,用于sdk开发 。
BUILD_STATIC_JAVA_LIBRARY:= $(BUILD_SYSTEM)/static_java_library.mk
使用语法:
include $(BUILD_STATIC_JAVA_LIBRARY)
与BUILD_JAVA_LIBRARY的区别
BUILD_JAVA_LIBRARY生成目标设备上的共享JAVA库
BUILD_STATIC_JAVA_LIBRARY生成静态JAVA库
二者的区别在于静态JAVA库是由.class文件打包而成JAR包,它在任何一个JAVA虚拟机上都可以运行;而共享JAVA库则是在静态库的基础上进一步打包成的.dex文件,众所周知,dex是在android系统上所使用的文件格式。
BUILD_JAVA_LIBRARY
编译为java库 。
BUILD_JAVA_LIBRARY:= $(BUILD_SYSTEM)/java_library.mk
使用语法:
include $(BUILD_JAVA_LIBRARY)
BUILD_MULTI_PREBUILT
多个prebuilt目标的makefile。
BUILD_MULTI_PREBUILT:= $(BUILD_SYSTEM)/multi_prebuilt.mk
使用语法:
include $(BUILD_MULTI_PREBUILT)
BUILD_PREBUILT
生成预编译可执行文件的makefile,主要用于生成手机上可执行程序。
BUILD_PREBUILT:= $(BUILD_SYSTEM)/prebuilt.mk
使用语法:
include $(BUILD_PREBUILT)
BUILD_HOST_PREBUILT
生成主机上预编译可执行文件的makefile,主要是一些编译工具。
BUILD_HOST_PREBUILT:= $(BUILD_SYSTEM)/host_prebuilt.mk
使用语法:
include $(BUILD_HOST_PREBUILT)
BUILD_PHONY_PACKAGE
生成伪目标的makefile。
BUILD_PHONY_PACKAGE:= $(BUILD_SYSTEM)/phony_package.mk
使用语法:
include $(BUILD_PHONY_PACKAGE)
BUILD_PACKAGE
生成手机app的makefile。
BUILD_PACKAGE:= $(BUILD_SYSTEM)/package.mk
使用语法:
include $(BUILD_PACKAGE)
BUILD_HOST_EXECUTABLE
编译成主机可执行文件使用的makefile。
BUILD_HOST_EXECUTABLE:= $(BUILD_SYSTEM)/host_executable.mk
使用语法:
include $(BUILD_HOST_EXECUTABLE)
BUILD_EXECUTABLE
编译成可执行文件使用的makefile。
BUILD_EXECUTABLE:= $(BUILD_SYSTEM)/executable.mk
使用语法:
include $(BUILD_EXECUTABLE)
BUILD_SHARED_LIBRARY
编译成动态库使用的makefile。
BUILD_SHARED_LIBRARY:= $(BUILD_SYSTEM)/shared_library.mk
使用语法:
include $(BUILD_SHARED_LIBRARY)
BUILD_STATIC_LIBRARY
编译成静态库使用的makefile。
BUILD_STATIC_LIBRARY:= $(BUILD_SYSTEM)/static_library.mk
使用语法:
include $(BUILD_STATIC_LIBRARY)
BUILD_HOST_STATIC_LIBRARY
编译成主机静态库使用的makefile。
BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk
如在Linux平台上编译的,这里就是编译Linux平台的静态库,因为是在PC上编译Android系统通过交叉编译,所以能生成Linux平台上可运行的动态静态库(不能在手机端运行)。
使用语法:
include $(BUILD_HOST_STATIC_LIBRARY)
CLEAR_VARS
由编译系统提供,指定让GNU MAKEFILE为你清除许多LOCAL_XXX变量(例如 LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES, 等等…),使用语法如下:
include $(CLEAR_VARS)
这是必要的,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。
可以在 android 安装目录下的/build/core/config.mk 文件看到其定义,为 CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk