1、前言

Android.mk用于向编译系统描述源文件和共享库,它实际上是编译系统解析一次或多次的微小GNU makefile片段。它的语法支持将源文件分组为模块,模块是静态库、共享库或独立的可执行文件。

2、简单示例

首先来看一个最简单的Android.mk的例子,如下所示:

# A simple Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := hello.c
LOCAL_MODULE := helloworld
include $(BUILD_EXECUTABLE)

对该Android.mk文件进行解析,如下:

LOCAL_PATH := $(call my-dir)

每个Android.mk文件必须以定义LOCAL_PATH为开始,它用于在开发项目文件中查找源文件,而宏my-dir则由编译系统提供,返回包含Android.mk的目录路径。

include $(CLEAR_VARS)

CLEAR_VARS变量由编译系统提供,并指向一个特定的GNU Makefile,由它负责清理很多LOCAL_XXX的值,例如:LOCAL_MODULE、LOCAL_SRC_FILES等,但是不清理LOCAL_PATH,这个清理动作是必须的,因为所有的编译控制文件由同一个GNU Make解析和执行,其变量是全局的,清理后才能避免相互影响。

LOCAL_SRC_FILES := hello.c

LOCAL_SRC_FILES变量必须包含将要打包成模块的C/C++源文件,不必列出头文件,编译系统会自动找出依赖的文件,缺省的C++源码的拓展名为.cpp,也可以通过LOCAL_CPP_EXTENSION进行修改。

LOCAL_MODULE := helloworld

LOCAL_MODULE模块必须定义,以表示Android.mk中的每一个模块,名字必须唯一并且不包含空格,Build System会自动添加适当的前缀和后缀。

include $(BUILD_EXECUTABLE)

BUILD_EXECUTABLE是编译系统提供的一个变量,指向一个特定的GNU Makefile脚本,表示要编译成一个可执行的文件,如果想编译成动态库则可以用BUILD_SHARED_LIBRARY,如果想编译成静态库则可以用BUILD_STATIC_LIBRARY。

3、保留的变量

在编写Android.mk文件时应该使用或者定义的变量,可以视具体情况定义其他的变量,但是NDK编译环境保留以下变量名:

(1)LOCAL_开头的变量名(例如:LOCAL_MODULE)

(2)PRIVATE、NDK_以及APP_开头的变量名(内部使用)

(3)小写命名(内部使用,如my-dir)

如果要在Android.mk文件中定义自己的变量,建议使用前缀MY_开头,例如:

MY_SOURCES := foo.c
ifneq ($(MY_CONFIG_BAR),)
MY_SOURCES += bar.c
LOCAL_SRC_FILES += $(MY_SOURCES)

4、NDK提供的变量

GNU Make在解析Android.mk文件之前由编译环境定义的一些变量,需要注意的是,在某些条件下,NDK可能会多次解析你的Android.mk文件,每一次都会为某些变量进行不同的定义。

(1)CLEAR_VARS

指向一个脚本,取消定义在模块变量下面几乎所有的LOCAL_XXX的定义,必须在一个新的模块下面包含这个脚本,如:

include $(CLEAR_VARS)

(2)BUILD_SHARED_LIBRARY

指向一个脚本,收集你提供的所有LOCAL_XXX变量的信息,决定如何根据你列出的源文件编译对应的共享库,注意,在包含这个脚本之前,你必须至少已经定义了LOCAL_MODULE和LOCAL_SRC_FILES,如:

include $(BUILD_SHARED_LIBRARY)

注意:这会生成一个名为lib$(LOCAL_MODULE).so文件。

(3)BUILD_STATIC_LIBRARY

该变量类似于BUILD_SHARED_LIBRARY,用来编译生成静态库,静态库不会拷贝到你的工程,但是可以用来生成共享库,如:

include $(BUILD_STATIC_LIBRARY)

注意:这会生成一个名为lib$(LOCLA_MODULE).a文件。

(4)PREBUILT_SHARED_LIBRARY

指定一个脚本,用来指定一个预置的共享库,和BUILD_SHARED_LIBRARY以及BUILD_SHARED_LIBRARY不同的是,LOCAL_SRC_FILES的值必须是一个预置共享库的路径,而不是一个源文件,如foo/libfoo.so文件,还可以在另一个模块中使用LOCAL_PREBUILTS变量来引用预置库。

(5)PREBUILT_STATIC_LIBRARY

和PREBUILT_SHARED_LIBRARY类似,但指定一个静态库。

