evo

自强不息,厚德载物 ii 无人驾驶fans ^_^ Making others better! Making life better!

【Bash百宝箱】Android编译系统(Makefile)

0、Makefile

Android编译系统基于GNU make,用来管理Makefile,Makefile的基础知识可参考:
http://blog.csdn.net/ieearth/article/details/47296429

Makefile最一般的规则就是个依赖树,如下:

target: prerequisites
    commands

target是我们编译时要生成的目标,prerequisites是编译目标所需要的依赖文件,当依赖文件比编译目标新时就会执行下面的commands,commands前需要保留一个tab制表符。Android编译系统正是基于这个简单的规则,构建了一个庞大的依赖树,首先从树的根节点开始。

1、根节点droid

Android系统源码根目录有一个Makefile:

### DO NOT EDIT THIS FILE ###
include build/core/main.mk
### DO NOT EDIT THIS FILE ###

这个Makefile没做什么事,只是简单地include另一个Makefile,build/core下的main.mk较为复杂,有1k多行代码,想要一下子看懂还是不太容易的,可以按照依赖树的规则,从根节点开始分析。Android编译系统依赖树的根节点为Makefile中从上到下的第一个编译目标,即droid:

# This is the default target.  It must be the first declared target.
.PHONY: droid
DEFAULT_GOAL := droid
$(DEFAULT_GOAL): droid_targets

.PHONY: droid_targets
droid_targets:

根节点droid是个伪目标,依赖于droid_targets,而droid_targets的依赖树有两个依赖分支:

ifneq ($(TARGET_BUILD_APPS),)
# If this build is just for apps, only build apps and not the full system by default.
...
.PHONY: apps_only
apps_only: $(unbundled_build_modules)
droid_targets: apps_only
...
else
...
# Building a full system-- the default is to build droidcore
droid_targets: droidcore dist_files 
endif # TARGET_BUILD_APPS

根据TARGET_BUILD_APPS变量的判断,当只编译app时,droid_targets依赖于apps_only,否则将编译整个系统,此时droid_targets依赖于droidcore和dist_files。理清了根节点droid的依赖树,main.mk看起来就简单多了,除了构建这些依赖规则之外,main.mk还实现了其它的配置检测功能。

a. 对编译环境的检测:比如java版本是否符合要求,当前机器上的make环境必须高于特定版本等,如果这些检查没有通过,一般情况下系统会终止编译。
b. 进行一些必要前期处理:比如说整个项目工程是否需要先进行清理工作,部分工具的安装等。
c. 引用其它Makefile文件:这点在整个main.mk中处处可见,如引用config.mk、cleanbuild.mk等。
d. 设置全局变量:这些全局变量决定了编译的具体实现过程。
e. 各种函数的实现:Android编译系统中定义了不少函数,它们提供了各种问题的统一解决方案,比如print-vars函数用于打印一串变量列表,my-dir可以知道当前所处的路径等,这些函数对我们自己编写Makefile文件也有一定的指导意义。

在Android中定制一款产品时,一般要添加几个脚本文件:vendorsetup.sh、AndroidProducts.mk、BoardConfig.mk、Android.mk。其中vendorsetup.sh是在envsetup.sh中被调用的,AndroidProducts.mk和BoardConfig.mk作一些配置工作,Android.mk用来编译具体的产品或者产品的某个部分。在Android源码的build/core目录下有许多的Makefile,下面介绍几个主要的。

main.mk:上面介绍了,这个是整个编译系统的主导文件。
config.mk:产品配置的主导文件,在main.mk中被include。
base_rules.mk:定义了编译系统需要遵循的基本规则,多个Makefile都引用了这个文件。
build_id.mk:定义了版本号,在version_defaults.mk中被引用。
cleanbuild.mk:定义了clean操作,在main.mk中被引用。
clear_vars.mk:清空几乎所有的以LOCAL_开头的系统变量,LOCAL_PATH不会被清空,在config.mk中把build/core/clear_vars.mk赋值给变量CLEAR_VARS,一般在Android.mk中使用,直接include这个文件。
definitions.mk:定义了一系列有用的函数,比如说获取当前路径的my-dir,通过call来调用,在Android.mk中经常可以看到,这个文件会include产品目录下自定义的definitions.mk,最终在main.mk中展开。
envsetup.mk:定义了编译时用到的环境变量,在config.mk中被inlcude,注意与envsetup.sh区分开来。
shared_library.mk:负责BUILD_SHARED_LIBRARY的具体实现,在config.mk中设置了这个环境变量,一般在Android.mk中include使用,表示编译目标为一个共享库。其它以BUILD_开头的表示编译目标类型的也有类似的Makefile来实现。
products_config.mk:产品配置,属于envsetup.mk中的一部分。
version_defaults.mk:用于生成版本信息。
...

2、droidcore与dist_files

在编译整个Android系统时,根节点droid依赖于droidcore和dist_files。

droidcore——

下面先来分析一下droidcore的生成过程,其依赖规则为:

# Build files and then package it into the rom formats
.PHONY: droidcore
droidcore: files \
    systemimage \
    $(INSTALLED_BOOTIMAGE_TARGET) \
    $(INSTALLED_RECOVERYIMAGE_TARGET) \
    $(INSTALLED_USERDATAIMAGE_TARGET) \
    $(INSTALLED_CACHEIMAGE_TARGET) \
    $(INSTALLED_VENDORIMAGE_TARGET) \
    $(INSTALLED_FILES_FILE) \
    $(INSTALLED_FILES_FILE_VENDOR)

systemimage用于生成system.img,其它的INSTALLED_*_TARGET也是用来生成对应的img,至于生成过程可根据依赖关系一层一层剥离。

dist_files——

# dist_files only for putting your library into the dist directory with a full build.
.PHONY: dist_files

dist_files只出现过一次,一般没什么作用。

3、Android.mk

当我们编译某个具体的模块时,就需要用到Android.mk了,那这个Android.mk该如何编写呢?Android系统中集成了许多开源项目,有非常多的Android.mk,最好的办法就是参考这些Android.mk,下面以Android中抓取内存信息的procrank工具为例,其源码位置在system/extras/procrank,Android.mk内容如下:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)
LOCAL_SRC_FILES := procrank.c
LOCAL_CFLAGS := -Wall -Wextra -Wformat=2 -Werror
LOCAL_SHARED_LIBRARIES := libpagemap
LOCAL_MODULE := procrank
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := debug
include $(BUILD_EXECUTABLE)

LOCAL_PATH通过调用my-dir函数保存了当前的路径。
CLEAR_VARS指向build/core/clear_vars.mk,用以清空以LOCAL_开头的系统变量,LOCAL_PATH除外。
LOCAL_SRC_FILES指定了编译用到的源文件。
LOCAL_CFLAGS指定了编译参数,如熟悉的-Wall等。
LOCAL_SHARED_LIBRARIES指出编译需要用到哪些共享库。
LOCAL_MODULE为编译目标的名字。
LOCAL_MODULE_PATH为编译目标的输出目录。
LOCAL_MODULE_TAGS指出编译模式为debug。
BUILD_EXECUTABLE告诉我们编译结果为一个可执行文件。
上面的Android.mk是一个非常简单的文件,实际应用中可能远比这个文件复杂,不过用法类似,在Android源码中会看到各种形式的Android.mk,这是一个学习Android.mk的好资源。

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/iEearth/article/details/50510545
文章标签: android Android-mk
个人分类: Android
所属专栏: Android知识库
上一篇【Bash百宝箱】Android源码下载及编译
下一篇【C++】Android中的同步机制
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