初步了解Android编译系统

来源:互联网 发布:netbeans php插件 编辑:程序博客网 时间:2024/05/18 00:32

前言

    由于公司需求,需要删除android平台上一些不需要的应用来节省系统空间。各处询问和删删减减之后突然想对android编译系统有个了解,所以在

http://www.360doc.com/content/13/0517/09/11640461_286025430.shtml

    这篇文章的指导下进行了学习,觉得受益匪浅,内容大部分都是该篇文章作者 强波 老师的内容,本文主要是根据自己的开发环境进行的一次学习记录。

Android Build系统简介

    Android Build系统可以看做是编译Android系统、Android SDK、以及相关文档的一套框架,可以看做是一个加工机器,进去的是源代码,出来的是一套成熟的工具。    目的:Android是开源的,提供自定义开发,那么无论怎么改,都可以按照这套Build系统来进行编译,这样就可以统一化管理,你要添加模块,删除模块,都可以通过这个Build系统来设定。    处理逻辑:Build系统的处理逻辑定义在Makefile文件中,其他脚本只是辅助作用。

Build系统mk文件的分类

Build系统的mk文件分类

Build系统结果的目录结构(/out 目录下)

所有的产物都在/out目录下
这里写图片描述

Build系统入口

入口即在源码根目录下执行make命令,等价于执行make droid命令,会先读取/build/core/Makefile文件,然后改文件中include main.mk文件,通过main.mk文件指向更多的mk文件,形成整个build系统的编译逻辑。

Android mk文件的简介

  • main.mk : 对编译环境进行检查,引入其他的Make文件。定义主要的Make目标。(Make目标的说明:比如执行 make clean这个命令,clean称为目标,有一个类似clean.mk文件,说着有对clean进行一个说明,说明这个命令(目标)是改如何运作,目标 == 命令 == 命令的内容)

  • help.mk : 名为help的目标的定义,就是make help这个命令如何做在这个mk文件中定义,这个命令会列出主要的make目标及其说明,在根目录下执行才会有效果

  • pathmap.mk : 将许多头文件路径,以 名 <—-> 值对的方式定义成映射列表,并提供include-path-for的函数来获取,eg:$(call include-path-for , framework-native)===>得到了 /framework/native/include 的路径,等价于定义常量

  • envsetup.mk : 配置Build系统需要的环境变量,比如:TARGET_PRODUCT,TARGET_BUILD_VARIANT。当前编译的主机平台信息(操作系统,CPU类型),指定编译结果的输出路径。

  • combo/select.mk : 根据编译器的平台选择平台相关的Make文件,/build/core/combo/arch(arm,arm64,x64,mips等等)

    -dvmpvar.mk : 在Build之前显示Build的配置信息,每次make之前都会出现的一排配置信息。如下图:

    -config.mk : 定义了许多常量来负责不同类型板块的编译,比如编译apk,C/C++ 库 ,JAVA库,等等,不同类型对应的常量不同,然后在Android.mk中包含了不同的常量,代表这个模块要编译成 apk C/C++ java 。定义了编译器参数以及常见的文件后缀,.zip , .jar , .apk ,根据BoardConfig.mk 文件配置相关的参数,设置常用的工具的路径,eg : flex ,e2fsck ,dx

  • definitions.mk : 定义大量的函数,提供给build系统其他文件使用,eg:my-dir , sing-package等等以及说明。

  • distdir.mk : dist目标的定义,dist 目录,拷贝到指定路径

  • dex_propt.mk : 针对启动Jar包的预先优化

  • Ddk-config.mk : 针对pdk(platform development kit)的配置文件

  • $(ONE_SHOT_MAKEFILE)变量:当用mmm编译某一个具体模块的时候,这些变量就为当前指定路径下的Make文件目录,比如:mmm package/apps/SystemUI,上述的变量其实就是指向 package/apps/SystemUI/Android.mk

  • $(subdir_makefiles) :各个模块的Android.mk 文件集合,通过python脚本来获取

  • post_clean.mk : 在上一次build基础上检查build配置,并执行必要的清理工作。

  • legacy_prebuild.mk : 只定义了GRANDFATHEREN_ALL_PREBUILT 变量

    Android 模块的概念

    -Build系统编译的单位不是文件,而是模块,模块又包括Java库,C/C++ku,APK应用,可执行文件等等,这个编译模块的方式在之前config.mk 文件中可以定义好。分类如下图 :
    这里写图片描述

  • 不同的模块编译的步骤和方法是不一样的,为了统一管理和执行,就在config .mk文件定义了许多常量,每个常量都描述了一种模块类型的编译方式。

  • 变量--mk文件--编译模块方式

  • 比如在SystemUI的根目录下的Android.mk 文件最后一句有include $(BUILD_PACKAGE)说明这个模块按照apk的编译模式去编译。至于如何编译,看packege.mk这个文件中的定义

  • 不同的模块编译过程有相同的步骤,比如编译Java库和apk程序都要编译Java文件这个内容,重复的部分会抽取出来,放到专门的文件中去,其他文件包含专门的文件就可以实现重复利用。

模块编译的关系
模块编译的关系

## 开发一款Android产品简介 ##