(6)TARGET_ARCH

由AOSP指定的CPU架构名称,arm表示与ARM兼容。

(7)TARGET_PLATFORM

解析Android.mk时,目标Android平台的名称。

(8)TARGET_ARCH_ABI

解析Android.mk时,目标CPU+ABI的名称,如armeabi-v7a。

(9)TARGET_ABI

目标平台和abi的连接,由$(TARGET_PLATFORM)-$(TARGET_ARCH_ABI)定义。

5、NDK提供的函数宏

下面是GNU Make的宏方法,必须使用$(call <function>)的形式使用,返回文本信息。

(1)my-dir

返回上一个包含Makefile文件的路径,通常是当前Android.mk的目录,在Android.mk文件起始位置定义LOCAL_PATH时很有用,如:

LOCAL_PATH := $(call my-dir)

注意:由于GNU Make的工作方式,该方法返回在解析编译脚本时最后一次包含Makefile文件的路径,在包含其他文件之后不要调用my-dir,例如下面的例子:

# Android.mk

LOCAL_PATH := $(call my-dir)
# Declare one module
...
include $(LOCAL_PATH)/foo/Android.mk
# Declare another module
...

这里的问题是,第二次调用my-dir会将LOCAL_PATH定义为$(LOCAL_PATH)/foo/而不是$(LOCAL_PATH)。

基于上面的这个原因,在一个Android.mk文件中,将额外的包含动作放在所有内容的后面,如下:

# Android.mk

LOCAL_PATH := $(call my-dir)
# Declare one module
...
LOCAL_PATH := $(call my-dir)
# Declare another module
...
# Extra include at the end of Android.mk
include $(LOCAL_PATH)/foo/Android.mk

还可以用一个变量保存第一次调用my-dir的值,如下:

# Android.mk
MY_LOCAL_PATH := $(call my-dir)
LOCAL_PATH := $(MY_LOCAL_PATH)
# Declare one module
...
includ $(LOCAL_PATH)/foo/Android.mk
LOCAL_PATH := $(MY_LOCAL_PATH)
# Declare another module
...

(2)all-subdir-makefiles

返回位于当前my-dir路径下的所有子目录中的Android.mk组成的列表,例如下面的结构:

sources/foo/Android.mk
sources/foo/lib1/Android.mk
sources/foo/lib2/Android.mk

如果source/foo/Android.mk文件中包含了这句:

include $(call all-subdir-makefiles)

那么,source/foo/lib1/Android.mk和source/foo/lib2/Android.mk会自动地被包含进来。

(3)this-makefile

返回当前Makefile文件的路径。

(4)parent-makefile

返回包含树中父Makefile文件的路径,如包含当前Makefile的Makefile的路径。

(5)grand-parent-makefile

与parent-makefile类似。

(6)import-module

该方法通过名字查找和包含另一个模块,通常的用法是:

$(call import-module,<name>)

该方法会在NDK_MODULE_PATH环境变量中查找标签为<name>的模块,然后自动地将它的Android.mk包含进来。

6、模块描述变量

下面的变量用来向编译环境描述模块,应该在include $(CLEAR_VARS)和include $(BUILD_XXX)之间定义这些变量,$(CLEAR_VARS)会取消定义或者清除所有这些变量。

(1)LOCAL_PATH

这个变量表示当前文件所在的路径,必须在Android.mk的开始处定义,可以由下面的命令来完成:

LOCAL_PATH := $(call my-dir)

$(CLEAR_VARS)不会清除该变量,因此,每个Android.mk只需定义一次即可。

(2)LOCAL_MODULE

模块的名字,每一个模块的名字必须唯一并且不含空格,必须在包含$(BUILD_XXX)脚本之前定义这个变量,默认的,这个名字决定了生成文件的名字,如名为<foo>的模块,共享库的名字为lib<foo>.so。

(3)LOCAL_MODULE_FILENAME

这个变量是可选的,帮助重新定义生成文件的名字,默认的情况下,<foo>模块会按照Unix的一般标准生成名为lib<foo>.a的静态库或者名为lib<foo>.so的共享库,可以通过LOCAL_MODULE_FILENAME重新定义生成文件的名字,如下:

# Android.mk
LOCAL_MODULE := foo-version-
LOCAL_MODULE_FILENAME := libfoo

注意:不要在LOCAL_MODULE_FILENAME中放路径或者拓展名,这些会被编译系统自动处理。

(4)LOCAL_SRC_FILES

