Android.mk基础
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基础的更多相关文章
- Android.mk的用法和基础【转】
一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...
- Android.mk的用法和基础
一个Android.mk file用来向编译系统描述你的源代码.具体来说:该文件是GNU Makefile的一小部分,会被编译系统解析一次或多次.你可以在每一个Android.mk file中定义一个 ...
- Android.mk 文件语法详解
0. Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build Syst ...
- Android.mk 基本应用
如果是在android源码里面编译我们自己的应用,就需要这个android.mk文件,这个文件就告诉android系统应用如何来编译这个应用以及这个应用它所依赖哪些文件等等信息.我对android.m ...
- 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 ...
- android.mk android源码编译
http://www.cnblogs.com/chenbin7/archive/2013/01/05/2846863.html Android.mk简单分析 2013-01-05 22:51 by . ...
- Android JNI入门第四篇——Android.mk文件分析
ndroid.mk文件是在使用NDK编译C代码时必须的文件,Android.mk文件中描述了哪些C文件将被编译且指明了如何编译.掌握Android.mk文件的编写主要是掌握其里头将要使用的一些关键字, ...
- [Cocos2d-x]Android的android.mk文件通用版本
原文地址: http://blog.ready4go.com/blog/2013/10/12/update-android-dot-mk-with-local-src-files-and-local- ...
- Android JNI的Android.mk文件语法详解
Android.mk简介: Android.mk文件用来告知NDK Build 系统关于Source的信息. Android.mk将是GNU Makefile的一部分,且将被Build System解 ...
随机推荐
- docker启动,重启,关闭命令
docker启动命令,docker重启命令,docker关闭命令 启动 systemctl start docker守护进程重启 sudo systemctl daemon-relo ...
- JS基础 —— 数据类型
JS数据类型分为简单数据类型(基本数据类型)和复杂数据类型(引用数据类型). 基本数据类型:Undefined.Null.Boolean.Number.String.Symbol. 引用数据类型:Ob ...
- elementui 自定义表头 renderHeader的写法 给增加el-tooltip的提示
1.html <el-table-column prop="taxes" :render-header="renderHeader" width=&quo ...
- 开机注册联通2G网络
2/3G PLMN LIST 在MM_RATCM_PLMN_LIST_CNF或NWSEL_MM_PLMN_SEARCH_CNF消息中可以查看2,3G搜到的PLMN LIST 内容如下: RAT:Rad ...
- loadrunner安装和应用
问题:1.负载测试流程 2.为什么实现性能测试自动化 3.设置场景 (场景定义) 4.事物响应时间,吞吐量和吞吐率,正在运行vuser,windows资源,每秒点击次数,每秒http响应数. 5.i ...
- Solr缓存原理分析及配置优化
一.缓存原理 缓存,带来急速性能体验! Solr提供了一系列的内置缓存来优化查询性能.Solr的缓存原理主要涉及以下4个方面: 1.缓存大小及缓存置换法 从缓存大小的角度来看,不能将缓存设置的太大,否 ...
- mysql主从复制几个重要的参数
1. relay_log_recovery = 1 当slave从库宕机后,假如relay-log损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的relay-log,并且重新从master上 ...
- Linux shell awk模式使用
awk的PATTERN表示方法: 1,正则表达式,格式为/regex/ 以冒号为分隔符,显示/etc/passwd以r开头的行的第一段 [root@wei awk]# awk -F: '/^r/{pr ...
- openCV CV2用法(转)
文章转自:https://www.kancloud.cn/aollo/aolloopencv/262768 一.读入图像 使用函数cv2.imread(filepath,flags)读入一副图片 fi ...
- 嵌入式linux开发uboot启动内核的机制(二)
一.嵌入式系统的分区 嵌入式系统部署在Flash设备上时,对于不同SoC和Flash设备,bootloader.kernel.rootfs的分区是不同的.三星S5PV210规定启动设备的分区方案如下: ...