源:Android.mk文件详解

从对Makefile一无所知开始,折腾了一个多星期,终于对Android.mk有了一个全面些的了解。了解了标准的Makefile后,发现Android.mk其实是把真正的Makefile包装起来,做成了一个对使用者来说很简单的东西。使用它来编译程序时,不管是动态库、可执行的二进制文件,还是Jar库、APK包,只要沿着一个简单的思路来做三大步就可以了:清除旧变量,设置新变量,调用编译函数。

明白了以后,发现Makefile语法不是问题,有很多教程和高手。编译模块时如何清除变量、调用编译函数等也不是问题,源码当中无处不在这样的例子。而对初学者来说,更需要明白的可能是,Android如何让使用脚本的人从Makefile语法当中解放出来,简单地按照上面的三大步就可以编译出任何模块。

拿AlarmClock来做例子的话:

//清除旧变量

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

//设置新变量

LOCAL_SRC_FILES := $(call all-subdir-java-files)

LOCAL_PACKAGE_NAME := AlarmClock

//调用编译函数

include $(BUILD_PACKAGE)

下面简单解释一下这三步:

1、清除旧变量,是因为Android.mk中所有的变量都是全局的,编译函数在编译时会调用这些变量。为了防止编译函数使用了编译其它模块时设置的变量,每次开始编译一个新的模块时清除所有的变量是个好习惯。

2、设置新变量就是把本次编译时用到的源码地址,包名等设置好。

3、调用编译函数其实就是include一个固定的mk文件,这个mk文件会根据设置的变量提取出编译模块需要的target,Command等信息并执行固定的编译命令。

看明白Android.mk后,最深的感受还是Android的这种封装思想,让我想起了很多以前没有思考过的东西。呵。。。

我会一些个人的理解记录Android一步步地演化出这种封装思想。真诚地欢迎批评指正。

Makefile这个东西,往最简单处说,就是这样的模式:

目标:信赖文件

执行命令

这里暂不考虑它的语法细节,举个不完整的例子,就是这样的:

AlarmClock.apk:AlarmClock.java

javac AlarmClock.java

java AlarmClock.class

要生成AlarmClock.apk,就需要AlarmClock.java这个信赖文件,然后执行后面两行的两个命令。假如我们简单粗暴地用这种写法去编译Android系统的话,会相当累。Android.mk就很巧妙地把它们进行了抽象。我们现在来模拟一下:

定义三个变量target,source,command,分别代表编译目标、信赖文件和编译命令,就成了这样:

$(target):$(source)

$(command)

这三个变量的值分别是:

target := AlarmClock.apk

source := AlarmClock.java

commnd := /

javac AlarmClock.java/

java AlarmClock.class

这样的话,在编译每个APK时,只要分别给target、source、command赋值,然后再这样写就可以了:

$(target):$(source)

$(command)

嗯,还是有点儿麻烦,那再抽象一次。定义一个变量name,让它存放要编译的模块的名字:

name := AlarmClock

然后再更改一下前面的三个变量:

target := $(name).apk

source := $(name).java

commnd := /

javac $(name).java/

java $(name).class

现在要编译一个模块Contacts需要做些什么呢?

name := Contacts

$(target):$(source)

$(command)

三行代码就可以了,很简单,对吧?但后面两行还是每次都要写,那再抽象。把后面两行放到一个build_apk.mk文件当中。然后定义一个变量:

BUILD_PACKAGES := build_apk.mk

全部完了,这回编译一个模块Contacts时只要这样做就可以了:

name := Contacts

include $(BUILD_PACKAGES)

一个不够复杂,那就多点儿:

name := Contacts

include $(BUILD_PACKAGES)

name := Phone

include $(BUILD_PACKAGES)

name := Email

include $(BUILD_PACKAGES)

//================强壮的分隔线=========

现在我们来完善一下上面的过程,把它系统化。

定义一个专门用来清除变量的clear_vars.mk里面的内容如下:

name :=

target :=

source :=

command :=

再定义一个变量CLEAR_VARS := clear_vars.mk。上面的编译脚本就变成了这样:

include $(CLEAR_VARS)

name := Contacts

include $(BUILD_PACKAGES)

include $(CLEAR_VARS)

name := Phone

include $(BUILD_PACKAGES)

include $(CLEAR_VARS)

name := Email

include $(BUILD_PACKAGES)

这回,清除旧变量、设置新变量、调用编译函数三大步全都有了。

好了,现在我们进入到Android源码的build/core/目录下。先看其中的main.mk,config.mk这两个文件。

main.mk里面是具体的脚本,在这里控制编译模块。