用来编译的模块的源文件列表,只需要列出需要被传给编译器的文件,编译环境会自动计算依赖关系,所有的源文件名是相对LOCAL_PATH的,也可以使用路径分隔符,如:

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

(5)LOCAL_CPP_EXTENSIONS

这是一个可选的变量,用来指示C++的源文件的文件拓展名,默认的是.cpp,但是可以改变它,如:

LOCAL_CPP_EXTENSION := .cxx

(6)LOCAL_C_INCLUDES

这是可选的变量,相对NDK根目录的相对路径列表,在编译所有的源文件时会被添加到搜索路径后面,如:

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

它们需要放置在LOCAL_CFLAGS/LOCAL_CPPFLAGS之前,在使用ndk-gdb进行native调试时将自动使用LOCAL_C_INCLUDES路径。

(7)LOCAL_CFLAGS

这是一个可选的变量,编译C/C++源文件时的编译器flags,可以用来指定额外的宏定义和编译选项。

(8)LOCAL_CXXFLAGS

LOCAL_CPPFLAGS的别名。

(9)LOCAL_CPPFLAGS

可选的变量,编译C++文件时编译器flags,在编译器命令行中,他们出现在LOCAL_CFLAGS之后。

(10)LOCAL_STATIC_LIBRARIES

需要链接到这个模块的静态库module(使用BUILD_STATIC_LIBRARY编译的)列表,只在共享库中有用。

(11)LOCAL_SHARED_LIBRARIES

该模块在运行时需要依赖的共享库列表,在链接时需要,并在生成文件中嵌入相应的信息。

(12)LOCAL_LDLIBS

编译模块时需要的额外链接flags列表,传递指定的以-l为前缀的系统库,例如,下面的指令会告诉链接器生成一个在加载的时候链接到/system/lib/libz.so的模块:

LOCAL_LDLIBS := -lz

(13)LOCAL_ALLOW_UNDEFINED_SYMBOLS

默认情况下,在编译共享数据库时会遇到未定义的引用,导致未定义符号的错误,这对在源码中抓取log的作用很大,但是,如果考虑到某些原因需要关闭这个选项,将变量设置为true即可。

(14)LOCAL_ARM_MODE

默认情况下,以thumb模式生成ARM目标二进制,每一个指令都是16比特宽,如果想强制生成arm(32比特指令)模式下的模块,可以定义这个变量为arm,如下:

LOCAL_ARM_MODE := arm

也可以通过在源文件名称后面添加后缀.arm的方式编译系统以指定的arm模式编译源文件,如:

LOCAL_SRC_FILES := foo.c bar.c.arm

这会告诉编译系统以arm模式编译bar.c,但根据LOCAL_ARM_MODE的值编译foo.c。

(15)LOCAL_ARM_NENO

定义这个变量为true允许在C/C++文件中使用ARM Advanced SIMD GCC(也叫NEON)指令,就像在程序集文件中使用NEON指令一样。

(16)LOCAL_CFLAGS

定义这个变量来记录一组C/C++编译flags,这些会被添加到使用这个变量的模块的LOCAL_STATIC_LIBRARIES或者LOCAL_SHARED_LIBRARIES的LOCAL_CFLAGS中,例如:

# Define "foo" module
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
include $(BUILD_STATIC_LIBRARY) # Define "bar" module
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_CFLAGS := -DBAR=
LOCAL_STATIC_LIBRARYS := foo
include $(BUILD_SHARED_LIBRARY)

在编译bar.c时会将-DFOO=1 –DBAR=2传给编译器,exported flags会被一层一层的传递,如果zoo依赖于bar,而bar依赖于foo,那么foo中的所有flags会被传给zoo,exported flags在当前module编译时不会被使用,在上面,编译foo/foo.c时不会传递-DFOO=1。

(17)LOCAL_EXPORT_CPPFLAGS

和LOCAL_EXPORT_CFLAGS一样,但是只对C++文件。

(18)LOCAL_EXPORT_C_INCLUDES

和LOCAL_EXPORT_CFLAGS一样,但记录的是C头文件路径。

(19)LOCAL_EXPORT_LDLIBS

和LOCAL_EXPORT_CFLAGS一样,记录链接器flags,导入的链接器flags会被添加到模块的LOCAL_LDLIBS中,这由Unix链接器的工作方式决定,当foo是一个静态库并且部分代码依赖系统库,该变量将会很有用,LOCAL_EXPORT_LDLIBS可以被用来导出依赖,如:

