原帖地址:http://blog.csdn.net/ygc87/article/details/6707814


下面是我个人对android-ndk-r4版本中Android.mk文件做的翻译,由于自己英语水平和专业知识的限制,有些地方可能翻译的不是很准确,敬请指正,本文仅希望对做android NDK开发的同仁们能提供一点点的帮助而已。

Android.mk文件是用来描述你想要编译进系统的资源的。

这个文件的语法允许你把你的资源打包进“modules”。Module应该是下面module中的一种:

- a static library

- a shared library

只有shared library会被打包到你的应用程序中,尽管static library也能用来生产shared library。

你可以在一个Android.mk中定义多个module,你也可以在几个module中使用相同的资源文件。

编译系统会为你处理一些细节。例如,你不需要在你的Android.mk文件中列出你的头文件或是你的文件之间明确的依赖关系。NDK编译系统会自动帮你处理。

这同时意味着,当升级到新版本的NDK时,你不需要动你的Android.mk文件就可以使用心得toolchain/platform支持。

注意,用在Android.mk文件中的语法和整个的android平台的开源资源语法是不同的。编译系统实现了对他们不同的使用,这是故意这样设计的,用来允许应用开发人员更容易地重用外部库资源代码。

一个简单的例子:

在语法详细说明之前,让我们先来看一个简单的“hello-jni”例子,文件在$NDK/samples/hello-jni下:

在这我们可以看到:

-src目录下包含这个简单的android工程的一个java源文件

-jni目录下包含了这个例子的本地源文件

这个源文件实现了一个简单的共享库,这个共享库实现了一个想vm应用程序返回一个字符串的本地方法。

-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)

编译系统提供的一个指向特殊的GNU Makefile文件的CLEAR_VARS变量将为你清理很多LOCAL_PATH中的LOCAL_XXX变量(例如: LOCAL_MODULE, LOCAL_SRC_FILES, LOCAL_STATIC_LIBRARIES等等)。这是有必要的,因为所有的编译控制文件都会在一个单独的GNU Make可执行上下文中被解析,在这里所有的变量都是全局的。

LOCAL_MODULE := hello-jni

用来标识分布在Android.mk文件中的每一个module的LOCAL_MODULE变量必须定义。名字必须是唯一的而且不能有空格。

注意,编译系统会给相应的生成文件自动地添加适当的前缀和后缀。换句话说,一个命名为“foo”的共享库module将生成名为“libfoo.so”的文件。

重点注意:

如果你的module命名为“libfoo”,编译系统不会为你添加另外一个“lib”前缀,还是会生成一个“libfoo.so”的文件而已。这个为了支持你需要使用的android平台资源的Android.mk文件。

LOCAL_SRC_FILES := hello-jni.c

LOCAL_SRC_FILES变量必须包含一个将要被编译和汇编进module的一个C/C++资源文件列表。注意你不需要列出头文件和包含文件,因为编译系统会自动帮你计算依赖关系;仅仅需要列出直接传递给编译器的资源文件就可以了。

注意:默认的C++资源文件的扩展名是“.cpp”。然而可以通过定义LOCAL_DEFAULT_CPP_EXTENSION变量来指定一个不同的扩展名。不要忘记最开始的dot(例如:.cxx是可以的,但是cxx是不行的)。

include $(BUILD_SHARED_LIBRARY)

BUILD_SHARED_LIBRARY是编译系统提供的一个指向GNU Makefile脚本的变量,它负责收集从最近的include $(CLEAR_VARS)' 变量开始的所有内定义的 LOCAL_XXX变量的信息,然后决定哪些需要编译以及怎样编译。BUILD_STATIC_LIBRARY变量可以生成一个static library。

在samples目录下有几个复杂的例子,在他们的Android.mk文件中你可以看到一些注释。

Reference:

下面是你可以在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提供的变量:

