主要来源:Secrets of Android.mk (翻译+整理)
这篇文档描述了用于向Android NDK解释你的C/C++源文件的Android.mk构建文件的语法。为了理解接下来的内容,我们假设你已经阅读了解释它们角色和使用场景的文档。
编写Android.mk文件是用来向编译系统描述你的源文件。更具体的说:
- 这个文件实际是GNUMakefile的一个极小的片段,它会被编译系统解析一次或多次。因此,你应该在文件中尽量少定义变量,并且不要假设在解析过程中没有定义任何东西。
- 文件语法的目的是让你将自己的源文件分成模块。模块的内容可以是以下之一:
只有共享库才会被安装/拷贝到你的应用程序包。静态库可以用来生成共享库。
在Android.mk文件中,你可以定义一个或多个模块,在多个模块中也可以使用相同的源文件。
- 编译系统将会为你处理很多细节。例如,你不需要在Android.mk中列出生成的文件之间的头文件或其他显示依赖关系。NDK编译系统将会自动为你计算这些内容。
这也意味着,更新NDK新版本时,你将会从新工具链/平台中受益,而无需去修改你的Android.mk文件。
请注意,该语法与AOSP中使用的Android.mk非常接近。尽管使用它们的编译系统实现是不同的,但这是一个刻意的决定,这会使应用程序开发者更容易地重用“外部”库的源代码。
简单例子
在详细介绍语法之前,我们先考虑一个简单的“JNIHello”示例。文件如下:
apps/hello-jni/project
这里,我们可以看到:
- “src”目录包含了这个简单Android工程的Java源文件
- “jni”目录包含了这个示例的native源文件。如,”jni/hello-jni.c”
这个源文件实现了一个简单的共享库,它实现了一个native方法,用于向VM应用返回一个字符串。
- ‘jni/Android.mk’文件向NDK编译系统描述了一个共享库。它的内容是:
-
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)
现在,让我们来解释这些行:
LOCAL_PATH := $(call my-dir)
一个Android.mk文件必须以LOCAL_PATH变量的定义开头。它用于在开发树中定位源文件。在此例中,宏函数’my-dir’由编译系统提供,用来返回当前目录的路径(包含Android.mk文件的目录自身)
include $(CLEAR_VARS)
CLEAR_VARS变量又编译系统提供,它指向一个GNU Makefile脚本;它会为你清除很多除LOCAL_PATH之外的LOCAL_XXXX变量,如LOCAL_MODULE、LOCAL_SRC_FILES、LOCAL_STATAIC_LIBRARIES。这是必须的,因为所有的编译控制文件都是在同一个GNU编译执行环境中解析的,并且这些变量都是全局的。
LOCAL_MODULE :=hello-jni
必须定义LOCAL_MODULE变量来标识你在Android.mk中描述的每个模块。它的值必须唯一且不包含任何空格。要注意,编译系统会自动为生成的文件添加适当的前缀和后缀。换句话说,一个名为’foo’的共享库会生成为’libfoo.so’。
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES必须包含一个C/C++源文件的列表,它会被构建并组装到模块中。注意,你不应该在这列出头文件和已经包含的文件,因为编译系统会自动计算这些依赖;只需要列举出将直接传递给编译器的源文件,这对你来说就行了。
注意,默认的C++源文件的扩展名是’.cpp’。当然你也可以通过指定LOCAL_CPP_EXTENSION变量去指定其他的扩展名。不要忘记那个最开始的点(如,’.cxx’会起作用;但’cxx’就不会)。
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY变量由编译系统提供,它指向一个GNU Makefile脚本,负责收集自
最近地’include$(CLEAR_VARS)’之后的所有你定义的LOCALL_XXX变量信息,并确定需要构建什么,以及如何正确地构建它。BUILD_STATIC_LIBRARY可以用来生成一个静态库。
示例目录中有更复杂的示例,可以查看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)
我们继续:
NDK提供的变量:
这些GNU Make变量是在你的Android.mk被解析之前由编译系统定义的。注意,在某些情况下,NDK也许会多次解析你的Android.mk,每次这些变量都会有不同的定义。
CLEAR_VARS
指向一个重新定义在某个模块描述之下列举出的几乎所有LOCAL_XXX变量的构建脚本。在开始一个新模块之前,你必须包含这个脚本,如:
Include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY
指向一个收集所有关于某个模块的你提供的LOCAL_XXX变量信息,并决定如何以你提供的源文件列表编译出一个目标共享库的构建脚本。注意,在包含这个文件之前,你必须至少定义过LOCAL_MODULE和LOCAL_SRC_FILES。示例用法:
Include $(BUILD_SHARED_LIBRARY)
注意,这将会生成一个名为lib$(LOCAL_MODULE).so的文件。
BUILD_STATIC_LIBRARY
BUILD_SHARED_LIBRARY的一种变体,用来编译一个目标静态库。静态库不会被拷贝到你的工程/包中,但是它们可以用来构建共享库(参考下面的LOCAL_STATIC_LIBRARY和LOCAL_WHOLE_STATIC_LIBRARIES描述)。示例用法:
Include $(BUILD_STATIC_LIBRARY)
注意,这将会生成一个名为lib$(LOCAL_MODULE).a的文件。
PREBUILT_SHARED_LIBRARY
指向一个用于指定预编译共享库(提前编译好的第三方库,可以加速编译过程)的构建脚本。与BUILD_SHARED_LIBRARY、BUILD_STATIC_LIBRARY不同,LOCAL_SRC_FILES变量的值必须是指向预编译库的单一路径(如,foo/libfoo.so),而不是一个源文件。你可以在其他模块中通过使用LOCAL_PREBUILTS变量来引用预编译共享库。
Eg:
I. 声明一个预编译库的模块
对于Android编译工具而言,每个预编译库必须声明为一个独立的模块。这里举一个例子,假设 libfoo.so 文件与 Android.mk 位于同一个目录:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := foo-prebuilt
LOCAL_SRC_FILES := libfoo.so
include $(PREBUILT_SHARED_LIBRARY)
按以下步骤声明这样一个模块:
1. 给该模块取一个名字(这里是 foo-prebuilt)。这个名字不需要与预编译库自身的名字相同。
2. 将 LOCAL_SRC_FILES 指定为你要提供的共享库的路径。通常,该路径是相对于 LOCAL_PATH 的路径。注意:必须保证共享库ABI的兼容性。
3. 如果你的库是共享库,则包含 PREBUILT_SHARED_LIBRARY 而不是 BUILD_SHARED_LIBRARY;如果是静态库,则包含PREBUILT_STATIC_LIBRARY。
预编译模块不需要编译。该预编译模块会被拷贝到$PROJECT/obj/local 下面,还会被拷贝到$PROJECT/libs/
II. 在其他模块中引用这个预编译库
在依赖该预编译库的模块对应的Android.mk中,将预编译库的名字(前面取的)加入到 LOCAL_STATIC_LIBRARIES 或 LOCAL_SHARED_LIBRARIES 声明中。例如,一个使用上面libfoo.so的简单例子如下:
include $(CLEAR_VARS)
LOCAL_MODULE := foo-user
LOCAL_SRC_FILES := foo-user.c
LOCAL_SHARED_LIBRARIES := foo-prebuilt
include $(BUILD_SHARED_LIBRARY)
PREBUILT_STATIC_LIBRARY
这与PREBUILT_SHARED_LIBRARY一样,但是只适用于静态库。
TARGET_ARCH
目标CPU架构的名称,由完整的Android开源项目构建指定。对于任何ARM兼容的版本来说,它的值是’arm’,这独立于CPU架构版本。
TARGET_PLATEFORM
Android.mk被解析时,目标Android平台的名称。例如,’android-3’相当于Android 1.5系统镜像。
TARGET_ARCH_ABI
......
TARGET_ABI
......
接下来的是GNU Make 函数宏,必须通过使用’$(call
my-dir
返回最近被包含的Makefile的路径,典型地就是当前Android.mk的目录。它用于在你的Android.mk开始处定义LOCAL_PATH变量,例如:
LOCAL_PATH := $(call my-dir)
特别注意,由于GNU Make的工作方式,它会真实地返回在解析构建脚本过程中最近包含的Makefile路径。不要在包含其他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,这是因为脚本包含动作在它之前执行。
因为这个理由,在Android.mk完成所有事情之后再添加额外的包含会更好:
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
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
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的路径,即包含当前Android.mk的Makefile的路径。
grand-parent-makefile
无需多说……
import-module
一个允许你通过名字找到并且包含另一个模块Android.mk的方法。一个典型的示例是:
$(call import-module,
这会从你的NDK_MODULE_PATH环境变量所引用的目录列表中,找到指定名字的模块,并自动为你包含它的Android.mk文件。NDK_MODULE_PATH需要自己指定,请参看相关部分。
接下来的变量都用于向编译系统描述你的模块。你应该在'include $(CLEAR_VARS)'和'include $(BUILD_XXXXX)'之间定义其中的某些变量。正如前面所写,除非明确指出,$(CLEAR_VARS)是一个会清空所有这些变量定义的脚本。
LOCAL_PATH
这个变量用于给出当前文件的路径。我们必须在Android.mk文件开始位置定义它,如下面这样做:
LOCAL_PATH:= $(call my-dir)
这个变量不会被$(CLEAR_VARS)清除,所以在每个Android.mk中对它定义一次即可(例如你在一个文件中定义了多个模块)。
LOCAL_MODULE
这是你模块的名字。它的值在所有模块名字中必须唯一,并且不能包含任何空格。你必须在包含任何$(BUILD_XXXX)脚本之前定义它。
默认情况下,模块名称决定了生成的文件的名称,如模块名为
你可以使用LOCAL_MODULE_FILENAME变量覆盖此默认值。
LOCAL_MODULE_FILENAME
这个变量是可选的,它允许你重新定义生成文件的名字。默认情况下,模块
你可以通过定义LOCAL_MODULE_FILENAME来覆盖它,如:
LOCAL_MODULE := foo-version-1
LOCAL_MODULE_FILENAME := libfoo
注意,你不应该在LOCAL_MODULE_FILENAME
中填入路径或文件扩展名,
编译系统会为自动为你处理这些。
LOCAL_SRC_FILES
这是一个编译你的模块需要的源文件的列表。只有列举出的文件才会被传递给编译器,因为编译系统会自动为你计算依赖。
注意,源文件的名称都是相对于LOCAL_PATH变量而言的,所以你可以使用路径组件,如:
LOCAL_SRC_FILES:= foo.c \
toto/bar.c
注意,在构建文件中应该总是使用Unix风格的正斜杠(/)。Windows风格的正斜杠无法被正确处理。
LOCAL_CPP_EXTENSION
这个变量是可选的,它用来指定C++源文件的扩展名。默认值是’.cpp”,但是你可以改变它。如:
LOCAL_CPP_EXTENSION:= .cxx
NDK r7开始,你可以为此变量定义一个扩展名列表,如:
LOCAL_CPP_EXTENSION:= .cxx .cpp .cc
LOCAL_CPP_FEATURES
这个变量是可选的,它被用来指定你的代码明确要依赖的C++特性。为了表明你的代码需要使用RTTI,可以向下面这样:
LOCAL_CPP_FEATURES:= rtti
要表明你的代码需要使用异常,可以这样:
LOCAL_CPP_FEATURES:= exceptions
你也可以同时使用它们(顺序不重要):
LOCAL_CPP_FEATURES:= rtti exceptions
这个变量的影响是:在使用源文件构建你的模块时,为编译器/连接器使能正确的标志位。对于预先构建的二进制文件,这也会帮助声明它要依赖的特性,从而确保最终的链接工作能正确完成。
相比于在你的LOCAL_CPPFLAGS定义中直接使能-frtti和-fexceptions,我们更推荐使用LOCAL_CPP_FEATURES
变量。
LOCAL_C_INCLUDES(包含头文件)
一个可选的、相对于NDK根目录,在编译所有源文件时(C/C++,汇编)会被添加到包含搜索路径中的一个(头文件)路径列表。如:
LOCAL_C_INCLUDES:= sources/foo
或者
LOCAL_C_INCLUDES:= $(LOCAL_PATH)/../foo
它们会在LOCAL_CFLAGS /LOCAL_CPPFLAGS中相应的标志之前被添加。
在使用ndk-gdb启动本地调试时,LOCAL_C_INCLUDES
路径为被自动使用。
LOCAL_CFLAGS
一个可选的、在编译C/C++源文件时会被传入的编译器标志位集合。它可以被用来指定附加的宏定义或编译选项。
重要地:不要尝试在你的Android.mk中改变优化/调试等级,编译系统会通过你在Android.mk中指定的切当信息,为你自动处理;同时让NDK在调试期间生成有用的数据文件。
注意:在android-ndk-1.5_r1中,该变量中的flag只会应用于C文件,而不是C++。为了匹配完整地Android构建系统行为,这已经被修正了(现在你可以使用LOCAL_CPPFLAGS仅为C++文件指定flag)
使用LOCAL_CFLAGS +=-I
LOCAL_CXXFLAGS
LOCAL_CPPFLAGS的一个别名。注意,使用此标致已过时,因为在以后的NDK版本中,它可能会消失。
LOCAL_CPPFLAGS
仅在构建C++源文件时,被传递给编译器的编译标志集合。在编译器的命令行中,它们会出现在LOCAL_CFLAGS之后。
注意:在Inandroid-ndk-1.5_r1,相应的标志位会同时应用于C和C++源文件。为了匹配完整地Android编译系统,这已经被修复了。(现在我们可以使用LOCAL_CFLAGS同时为C/C++指定标志)。
LOCAL_STATIC_LIBRARIES
该模块需要链接的静态库(由BUILD_STATIC_LIBRARY构建,.a文件)列表。该变量只对共享库模块起作用。
LOCAL_SHARED_LIBRARIES
模块运行时需要依赖的共享库模块列表。这在链接时是必要的,并会将相应的信息嵌入到生成文件中。(会生成依赖关系,当依赖的库不存在时,会去编译它)
LOCAL_WHOLE_STATIC_LIBRARIES
LOCAL_STATIC_LIBRARIES的一个变体,它用来告诉链接器相应的库模块要被当做“whole archives”来使用。具体可以查看GNU链接器文档 –whole-archive标志。
当多个静态库模块之间存在环形依赖时,它会很有用。注意,当用于构建共享库时,这会强制将所有静态库中的所有对象文件添加到最后生成的二进制文件中。当构建可执行文件时,这不会为真。
LOCAL_LDLIBS
构建模块时被使用的附加的链接标志列表。在使用”-l”前缀向系统指定系统库时很有用。如,下面的声明将告诉链接器在加载时生成一个链接到/system/lib/libz.so的模块:
LOCAL_LDLIBS:= -lz
(不会产生依赖关系,即如果z模块没有,不会去编译它)
LOCAL_ALLOW_UNDEFINED_SYMBOLS
默认情况下,在编译一个共享库时,遇到任何未定义的引用都将会导致“undefined symbol”错误。这对捕获你代码中的漏洞是很有帮助的。
但是,如果处于某些理由,你想禁用这个检查,可以将这个变量设为“true”。注意,相应的共享库在运行时也许会出现加载失败。
LOCAL_ARM_MODE
默认情况下,ARM平台的二进制文件将会在“thumb”模式下生成,每个指令宽度都是16位。如果你想强制让模块对象在‘ARM’模式下(32位指令)生成,可以将该变量的值定义成‘arm’:
LOCAL_ARM_MODE := arm
注意,你可以通过在源文件名称的末尾加上‘.arm’后缀,来命令构建系统仅在ARM模式下编译特定的文件。如:
LOCAL_SRC_FILES := foo.c bar.c.arm
这将会告诉编译系统bar.c将总是在ARM模式下编译,而foo.c将根据LOCAL_ARM_MODE的值来决定编译模式。
注意,在你的Android.mk中将APP_OPTIM设置为’debug’也会导致A生成ARM的二进制文件。这是因为在‘thumb’代码下,交叉工具链的debugger还无法很好的工作。
LOCAL_ARM_NEON
将这个变量的值定义为‘true’,你就可以在你的C/C++源文件中使用NEON GCC内链,或在汇编文件中使用NEON指令。
在使用次变量时,我们要确保目标平台的CPU架构支持相应的指令集;否则,程序将不会正常工作。
我们可以通过为某个文件指定’.neon’后缀,来让它以NEON模式编译,如:
LOCAL_SRC_FILES= foo.c.neon bar.c zoo.c.arm.neon
这个例子中,’foo.c’将会以thumb + neon模式编译,’bar.c’将会以thumb模式编译,’aoo.c’将会以arm + neon模式编译。
注意,如果你同时使用’.arm’和’.neon’后缀,则’.neon’后缀必须在’.arm’之后出现如foo.c.arm.neon可以工作,但foo.c.neon.arm 不行)。
LOCAL_DISABLE_NO_EXECUTE
......
LOCAL_DISABLE_RELRO
......
LOCAL_EXPORT_CFLAGS
可以定义这个变量来记录一组C/C++编译器标志,这些标志将被添加到任何使用LOCAL_STATIC_LIBRARIES或LOCAL_SHARED_LIBRARIES来引用该模块的其他模块的LOCAL_CFLAGS定义中。
如,考虑以下模块’foo’的定义:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_CFLAGS := -DFOO=1
include $(BUILD_STATIC_LIBRARY)
另一个名为’bar’的模块依赖于它:
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_CFLAGS := -DBAR=2
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
这时,标志'-DFOO=1 -DBAR=2'在构建bar.c时会被传递给编译器。
将标志导出到你模块的LOCAL_CFLAGS是刻意而为的,这样你可以很容易地覆盖它们。同时它们具有传递性:如果’zoo’依赖’bar’,’bar’依赖’foo’,此时’zoo’也会得到’foo’导出的标志。
最后,那些被导出的属性在模块自身的构建过程中不会被使用。在上面的例子中,在构建foo/foo.c时,-DFOO=1并不会传递给编译器。
LOCAL_EXPORT_CPPFLAGS
与LOCAL_EXPORT_CFLAGS一致,但只对C++标记生效。
LOCAL_EXPORT_C_INCLUDES
与LOCAL_EXPORT_CFLAGS一致,但只对C包含路径生效。如果’bar.c’想包含模块’foo’提供的头文件,就可以使用该变量。
LOCAL_EXPORT_LDLIBS
与LOCAL_EXPORT_CFLAGS一致,但只对链接标志生效。要注意,由于Unix链接器的工作方式,输入的链接器标志将会直接添加到你模块的LOCAL_LDLIBS中。
当模块’foo’是静态库,并且它有一部分代码依赖于一个系统库时这将会非常有用。LOCAL_EXPORT_LDLIBS可以被用来导出这个依赖关系。如:
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_STATIC_LIBRARIES := foo
include $(BUILD_SHARED_LIBRARY)
因此,libbar.so在构建时会在链接器命令的末尾附带一个-llog标志,来指明它依赖于系统logging库,因为它依赖于’foo’。
LOCAL_SHORT_COMMANDS
当你的模块有非常多的源文件或依赖大量的静态库或共享库时,可以将此变量设置为‘true’。这将会强制构建系统使用一个中间文件列表,库归档程序或静态链接器可以通过@$(listfile)的语法去使用它。这对Windows系统来说是有用的,它的命令最大只能接收8191个字符,这对复杂项目来说太小了。
这也会影响个别源文件的编译,因为几乎所有的编译器标志也存放在列表文件中。
除‘true’之外的其他任何值都会导致处理恢复成默认情况。你也可以在通过Application.mk中定义APP_SHORT_COMMANDS,让你工程中的所有模块都强制使用此行为。
NDK_TOOLCHAIN_VERSION
为了选择GCC编译器的版本,可以定义将此变量定义成4.4.3或4.6。默认值是4.6。
Android Build Cookbook提供了一些代码片段,可以帮助您快速实现一些常见的构建任务。
构建一个简单的Apk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
#Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
#Tell it to build an APK
include $(BUILD_PACKAGE)
构建一个依赖于精通.jar文件的Apk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#List of static libraries to include in the package
LOCAL_STATIC_JAVA_LIBRARIES := static-library
#Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
#Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
#Tell it to build an APK
include $(BUILD_PACKAGE)
构建一个应该使用platform 秘钥签名的Apk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#Build all java files in the java subdirectory
LOCAL_SRC_FILES := $(call all-subdir-java-files)
#Name of the APK to build
LOCAL_PACKAGE_NAME := LocalPackage
LOCAL_CERTIFICATE := platform
#Tell it to build an APK
include $(BUILD_PACKAGE)
构建一个使用指定的厂家秘钥签名的Apk
LOCAL_PATH := $(call my-dir)
include$(CLEAR_VARS)
# Build all javafiles in the java subdirectory
LOCAL_SRC_FILES:= $(call all-subdir-java-files)
# Name of the APKto build
LOCAL_PACKAGE_NAME := LocalPackage
LOCAL_CERTIFICATE:= vendor/example/certs/app
# Tell it tobuild an APK
include$(BUILD_PACKAGE)
添加一个预编译Apk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#Module name should match apk name to be installed.
LOCAL_MODULE := LocalModuleName
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
include $(BUILD_PREBUILT)
添加一个静态Java库
LOCAL_PATH := $(call my-dir)
include$(CLEAR_VARS)
# Build all javafiles in the java subdirectory
LOCAL_SRC_FILES:= $(call all-subdir-java-files)
# Any librariesthat this library depends on
LOCAL_JAVA_LIBRARIES := android.test.runner
# The name of thejar file to create
LOCAL_MODULE :=sample
# Build a staticjar file.
include$(BUILD_STATIC_JAVA_LIBRARY)
下面是一些按字母顺序排列、你会经常在Android.mk文件看到的变量。首先,我们要注意名字的含义:
include $(CLEAR_VARS)
行会清理这些变量,所以在包含该文件之后,你就能认为它们是空值了。在绝大多数模块中使用最多的就是LOCAL_变量下表未包含上面已经介绍过的变量及描述。
变量 | 描述 |
---|---|
LOCAL_ASSET_FILES | 指定编译APK时(include $(BUILD_PACKAGE) )要使用的资源文件列表。一般这样使用:LOCAL_ASSET_FILES += $(call find-subdir-assets) |
LOCAL_C_INCLUDES | 用于C/C++编译器寻找头文件的目录。这些目录默认是基于代码根目录的。如果你自己要使用的头文件包含子目录,可以使用LOCAL_PATH。例如:LOCAL_C_INCLUDES += extlibs/zlib-1.2.3
|
LOCAL_CC/LOCAL_CXX | 如果你想为这个模块使用别的C/C++编译器器,将该变量设置为新编译器的路径。如果不设置,则会使用默认编译器。LOCAL_CC对应C,LOCAL_CXX对应C++ |
LOCAL_COPY_HEADERS/LOCAL_COPY_HEADERS_TO | 在使用Android编译的库时,需要include这个库的头文件 Android编译时会包含out/target/product/generic/obj/include/ 下的头文件,LOCAL_COPY_HEADERS_TO和LOCAL_COPY_HEADERS的作用就是把需要暴露给外部的头文件copy到这个路径下 其中 LOCAL_COPY_HEADERS_TO 指定out/target/product/generic/obj/include/ 下的一个目录 LOCAL_COPY_HEADERS 指定要 copy 的头文件 |
LOCAL_FORCE_STATIC_EXECUTABLE | 如果编译时候需要链接的库有共享和静态两者共存的情况。设定此变量值为true将会优先链接静态库。通常这种情况只会在编译root/sbin目录下的应用才会用到,因为他们执行的时间比较早,文件系统的其他部分还没有加载。 |
LOCAL_JAVA_LIBRARIES | 在链接Java应用或库时,它指定了那些需要被包含的java类的class文件。现在,它只会是core或framework中的一个。大多数情况下,它会是这样:LOCAL_JAVA_LIBRARIES := core framework 在使用 include $(BUILD_PACKAGE) 构建APP时,没有必要,同时也不允许设置该变量,相应的库会自动被包含。 |
LOCAL_LDFLAGS | 通过设置该变量,可以向链接器传递一些标志。要注意,对ld来说,参数的顺序是非常重要的。 |
LOCAL_MODULE_PATH | 指示编译系统将某块放置到一个特定的路径,而不是根据它的类型指向的默认路径。如果你的模块是可执行文件或是共享库,当你重写了该变量,此时也要设置LOCAL_UNSTRIPPED_PATH;这样,未剥离的二进制文件才会被安装到某个路径。否则,会发生错误。 |
LOCAL_MODULE_TAGS | 可以给该变量设置多个值,以空格分开。这个变量控制了哪个版本下会编译该文件。如:
|
LOCAL_PACKAGE_NAME | 指定APP名称 |
LOCAL_POST_PROCESS_COMMAND | 在编译host可执行文件时,可以指定一个命令在该模块链接结束后执行。 |
LOCAL_PREBUILT_EXECUTABLES | 在包含$(BUILD_PREBUILT) 或$(BUILD_HOST_PREBUILT)时,指定需要复制的可执行文件 |
LOCAL_PREBUILT_LIBS | 在包含$(BUILD_PREBUILT) o或$(BUILD_HOST_PREBUILT)时,指定需要拷贝的库文件 |
LOCAL_REQUIRED_MODULES | 以空格分割,可以向该变量设置多个需要的模块名称,如:libblah或Email。如果此模块被安装,那么该变量所指定的所有模块也会被安装 |
LOCAL_SRC_FILES | 编译器通过该变量知晓它需要编译哪些源文件(.c/.cpp/.y/.h/.java)。对于lex和yacc文件,编译系统知道如何正确地自动执行中间的.h和.c / .cpp文件。加入一个文件在包含此Android.mk目录的一个子目录中,需要在该文件前指定子目录:LOCAL_SRC_FILES := \ |
LOCAL_UNSTRIPPED_PATH | 指定模块的unstripped(未被符号剥离)版本在out目录下的保存路径。 如果你为一个可执行文件或共享库指定了LOCAL_MODULE_PATH,却没有指定LOCAL_UNSTRIPPED_PATH,将会发生错误。 |
LOCAL_WHOLE_STATIC_LIBRARIES | 指定需要包含进模块中的静态库文件,此时链接器不会移除从这些链接库中移除dead code(调用者模块永远都不会用到的代码段和变量)。 |
LOCAL_YACCFLAGS | 指定YACC使用的标志。(Lex(Lexical Analyzar 词法分析生成器),Yacc(Yet Another Compiler Compiler 编译器代码生成器)是Unix下十分重要的词法分析,语法分析的工具。经常用于语言分 析,公式编译等广泛领域。) |