config.mk中定义了下面这样的文件调用:

CLEAR_VARS:= $(BUILD_SYSTEM)/clear_vars.mk

BUILD_HOST_STATIC_LIBRARY:= $(BUILD_SYSTEM)/host_static_library.mk

编译模块时,每一个include其实都是一次功能调用,或者对mk文件的调用,或者对变量和函数的调用。做为单独的功能模块抽象出来的mk文件都在build/core/目录下,而函数的定义全部在definitions.mk中。

万事开头难,有了上面的思路,再看这些脚本就很简单了。一路顺风,呵。。。

Android.mk文件详解(转)的更多相关文章

  1. Android编译系统(Android.mk文件详解)

    [Android-NDK(Native Development Kit)  docs文档] NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成a ...

  2. Android.mk文件和Application.mk文件详解

    Android.mk文件和Application.mk文件详解 相同点:都是轻量级 Makefile(Makefile文件定义一些列指令,指定文件编译顺序,类似shell脚本) Application ...

  3. Android.mk用法详解

    一.Android.mk介绍 Android.mk是Android提供的一种makefile文件,用来指定诸如编译生成so库名.引用的头文件目录.需要编译的.c/.cpp文件和.a静态库文件等.要掌握 ...

  4. NDK开发之Application.mk文件详解

    做过NDK开发的同学应该都知道有个Application.mk文件,这是android NDK构建系统使用的一个可选构建文件.它的目的是描述应用程序需要哪些模块,也定义了所有模块的一些通用变量.主要有 ...

  5. Android清单文件详解(三)----应用程序的根节点<application>

    <application>节点是AndroidManifest.xml文件中必须持有的一个节点,它包含在<manifest>节点下.通过<application>节 ...

  6. Android.mk 文件语法详解

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

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

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

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

  9. Android编译过程详解(一)

    Android编译过程详解(一) 注:本文转载自Android编译过程详解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359 ...

随机推荐

  1. World Finals 2003 UVA - 1025 A Spy in the Metro(动态规划)

    分析:时间是一个天然的序,这个题目中应该决策的只有时间和车站,使用dp[i][j]表示到达i时间,j车站在地上已经等待的最小时间,决策方式有三种,第一种:等待一秒钟转移到dp[i+1][j]的状态,代 ...

  2. ZOJ Problem - 2588 Burning Bridges tarjan算法求割边

    题意:求无向图的割边. 思路:tarjan算法求割边,访问到一个点,如果这个点的low值比它的dfn值大,它就是割边,直接ans++(之所以可以直接ans++,是因为他与割点不同,每条边只访问了一遍) ...

  3. Log4j NDC MDC

    NDC(Nested Diagnostic Context)和MDC(Mapped Diagnostic Context)是log4j种非常有用的两个类,它们用于存储应用程序的上下文信息(contex ...

  4. 滑轮关节(b2PulleyJoint)

    package{ import Box2D.Collision.b2AABB; import Box2D.Collision.b2RayCastInput; import Box2D.Collisio ...

  5. 【转】PHP代码审计

    PHP代码审计 目录 1. 概述3 2. 输入验证和输出显示3 2.1 命令注入4 2.2 跨站脚本4 2.3 文件包含5 2.4 代码注入5 2.5 SQL注入6 2.6 XPath注入6 2.7 ...

  6. laravel 报错 mcrypt_decrypt(): Key of size 11 not supported by this algorithm. Only keys of sizes 16, 24 or 32 supported

    修改app/config/app.php文件 将key设置成长度为16,24,32的字符串

  7. HDU 5875 st+二分区间

    题目大意:给你n个数,q次询问,每次询问区间[l, r],问a[i]%a[i + 1] % a[i + 2]...%a[j](j <= r)的值 思路:st预处理维护,再二分区间,复杂度n*(l ...

  8. POJ1611 The Suspects 并查集模板题

    题目大意:中文题不多说了 题目思路:将每一个可能患病的人纳入同一个集合,然后遍历查找每个点,如果改点点的根节点和0号学生的根节点相同,则该点可能是病人. 模板题并没有思路上的困难,只不过在遍历时需要额 ...

  9. POJ 1426 Find The Multiple BFS

    没什么好说的 从1开始进行广搜,因为只能包涵0和1,所以下一次需要搜索的值为next=now*10 和 next=now*10+1,每次判断一下就可以了,但是我一直不太明白我的代码为什么C++提交会错 ...

  10. tabBarItem动画

    1.有时,我们需要为tabBarItem设置一些动画.在网上查了半天,没有结果.自己写了一个简单的动画 代码如下: - (void)tabBarController:(UITabBarControll ...