在你的Android.mk文件解析之前,编译系统定义了这些GNU Make变量。注意,在某种情况下NDK可能会多次解析你的Android.mk文件,每一次解析某些变量的定义可能不同。

CLEAR_VARS

指向一个几乎所有在"Module-description"部分列出的LOCAL_XXX变量都没有定义的编译脚本(我的理解就是在编译前清空所有变量,然后在这个变量的下面再重新定义)。在开始一个新的module之前你必须包含这个脚本,例如:

include $(CLEAR_VARS)

BUILD_SHARED_LIBRARY

指向一个收集所有你提供的关于module的LOCAL_XXX变量的信息的编译脚本,然后决定如何根据你列出的资源编译一个目标shared library。注意,你在包含这个变量之前必须至少OCAL_MODULE 和LOCAL_SRC_FILES 变量。可以这样使用:

include $(BUILD_SHARED_LIBRARY)

注意它将生成一个以lib$(LOCAL_MODULE).so命名的文件。

BUILD_STATIC_LIBRARY

BUILD_STATIC_LIBRARY变量的不同之处在于它是用来生成一个目标static ibrary 。static ibrary 不会被打包进你的工程包,但是可以用来生成shared library(看下面的LOCAL_STATIC_LIBRARIES 和LOCAL_STATIC_WHOLE_LIBRARIES说明)。可以这样使用:

include $(BUILD_STATIC_LIBRARY)

注意,它将生成一个以lib$(LOCAL_MODULE).a命名的文件。

TARGET_ARCH

指明一个full Android open-source build明确说明的目标CPU架构。如果是“arm”用来所有的兼容ARM的编译,不依赖与CPU架构版本。

TARGET_PLATFORM

当Android.mk文件解析时,指明一个android目标平台。例如"android-3”对应"android1.5"系统镜像。完整的平台名字和android系统镜像的对应列表可以阅读docs/目录下STABLE-APIS.TXT文档。

TARGET_ARCH_ABI

当Android.mk文件解析时,指明一个目标CPU+ABI。有两个值可供使用:

armeabi
对应Armv5TE

armeabi-v7a

注意:Android NDK 1.6_r1之上的版本,这个变量被定义为'arm'。然而,这个变量的重定义能够被Android platform内部更好的使用。

对于更多的ABI架构和对应的兼容性问题的细节,可以阅读docs目录下的CPU-ARCH-ABIS.TXT文档。

其他的ABI架构将会在以后的NDK版本中引入,并且有不同的名字。注意,所有基于ARM的ABIs都会被'TARGET_ARCH' 定义为 'arm',但是可能有不同的'TARGET_ARCH_ABI'。

TARGET_ABI

目标平台和abi的连结,它被定义为$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI),当你用真机测试一个指定的目标平台镜像的时候会有用处。

默认情况下,它将是'android-3-armeabi'

(Android NDK 1.6_r1以上的版本,'android-3-arm'是默认的)

NDK提供的宏函数

下面是GNU Make宏函数,通过使用'$(call <function>)'来获得他的值。它们返回文本信息。

my-dir

返回相对于上层的NDK编译系统的当前Android.mk文件目录的路径。这对于以下面这种方式在你的Android.mk文件的开始定义LOCAL_PATH变量很有用:

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文件的路径。

Module描述变量

下面的变量是用来向系统描述你的module的。你应该在一个'include $(CLEAR_VARS)'和'一个include $(BUILD_XXXXX)'变量之间定义它们中的某些变量。前面的部分已经介绍过了,$(CLEAR_VARS)变量是取消/清除所有这些变量的定义,除非在他们的描述说明确地注明。

LOCAL_PATH

这个变量用来给出当前文件的路径。你必须在你的Android.mk文件的开始定义它,比如下面这样定义是可以的:

LOCAL_PATH := $(call my-dir)

这个变量不会被$(CLEAR_VARS)清除掉,所以在每一个Android.mk文件中仅需要定义一次(在你的一个文件中定义了几个module的情况下)。