# Define "foo" module
include $(CLEAR_VARS)
LOCAL_MODULE := foo
LOCAL_SRC_FILES := foo/foo.c
LOCAL_EXPORT_LDLIBS := -llog
include $(BUILD_STATIC_LIBRARY) # Define "bar" module
include $(CLEAR_VARS)
LOCAL_MODULE := bar
LOCAL_SRC_FILES := bar.c
LOCAL_STATIC_LIBRARY := foo
include $(BUILD_SHARED_LIBRARY)

这里,libbar.so在链接时编译-llog,表示它依赖于系统日志库,因为它依赖于foo。

(20)LOCAL_FILTER_ASM

使用一个shell命令定义这个变量,用来过滤LOCAL_SRC_FILES中的或者由其生成的程序集文件。

Android.mk基础的更多相关文章

  1. Android.mk的用法和基础【转】

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

  2. Android.mk的用法和基础

    一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...

  3. Android.mk 文件语法详解

    0. Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build Syst ...

  4. Android.mk 基本应用

    如果是在android源码里面编译我们自己的应用,就需要这个android.mk文件,这个文件就告诉android系统应用如何来编译这个应用以及这个应用它所依赖哪些文件等等信息.我对android.m ...

  5. Android.mk 文件语法详解 转:http://blog.sina.com.cn/s/blog_602f8770010148ce.html

    0. Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build Syst ...

  6. android.mk android源码编译

    http://www.cnblogs.com/chenbin7/archive/2013/01/05/2846863.html Android.mk简单分析 2013-01-05 22:51 by . ...

  7. Android JNI入门第四篇——Android.mk文件分析

    ndroid.mk文件是在使用NDK编译C代码时必须的文件,Android.mk文件中描述了哪些C文件将被编译且指明了如何编译.掌握Android.mk文件的编写主要是掌握其里头将要使用的一些关键字, ...

  8. [Cocos2d-x]Android的android.mk文件通用版本

    原文地址: http://blog.ready4go.com/blog/2013/10/12/update-android-dot-mk-with-local-src-files-and-local- ...

  9. Android JNI的Android.mk文件语法详解

    Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build System解 ...

随机推荐

  1. Kubernetes中的Volume介绍

    Kubernetes中支持的所有磁盘挂载卷简介发表于 2018年1月26日 Weihai Feb 10,2016 7400 字 | 阅读需要 15 分钟 容器磁盘上的文件的生命周期是短暂的,这就使得在 ...

  2. One SQL to Rule Them All – an Efficient and Syntactically Idiomatic Approach to Management of Streams and Tables(中英双语)

    文章标题 One SQL to Rule Them All – an Efficient and Syntactically Idiomatic Approach to Management of S ...

  3. java--String与int相互转换

    字符串与int类型的互相转换 String ---> int //方式一:Integer(String s) //demo: Integer i = new Integer("10&q ...

  4. getOwnPropertyDescriptor

    语法 Object.getOwnPropertyDescriptor(obj, prop) 参数 obj 需要查找的目标对象 prop 目标对象内属性名称 返回值 如果指定的属性存在于对象上,则返回其 ...

  5. Android viewPager+fragment实现滑页效果

    先上图,手指在手机向左或者向右滑就可以实现相应的页面切换. 先看activity_main.xml文件,非常简单,主要是三个标题TextView和viewpager <?xml version= ...

  6. sudo: /usr/lib/sudo/sudoers.so must be only be writable by owner

    因为某种原因,手动给usr文件夹改了权限,之后我自己这个账户(非root)就不能运行sudo命令,提示"sudo: /usr/lib/sudo/sudoers.so must be only ...

  7. elastic常用工具

    elasticsearch 常用工具: elasticsearch-dump :备份 elasticsearch-head :数据展示.操作平台 elasticsearch-head github 地 ...

  8. Linux计划任务管理

    计划任务 类型:     一次性计划任务     周期性计划任务      一次性计划任务 前提:  atd服务必须运行 [root@wei init.d]# yum -y install at   ...

  9. 开放API接口安全处理!

    目录 概念 加密 MD5 Token 开放api参数 重复提交,恶意调用 日志 验证码 开放API接口安全处理! 参考文献: 公钥,私钥和数字签名这样最好理解 (转载) 概念 存在问题: 数据窃取 数 ...

  10. DML(数据库操作语言)(六)

    一.INSERT插入语句 语法: INTERT INTO 表名(列名1,列名2, ...) VALUES(列值1, 列值2, ...);# 在表名后给出要插入的列名,其他没有指定的列等同与插入null ...