Android.mk文件说明
来源:互联网 发布:com域名攻击 编辑:程序博客网 时间:2024/06/09 20:51
以下内容根据官方文档翻译,转载请注明出处。
概述
Android.mk
文件位于项目目录下的jni/
子文件夹中。它向编译系统描述你的资源文件以及共享库文件。它实际上是一个小型的GNU makefile片段。编译系统在编译过程中会对它进行一次或多次解析。Android.mk
文件主要是用于定义在Application.mk
、编译系统以及环境变量中所没有定义的项目级别的设定。它还能复写指定模块的项目级别的设定。
Android.mk
的语法允许你将源文件组织为模块的形式。一个模块可以是一个静态库、一个共享库或者是一个独立的可执行文件。你可以在每个Android.mk
中定义一个或多个模块,也可以在多个模块用使用同一个源文件。编译系统只会把共享库放到你的程序包中。另外,静态库可以生成共享库。
除了打包库文件之外,编译系统还会为你处理许多细节问题。泪如,你不需要在你的Android.mk
中列出头文件或列出生成文件的显式的依赖,NDK编译系统会自动为你计算它们之间的依赖关系。这样,当未来的NDK版本中出现新的工具链/平台支持时,你就不需要再改动你的Android.mk
文件了。
尽管使用的编译系统不同,这里的语法与Android Open Source项目中所发布的Android.mk
文件的语法非常相似。这样做的目的是为了让应用开发人员更容易的服用他们的外部库文件的源代码。
基础知识
在详细了解语法知识之前,最好先对Android.mk
文件中包含什么信息有一个基础的了解。这一节使用Hello-JNI
示例中的Android.mk
文件解释一下每一行都起到了什么作用。
一个Android.mk
文件必须以定义LOCAL_PATH
变量起始:
LOCAL_PATH := $(call my-dir)
这个变量指示了源文件在开发树中的位置。变量中的宏函数my-dir
由编译系统提供,它返回当前目录的路径(Android.mk
所在目录)。
下一行声明了CLEAR_VARS
变量,它的值由编译系统提供。
include $(CLEAR_VARS)
CLEAR_VARS
变量指向一个特定的GNU Makefile文件,它会为你清除许多LOCAL_XXX
变量,例如LOCAL_MODULE
,LOCALE_SRC_FILES
,LOCAL_STATIC_LIBRARIES
。记住,它并不清除LOCAL_PATH
变量。GNU编译系统在同一个环境下解析所有的编译控制文件,在这里,所有的变量都是全局的,因此,你必须在描述每一个模块之前重新声明CLEAR_VARS
。
下一行的LOCAL_MODULE
变量存储的是你想要构建的模块的名字。应用中的每一个模块都应声明一次该变量。
LOCAL_MODULE := hello-jni
每个模块的名字必须唯一,并且不含有空格。编译系统在生成最终的共享库文件时,会自动为它添加相应的前缀和后缀。例如,上面的例子中,最后生成的库文件名为libhello-jni.so
。
注: 如果你的名字中已经以
lib
起始。编译系统不会再为它添加lib
前缀。因此若模块名为libfoo
,最后生成的库文件为libfoo.so
。
再下一行枚举了所有的源文件,通过空格来分隔多个文件:
LOCAL_SRC_FILES := hello-jni.c
LOCAL_SRC_FILES变量必须包含编译进模块中的C或C++文件列表。
最后一行帮助编译系统将所有一切整合在一起
include $(BUILD_SHARED_LIBRARY)
BUILD_SHARED_LIBRARY
指向一个GNU Makfile脚本,它会收集你在LOCAL_XXX
变量中定义的所有信息。这个脚本决定编译什么以及如何编译。
变量与宏定义
编译系统在Android.mk
文件中提供了许多可用的变量。这些变量都有预设的值。
除了这些变量之外,你还能定义自己的变量。当你这么做的时候,需要记住以下名字是被NDK编译系统自己保留的:
* 以LOCAL_
开头的名字,如LOCAL_MODULE
。
* 以PRIVATE_
,NDK_
,APP
开头的名字,这些名字在编译系统内部使用
* 小写的名字,如my-dir
,同样,这些名字在编译系统内部使用。
因此,如果你要在Android.mk
中定义自己的变量,最好使用MY_
开头。
NDK 预定义变量
这一节讨论编译系统在解析你的Android.mk
之前预定义的一些GNU Make变量。在特定环境下,NDK可能会多次解析你的Android.mk
文件,每次使用一套不同的变量定义。
CLEAR_VALS
这个变量指向一个脚本,它会解除在”开发者定义变量”中列出的几乎所有LOCAL_XXX
变量。每次描述一个新的模块时,使用这个变量来包含这个脚本。
include $(CLEAR_VARS)
BUILD_SHARED_LIBRARY
这个变量指向一个编译脚本,它会收集所有你定义的关于这个模块的LOCAL_XXX
变量信息,并决定如何根据你所列出的源文件来编译一个共享库。记住,在使用这个脚本之前,你必须至少定义了LOCAL_MODULE
以及LOCAL_SRC_FILES
变量。
使用语法为:
include $(BUILD_SHARED_LIBRARY
使用共享库变量会让编译系统生成一个.so
文件。
BUILD_STATIC_LIBRARY
BUILD_STATIC_LIBRARY
用于生成静态库。编译系统不会将静态库拷贝到你的项目/包中。但是它可以用于生成共享库文件(参考LOCAL_STATIC_LIBRARIES
以及`LOCAL_WHOLE_STATIC_LIBRARIES)。
include $(BUILD_STATIC_LIBRARY)
使用静态库变量会让编译系统生成一个.a
库文件。
PREBUILT_SHARED_LIBRARY
指向一个用于指定已编译好的共享库文件的编译脚本。与BUILD_SHARED_LIBRARY
以及BUILD_STATIC_LIBRARY
不同,这里的LOCAL_SRC_FILES
不能是源文件,而应该是指向一个单独的已编译好的共享库文件,如foo/libfoo.so
。使用语法如下:
include $(PREBUILT_SHARED_LIBRARY)
你也能通过使用LOCAL_PREBUILTS
变量指向另一个模块预先编译好的库文件。关于使用预编译库的跟多信息,可参考使用预编译库
PREBUILT_STATIC_LIBRARY
与PREBUILT_SHARED_LIBRARY
相同,但是应用于静态库文件。
TARGET_ARCH
由Android Open Source Project给出的目标CPU架构的名字。对于任意ARM兼容的构建,使用arm
,独立于ABI变量所指定的CPU架构版本(参考下面的TARGET_ARCH_ABI
)。
TARGET_PLATFORM
编译系统目标Android API等级。例如,Android 5.1系统对应的是Android API 22:android-22
。关于完整的对应信息,查看Android NDK Native APIs。使用示例:
TARGET_PLATFORM := android-22
TARGET_ARCH_ABI
这个变量存储目标CPU与架构的信息。你可以指定一个或多个下表中的值,通过空格分隔。
表1. ABI设定与不同的CPU架构
以下示例表示设定目标为 ARMv8 AArch64:
TARGET_ARCH_ABI := arm64-v8a
注: 直到Android NDK 1.6_r1为止,这个变量都被定义为
arm
。
关于架构ABI以及相关的兼容问题,参考ABI Management。
TARGET_ABI
目标Android API等级与ABI的串联信息。在你希望在一个真实设备上进行测试时非常有用。例如,可以指定一个运行于Android API level 22下的64位ARM设备。
TARGET_ABI := android-22-arm64-v8a
注:直到Android NDK 1.6_r1为止,它的默认值都是
android-3-arm
。
模块描述变量
本节中描述的变量用于向编译系统描述你的模块。每一个模块描述都应遵循以下流程:
1. 使用CLEAR_VARS
初始化变量
2. 为模块相关变量赋值
3. 使用BUILD_XXX
变量编译模块
LOCAL_PATH
定义当前文件路径。你必须在Android.mk
开头定义这个变量。
LOCAL_PATH := $(call my-dir)
CLEAR_VARS
不会清除这个变量的值。因此,若你在Android.mk
中描述了多个模块,只需要定义一次即可。
LOCAL_MODULE
模块名,必须唯一并且不含空格。你必须在包含任意脚本前定义该变量(除了CLEAR_VARS
)。你不需要添加lib
前缀或.a
,.so
后缀。
LOCAL_MODULE := "foo"
如果你需要指定生成文件的名字,而不是系统自动生成。你可以使用LOCAL_MODULE_FILENAME
变量。
LOCAL_MODULE_FILENAME
可选变量,用于替换系统自动生成的文件名,如下例,会生出libnewfoo
文件而不是libfoo
文件。
LOCAL_MODULE := fooLOCAL_MODULE_FILENAME := libnewfoo
对于共享库文件,示例所生成的文件名为libnewfoo.so
注: 你不能更改文件路径或拓展名
LOCAL_SRC_FILES
指定生成模块所需的文件列表。只需列出编译系统实际进行编译的文件,因为编译系统会自动计算相关的依赖。
既可以使用相对路径(相对于LOCAL_PATH
),也可以使用绝对路径。
建议使用相对路径以便于移植。
注: 系统无法识别Windows形式的斜杠(\),只能识别Unix格式的斜杠(/)
LOCAL_CPP_EXTENSION
可选变量,用于指定非.cpp
后缀作为C++源文件的后缀。例如,你可以使用.cxx
作为文件后缀(必须包含点)。
LOCAL_CPP_EXTENSION := .cxx
从NDK r7开始,你可以使用多种类型的格式,如
LOCAL_CPP_EXTENSION := .cxx .cpp .cc
LOCAL_CPP_FEATURES
可选变量,指定代码所依赖的C++特性。它会在编译过程中启用正确的编译与链接选项。对于预编译二进制文件,这个变量同样声明了二进制文件所依赖的特性,以便于保证最终链接顺利。建议使用该变量而不是直接在LOCAL_CPPFLAGS
中启用-frtti
与-fexceptions
。
使用LOCAL_CPP_FEATURES
允许编译系统为每一个模块提供合适的编译选项,而LOCAL_CPPFLAGS
会导致编译器为所有的模块使用同一套编译选项,而不考虑实际所需。
例如,指定使用RTTI(运行时类型信息)
LOCAL_CPP_FEATURES := rtti
指定使用C++异常
LOCAL_CPP_FEATURES := exceptions
你也可以因此指定多个值,如
LOCAL_CPP_FEATURES := rtti features
指定顺序没有影响
LOCAL_C_INCLUDES
可选变量,指定头文件所在目录,相对于NDKroot
的路径,如:
LOCAL_C_INCLUDES := sources/foo
或者
LOCAL_C_INCLUDES := $(LOCAL_PATH)//foo
你必须在使用LOCAL_CFLAGS
或LOCAL_CPPFLAGS
进行任何相应的包含之前定义该变量。 ndk-gdb
调试同样会自动调用LOCAL_C_INCLUDES
信息。
LOCAL_CFLAGS
可选变量,设置在编译时使用的编译标志。例如添加额外的宏定义,或编译选项。
尽量不要再Android.mk
中更改优化/调试级别。编译系统会根据Application.mk
中的信息自动处理相关设定。
注:在android-ndk-1.5_r1中,这个标志只会用于C源文件,而不会用于C++。
你可以通过它指定额外的头文件路径:
LOCAL_CFLAGS += -I<path>,
但是最好还是通过LOCAL_C_INCLUDES
来进行,以便于调试。
LOCAL_CPPFLAGS
可选,设置在编译时仅用于C++源文件的编译选项。这些编译选项在编译时会显示在LOCAL_CFLAGS
之后。
注: 在android-ndk-1.5_r1中,这个标志同时应用于C与C++文件。
LOCAL_STATIC_LIBRARIES
指定当前模块所依赖的静态库。
若当前模块为共享库或可执行文件,这个变量所指定的库会被强制链接到生成的二进制文件中。
若当前模块为静态库,则该变量只是指示当前库所依赖的库列表。
LOCAL_SHARED_LIBRARIES
当前模块运行所需的共享库。该信息在链接时所使用,并被嵌入到生成的二进制文件中。
LOCAL_WHOLE_STATIC_LIBRARIES
这个变量为LOCAL_SHARED_LIBRARIES
的变种。主要用于解决循环依赖问题。
LOCAL_LDLIBS
这个变量包含构建共享库或可执行文件所需的额外链接选项。它能让你用-l
前缀指定想要链接的系统库。例如,你可以通过如下示例告诉链接器生成一个在启动时链接到/system/lib/libz.so
库的模块:
LOCAL_LDLIBS := -lz
关于可用的系统库列表,参考Android NDK Native APIs。
注:若你定义的模块是一个静态库,编译系统会忽视它,并输出一个警告信息。
LOCAL_LDFLAGS
编译时使用的其它链接标志。如在 ARM/X86 GCC 4.6+ 上使用ld.bfd
链接器而不是默认的ld.gold
:
LOCAL_LDFLAGS += -fuse-ld=bfd
注:若你定义的 模块 是一个静态库,编译系统会忽视它,并输出一个警告信息。
LOCAL_ALLOW_UNDEFINED_SYMBOLS
是否允许未定义的符号变量存在。
注:若你定义的 模块 是一个静态库,编译系统会忽视它,并输出一个警告信息。
LOCAL_ARM_MODE
编译系统默认生成thumb模式的二进制文件,即指令为16位宽度,并链接thumb/
目录下的STL库。将这个变量设定为arm
会强制编译系统生成32位的arm
模式文件。
LOCAL_ARM_MODE := arm
你也可以针对单独的源文件提供该编译选项,如下例中的bar.c
会一直以ARM模式编译,而foo.c
的编译模式则取决于LOCAL_ARM_MODE
。
LOCAL_SRC_FILES := foo.c bar.c.arm
注:在
Application.mk
中将APP_OPTIM
设置为debug
同样可以启用ARM模式,因为调试器无法正确处理Thumb代码。
LOCAL_ARM_NEON
这个参数只有在目标为armeabi-v7a
时才有影响。它允许你在C和C++源码中使用ARM Advanced SIMD(NEON) GCC函数,以及在汇编文件中使用NEON指令。
记住这点,并不是所有的ARMv7架构的CPU都支持NEON指令集拓展。因此,你必须在运行时检测是否能够安全的使用这些代码。更多信息,请参考NEON Support与The cpufeatures Library。
同样,你可以针对指定源文件启用NEON支持:
LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon
同时指令两个后缀时,.arm
必须在.neon
之前。
LOCAL_DISABLE_NO_EXECUTE
未了解
LOCAL_DISABLE_RELRO
未了解
LOCAL_DISABLE_FORMAT_STRING_CHECKS
编译系统编译代码时,默认提供字符串格式化保护。当使用printf
之类的函数格式化一个非常量的字符串时会引发一个编译器错误。
保护默认打开,可通过设置该值为true
进行关闭。没有无法避免的理由不建议这么做。
LOCAL_EXPORT_CFLAGS
该变量记录的编译选项会被添加到通过LOCAL_STATIC_LIBRARIES
或LOCAL_SHARED_LIBRARIES
使用该模块的其它模块的LOCAL_CFLAGS
中。
如下例:
include $(CLEAR_VARS)LOCAL_MODULE := fooLOCAL_SRC_FILES := foo/foo.cLOCAL_EXPORT_CFLAGS := -DFOO=1include $(BUILD_STATIC_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := barLOCAL_SRC_FILES := bar.cLOCAL_CFLAGS := -DBAR=2LOCAL_STATIC_LIBRARIES := fooinclude $(BUILD_SHARED_LIBRARY)
bar.c
编译时会同时启用-DFOO=1
以及-DBAR=2
。
另外,这种模块间的关系是可传递的。若zoo
依赖于bar
,则zoo
也会继承foo
中导出的标志位。
最后,导出的变量在编译本模块时是不是用的。因此,编译foo
时,-DFOO=1
并未被传递给编译器。
LOCAL_EXPORT_CPPFLAGS
与LOCAL_EXPORT_CFLAGS
相同,但仅用于C++标志。
LOCAL_EXPORT_C_INCLUDES
与LOCAL_EXPORT_CFLAGS
相同,用于头文件包含路径。
LOCAL_EXPORT_LDFLAGS
导出链接器设置
LOCAL_EXPORT_LDLIBS
导出需要链接的系统库,例如
include $(CLEAR_VARS)LOCAL_MODULE := fooLOCAL_SRC_FILES := foo/foo.cLOCAL_EXPORT_LDLIBS := -lloginclude $(BUILD_STATIC_LIBRARY)include $(CLEAR_VARS)LOCAL_MODULE := barLOCAL_SRC_FILES := bar.cLOCAL_STATIC_LIBRARIES := fooinclude $(BUILD_SHARED_LIBRARY)
在上例中,编译系统在构建libbar.so
时,会将-llog
放到链接命令的最后。因为·libbar.so·依赖于foo
,而foo
依赖于系统日志库。
LOCAL_SHORT_COMMANDS
主要用于Windows系统。Windows系统命令行最多只能接收8191个字符,当项目非常复杂时,编译命令往往会超出这个限制。将这个变量设为true
可以缩短编译命令。
可以在Application.mk
中定义APP_SHORT_COMMANDS
以在所有模块中启用该行为。
不建议默认开启该特性,因为它会导致编译速度变慢。
LOCAL_THIN_ARCHIVE
用于静态库,可减小库文件大小,未做详细了解
LOCAL_FILTER_ASM
未做了解
NDK提供的函数宏
本节介绍NDK提供的GNU Make函数宏。使用$(call <function>)
来执行它们,它们会返回文本形式的信息。
my-dir
返回最近一次包含的makefile文件的路径,一般是当前Android.mk
文件的路径。在Android.mk
文件开头定义LOCAL_PATH
时,my-dir
非常有用。
LOCAL_PATH := $(call my-dir)
基于GNU Make的工作方式,这个宏返回的实际上是编译系统在解析构建脚本时所引入的最后一个makfile文件的路径。因此,你不应该在包含另一个文件之后再调用my-dir
。
例如:
LOCAL_PATH := $(call my-dir)# ... declare one moduleinclude $(LOCAL_PATH)/foo/`Android.mk`LOCAL_PATH := $(call my-dir)# ... declare another module
这里的问题在于,当第二次调用my-dir
来定义LOCAL_PATH
时,实际上反悔的是$PATH/foo
而不是$PATH
,因为它才是最近所包含的文件。
你可以将额外文件的包含放在最后来避免这个问题,如:
LOCAL_PATH := $(call my-dir)# ... declare one moduleLOCAL_PATH := $(call my-dir)# ... declare another module# extra includes at the end of the Android.mk fileinclude $(LOCAL_PATH)/foo/Android.mk
如果这个方法不太方便,可以将my-dir
的值存入另一个变量,例如:
MY_LOCAL_PATH := $(call my-dir)LOCAL_PATH := $(MY_LOCAL_PATH)# ... declare one moduleinclude $(LOCAL_PATH)/foo/`Android.mk`LOCAL_PATH := $(MY_LOCAL_PATH)# ... declare another module
all-subdir-makefile
返回当前my-dir
目录下所有子目录中的Android.mk
路径。
你可以通过这个函数来向编译系统提供嵌套式的源代码目录结构。默认情况下,NDK只会在包含Android.mk
文件的目录下查找文件。
this-makefile
返回当前makefile的路径
parent-makefile
返回包含当前makefile的makefile的路径
grand-parent-makefile
返回更上一级的makefile的路径
import-module
通过模块的名字查找并包含对应的Android.mk
文件,举例:
$(call import-module,<name>)
在这个例子中,编译系统会在NDK_MODULE_PATH
环境变量所指向的目录中查找名为<name>
的模块,并自动包含其Android.mk
文件。
- Android.mk文件说明
- android make .mk文件说明
- Android.mk和Application.mk文件中部分变量说明
- Android编译系统分析,mk文件说明等
- Android.mk详细说明
- Android.mk简要说明
- Android.mk语法说明
- android.mk说明
- Android.mk 说明
- Android jni编译时 Android.mk文件 规范说明
- android jni编译时Android.mk文件的规范说明
- Android.mk文件语法规范与变量详细说明
- Android.mk和Application.mk文件语法规范说明及举例
- Android.mk和Application.mk文件语法规范说明及举例
- android.mk中LOCAL_MODULE_TAGS说明
- Android.mk官方说明 中文翻译
- android.mk的配置说明
- Android.mk 文件,多个mk文件
- Spring-与Struts简单框架的整合
- git学习总结(二)
- jsoncpp编译方法 和 vs2010中导入第三方库的方法
- aidl 不能生成对应 java文件
- 杭电ACM1527——取石子游戏~~威佐夫博奕
- Android.mk文件说明
- NGUI研究院之制作转圈的技能CD特效(八)
- jsp里的四大作用域
- Android手表商场项目总结
- getParameter和getAttribute的区别是什么?
- 《ArcGIS Runtime SDK for Android开发笔记》——(4)、基于Android Studio构建ArcGIS Android开发环境
- Android Studio 项目加载插件错误
- attribute与parameter区别
- PHP版本Thread Safe(线程安全)Thread Safe(线程安全)区别