LOCAL_MODULE

你的module的名字。它必须在所有的module名字中是唯一的,而且不能有空格。你必须在任何一个$(BUILD_XXXX)脚本之前定义它。

module名字决定了生成文件的名字,例如:一个名字为lib<foo>.so的shared library的module名字为<foo>。可是,你应该在你的NDK编译文件中(无论是Android.mk还是 Application.mk)进引用其它module的通用的名字(例如<foo>)。

LOCAL_SRC_FILES

这是一个将用于你的module编译的资源文件列表。只用在列表中的文件才会传递给编译器,因为编译系统自动帮你计算依赖关系。

注意,所有的资源文件名字都是相对于LOCAL_PATH的,你能够使用路径分隔符,例如:

LOCAL_SRC_FILES := foo.c \
toto/bar.c

注意:只有使用Unix风格的正斜线(/)在编译文件中才可以,windows风格的反斜线(\)不能被正确处理。

LOCAL_CPP_EXTENSION

这是一个可选择的变量,它能用来定义c++源文件的文件后缀名。默认的是'.cpp',但是你可以改变它。例如:

LOCAL_CPP_EXTENSION := .cxx

LOCAL_C_INCLUDES

一个可选的编译所有源文件(C,C++,汇编)时会添加到include搜索路径相对于NDK *root*文件夹的路径的列表。例如:

LOCAL_C_INCLUDES := sources/foo

或者

LOCAL_C_INCLUDES := $(LOCAL_PATH)/../foo

他们会在LOCAL_CFLAGS / LOCAL_CPPFLAGS中的任何inclusion flag之前被替换。

LOCAL_CFLAGS

当编译 C 和 C++源文件时传递的一组可选的编译器标识。

它可以用来指定额外的宏定义或编译选项。

重要信息:不要在你的Android.mk文件中尝试去改变优化/调试等级,这个可以通过在你的Android.mk文件中指明适当的信息来让系统自动处理,将会使NDK生成在调试中可以使用的有用的数据文件。

注意:在android-ndk-1.5_r1中,对应标记仅能用在c源文件上,不能用在c++源文件上。这能够正确匹配所有的android编译系统行为。(你现在可以使用LOCAL_CPPFLAGS来仅为c++源文件设置标识)。

LOCAL_CXXFLAGS

LOCAL_CPPFLAGS的一个别名。注意,这种标识的使用是过时的,因为在以后的NDK版本中它可能被取消。

LOCAL_CPPFLAGS

当仅编译 C++源文件时传递的一组可选的编译器标识。他们将在LOCAL_CFLAGS之后显示在命令行上。

注意:在android-ndk-1.5_r1中,对应标记在c源文件上和在c++源文件上都能使用。这能够正确匹配所有的android编译系统行为。(你现在可以使用LOCAL_CFLAGS来为c++源文件和c源文件设置标识)。

LOCAL_STATIC_LIBRARIES

将要被链接进这个module的static libraries modules的列表(用BUILD_STATIC_LIBRARY编译过的)。这个仅在shared library modules中能被检测到。

LOCAL_SHARED_LIBRARIES

依赖于运行时的shared libraries *modules*的列表。这在链接时是必要的,为了把对应的信息嵌入到生成的文件中。

注意:他不会把列出的module添加到编译表中,例如:你仍然需要在你的Application.mk文件中把他们添加到你的应用程序需要的module中。

LOCAL_LDLIBS

编译你的module时使用到的额外的链接器标识列表。它能够用一个带 "-l" 前缀的表达式传递一个指明的系统库的名字。例如:下面的定义将会通知编译器在加载的时候生成一个链接到/system/lib/libz.so的module:

LOCAL_LDLIBS := -lz

阅读docs目录下的STABLE-APIS.TXT文档,你将能了解到在这个NDK版本中你可以链接的系统库的列表。