如何定义一个产品

  • 如何在Build系统中去增加一个队该产品的定义
  • 通常放在/device 或者 是 /vender 目录下。
  • 但是一般现在的话是放在/device目录下,以 /device/公司名/产品名来定义一个产品,/vender是历史遗留问题,Google不建议在这里来使用。

    产品定义包含的文件(四个)

  • Androidproduct.mk : 这个一般只定义一个变量,名为:PRODUCT_MAKEFILE,值为:产品版本定义的文件名内容。在/device/generic/arm(x64…)/和/device/sample/products/目录下有。一般指向本目录下的一个mk文件。

  • 产本版本定义文件: 该文件包含了对特定产品版本的定义,该文件可能不止一个,同一个产品对应多个版本(国内版本,国外版本),文件中有:产品名,产品型号等等

    注意:这里版本定义不需要每个都定义,Build系统预先定义了一些组合,在/build/target/product/目录下每个文件定义了一个组合,eg:core.mk,full-base.mk,如何引用的:eg:在/device/generic/armv7-a-neon(或者arm64这两个指向 arm64中的mini_common.mk),在该文件指向了core.mk,产品版本的定义就在core.mk或者是mini_common.mk中,即指向同一个产品组合中

  • BroadConfig.mk : 该文件用来配置硬件主板,定义的是设备底层的硬件特性,eg:主板的相关信息,wifi相关信息,还有radioimage,内核等等

  • vendersetup.sh : 在/device/generic/mini_emulator_mip(还有其他)/目录中有这个文件,该文件的作用是 通过 add_lunch_combo函数在lunch函数中添加一个菜单选项。

什么是菜单选项:你在lunch的时候会出现几排那种配置,那个配置就是通过运行这个脚本文件来添加的,在没有source 之前直接lunch 是没有任何内容的,但是source build/envsetup.sh 命令后,会扫描/device/和 /vendor/目录下的素有的vendersetup.sh文件,根据其内容,即运行add….函数来添加选项,所以在source直接在进行lunch会出现很多配置选项

这里写图片描述

格式:产品名称 - 编译类型

如何去添加新模块

  • 在源码树中,一个模块的所有文件都处于同一个文件夹中,为了将当前模块添加到整个build系统中,每个模块需要一个专门的Makefile文件。文件名统一为:Android.mk ,build系统会依据文件内容编译出相应产物,在build系统中,编译以模块为单位,而不是以文件为单位。build系统会根据文件内容编译出相应的产物
  • 一个模块依赖的对象只可以是另一个模块,而不是其他类型的对象。
  • eg:编译好的二进制库,如果当做依赖对象,将编译好的库作为单独的模块,使用BUILD_PREBUILT或者BUILD_MULIT_PREBUILT
  • eg : 编译JAVA库需要Jar包,不可指定路径作为依赖,而先将Jar包打包成一个模块,而后编译Java库时通过模块的名称依赖这些Jar包。

例子: /package/Dialer/Android.mk

  • 以/package/Dialer/Android.mk 为例,一般以以下两句开头
  • LOACL_PATH : = $ (call my-dir)
  • 设置当前模块的编译路径为当前文件夹路径
  • include $(CLEAR-VARS)
  • 清理其他模块设置过的编译环境中的变量,这个CLEAR-VARS定义在config.mk 文件中指向的 clear_vars.mk 文件
  • build系统定义了很多环境变量,编译不同的模块,环境变量对应的内容应该是不同的,所以要先清理一下,先设置这些变量,再编译。
  • 有这些变量需要了解一下
  • LOCAL_SRC_FILES : 当前模块包含所有的源代码文件
  • LOCAL_MODULE : 当前模块名称,唯一,模块间的依赖关系通过这些名称来确定
  • LOCAL_STATIC_LIBRARIES : 依赖库的名称(后面加上其他模块的名称,这个名称就是上面的LOCAL_MODULE来定义的)
  • LOCAL_JAVA_LIBRARY : 当前模块一拉的JAVA共享库
  • 在/package/Dialer/Android.mk 中有:
  • LOCAL_JAVA_LIBRARY : = telephony-common
  • 说明dialer一拉的共享java库为telephony-common,这个模块是在/framework/opt/telephony/Android.mk 中有LOCAL_MODULE : =telephony-common 来定义的
  • LOCAL_PACKAGE_NAME : 当前APK包名
  • LOCAL_CERTIFICAFE : 签署当前应用的证书名称 这个是定义是否可以加入到系统中。
  • LOCAL_MODULE_TAGS : 当前模块包含的标签,一个模块可以拥有多个标签,标签可能为 debug,eng,user,development,optional 这里注意,如果没写的话就是optional,所以的版本都会编译进去的

    不同版本编译的内容

    eng 版本

  • 处于开发阶段编译的版本

  • 安装带有debug,user,development标签的模块
  • 安装所有无标签的非APK模块
  • 安装所有产品定义文件中指定的APK模块

    user

  • 处于最终发布的版本

  • 安装带有user标签的模块
  • 安装所有无标签的非APK模块
  • 安装所有产品定义文件中指定的APK模块,(非?)APK模块将会被忽略掉

    userdebug

  • 处于调试阶段的版本

  • 与user一样然后还会安装安装debug标签的模块
  • 安装所有无标签的非APK模块
  • 编译出来的系统有root访问权限

编译出一个apk文件 ##

  • 在文件最后加入 include $(BUILD_PACKAGE) ,这个BUILD_PACKAGE在 config.mk 文件中定义了,决定了编译模块的方式
  • include 引入其他目录下的mk文件。

BUILD系统定义的便捷函数

  • $(call my-dir) : 获取到当前文件路径
  • $(call all-java(C,aidl) - file -under ,) :获取指定目录下的所有Java文件,C文件,aidl文件
  • $(call all-makefile s-under ,) : 获取指定目录下的Make文件
0 0
原创粉丝点击