LOCAL_ALLOW_UNDEFINED_SYMBOLS

默认情况下,当尝试编译一个shared library时任何一个没有定义的引用都将产生一个"undefined symbol"错误。这对在你的源代码中捕获bug很有帮助。
可是,如果由于某种原因你需要让这些检查失效,把这个变量设置为'true'。注意,对应的shared library在运行时加载可能出错。

LOCAL_ARM_MODE

默认情况下,ARM的二进制文件将生成每一条指令都是16位的'thumb'模式。你可以定义这个变量为'arm',如果你想强制生成的module目标文件为 'arm'(每条指令32位)模式的。例如:

LOCAL_ARM_MODE := arm

注意,你也可以通过在源文件名后面添加一个'.arm'来指示编译系统只把指定的文件编译'bar.c'。例如:

LOCAL_SRC_FILES := foo.c bar.c.arm

通知编译系统总是把'bar.c'编译成'.arm'模式,而依据LOCAL_ARM_MODE变量的值来编译 foo.c 文件。

注意:在你的Application.mk文件中设置APP_OPTIM为 'debug'也能强制生成ARM二进制文件。这是因为在thumb模式下toolchain debugger 中的bug不能得到较好的处理。

LOCAL_ARM_NEON

把这个变量设置为'true'能够允许你在你的C和C++源码中使用ARM Advanced SIMD(a.k.a. NEON)GCC,也能在汇编文件中使用NEON指令。

你仅仅应该在想要对应ARMv7指令序列的'armeabi-v7a' ABI时定义它。注意,不是所有基于ARMv7的CPU都支持NEON指令序列扩展,你应该开启运行时检查来确保你能安全地使用这些代码在运行期间。更多的关于这些的内容,可以阅读docs目录下的CPU-ARM-NEON.TXT 和CPU-FEATURES.TXT.文档。

二选一,你也可以在指定的文件后面加上'.neon'来指示表仪器把指定的文件编译成NEON支持的文件,例如:

LOCAL_SRC_FILES = foo.c.neon bar.c zoo.c.arm.neon

在这个例子中'foo.c'将被编译成thumb+neon模式,'bar.c'将被编译成'thumb'模式,'zoo.c' 将被编译成'arm+neon'模式。

注意,如果 '.neon' 后缀和'.arm' 后缀都是用,那么 '.neon' 后缀和一定要添加到'.arm' 后缀之后。(例如: foo.c.arm.neon 可以,但是 foo.c.neon.arm 不可以)。

LOCAL_DISABLE_NO_EXECUTE

Android NDK r4添加的用来支持"NX bit"安全特性的。默认情况下是启用的,但是你也可以设置这个变量为 'true'来启用它,如果你真的需要这么做的话。

注意:这个特性不会修改ABI,它仅仅是使内核能够指向ARMv6+ CPU设备。在这种特性下生成的机器码将不需要做修改就能运行在更早的CPU架构上。

更多相关文章

  1. android实现横竖屏不间断播放文件
  2. android 调试利器之IDA
  3. Android(安卓)Kotlin使用指南
  4. [置顶] Android原生(Native)C(JNI/NDK)开发之一:环境搭建篇
  5. Android内置应用到系统的方法总结
  6. Android6.0 ueventd
  7. android应用安全——代码安全(android代码混淆)
  8. Qt for Android(安卓)编译纯C工程
  9. NPM 和webpack 的基础使用

随机推荐

  1. android VoiceRecognition 语音识别并打
  2. Android中点击事件之FocusChangedListene
  3. Android(安卓)终端命令安装 apk 应用程序
  4. android wifi 设置 控制开关
  5. Rk3399 android7.1 camera 分析
  6. Android获取文件的MD5值
  7. Android(安卓)文件读写工具类
  8. [置顶] Android(安卓)Studio 配置
  9. Android(安卓)linux adc驱动(s5pv210)
  10. android popupwindow 中listview 无法点