Android编译系统结构

Android编译系统的架构:

分析Android编译系统,你会发现,Android编译系统完成的并不仅仅是对目标(主机)系统二进制文件、java应用程序的编译、链接、打包等,而且还有包括生成各种依赖关系、确保某个模块的修改引起相依赖的文件的重新编译链接,甚至还包括目标文件系统的生成,配置文件的生成等,因此Android编译系统具有支持多架构(linux-x86、windows、arm等)、多语言(汇编、C、C++、Java等)、多目标、多编译方式。这些目标和结构决定其架构也很重要。

Android编译系统集中于build/core下,几个很重要的*.mk文件如下:

main.mk(主控Makefile)

base_rules.mk(对一些Makefile的变量规则化)

config.mk(关于编译参数、编译命令的一些配置)

definations.mk(定义了很多编译系统中用到的宏,相当于函数库)

Makefile(这个Makefile特指build/core下的Makefile,此文件主要控制生成system.img,ramdisk.img,userdata.img,以及recorvery image,sdk等)

Binary.mk(控制如何生成目标文件)

Clear_vars.mk(清除编译系统中用到的临时变量)

Combo/linux-arm.mk(控制如何生成linux-arm二进制文件,包括ARM相关的编译器,编译参数等的设置)

Copy_headers.mk(将头文件拷贝到指定目录)

分散于各个目录下的Android.mk(控制生成局部模块的源码,名称所需头文件路径,依赖库等特殊选项)

Build/envsetup.mk(编译环境初始化,定义一些实用的shell函数,方便编译使用)

以上几个主要的文件,可以按照社会分工打一个比方:

Main.mk是总统,是老大,承担了很多工作。

Makefile是副总统,辅佐老大Main.mk

Base_rules.mk是交警,让不规则的东西,变得规则。

Config.mk是省长,规定了各个人民群众该如何行事

Definations.mk是图书馆管理员

Binary.mk应该属于村长了,规定每个人该如何行事

Clear_vars.mk应该属于保洁公司的工人吧

Combo/linux-arm.mk应该属于社会公民了,他决定自己该如何去做

Main.mk分析

Main.mk主要包含如下几个部分的内容

1.       SHELL设置

2.       编译环境配置

3.       编译环境检查

4.       包含必要的宏

5.       根据make参数设置编译时的变量

6.       包含需要编译的Android.mk

7.       设置编译系统Target:prerequisites 控制整个编译流程

下面对上面几点进行必要解释:

有了前面小节对Android编译系统架构的分析,如果需要修改Android编译系统,就可以不至于盲目找问题,修改代码了。今天分析下main.mk,看它能为我们Android编译提供什么有价值的信息,以及如何自己定制我们的Android编译系统。

Main.mk的第一句就根据ANDROID_BUILD_SHELL来包裹编译系统用到的Shell,如果我们不想使用bash,而想使用sh,那么就可以在它前面写上ANDROID_BUILD_SHELL := /bin/sh,或者在build/envsetup.sh中添加相关定义。

定义完SHELL之后,就是对MAKE_VERSION的检查,然后定义了默认的编译目标droid!

如果我们敲入make之后,不加任何参数,默认的目标就是droid。注意虽然后面的include $(BUILD_SYSTEM)/config.mk写在默认目标droid依赖之后,但其和之后的语句都是要执行的,这是Makefile的语法决定的。

后面会include config.mk cleanbuild.mk对编译系统进行必要的配置。后面就是对编译环境的检查,包括是否大小写敏感、路径检查、java版本检查、javac版本检查。Android对编译环境的检查如果符合条件,在下次编译的时候,不会再次进行检查。

检查完版本之后,会包含进definations.mk,如前所述,definations.mk中定义了很多编译系统中用到的宏,这些宏在编译时需要经常调用,因此在编译的很靠前的阶段,就将之包含了进来。

然后就是针对make时传入的编译类型(eng user userdebug showcommands等)进行编译配置,这些配置会影响到最终编译目标所包括的模块。对于eng user userdebug sdk win_sdk tests等编译目标的区别,读者可以通过查看main.mk的代码找出其中到底有什么不同。

此处略去部分部分不重要的内容,直接跳到

Ifeq($(SDK_ONLY),true)处,大概368行附近,这个判断语句一直到这个语句块结束,都是对subdirs变量的设置,subdirs变量决定了哪些子文件夹最终被编译。

在后面的subdir_makefiles变量的设置,决定了哪些Android.mk被编译。紧接着include $(subdir_makefiles)就会添加所有这些Android.mk文件的依赖。这其中包含了droid的依赖,后面我们会发现。

然后就会根据这些Makefile,找出所有需要编译的模块(module),以及进行必要的分类(eng_MODULES/debug_MODULES/tests_MODULES等、modules_to_check/modules_to_install等),用以区别对待。

紧接着是定义了一系列的隐含目标:prebuilt、all_copied_headers、files、checkbuild、ramdisk、systemtallball、userdataimage、userdatatarball、bootimg、droidcore等。最重要的一点,是会发现droid依赖于droidcore,而droidcore依赖于

droidcore: files \

systemimage \

$(INSTALLED_BOOTIMAGE_TARGET) \

$(INSTALLED_RECOVERYIMAGE_TARGET) \

$(INSTALLED_USERDATAIMAGE_TARGET) \

$(INSTALLED_FILES_FILE)

正是这几个依赖项,控制着整个android的编译。



        图1 android 的makefile结构

 

android的编译文件主要依赖于mk文件,其源码编译名字是Android.mk,而不我们常见的Makefile文件。

 

android目录下的Makefile文件,include了build/core目录下的main.mk文件。

main.mk文件

    main.mk要完成功能,主要如下:

   包含build/core/config.mk:根据目标板的标准变量和主机信息,设置一些变量。确定输出目录和产品工程。

    SHELL := /bin/bash, 表明用到系统bash,如果想用其他的sh,那么据此而改即可。

   检测host的操作系统,编译环境。

   包含definitions.mk,标准的编译系统设定参数。主要是一些宏定义,如在Android.mk常见到的all-subdir-makefiles、my-dir之类的宏。 

   主要内容还是在 config.mk文件。

1config.mk

   首先会检测主目录下的buildspec.mk,目前此文件不存在,我们可在此设置一些参数。

   这些参数,可用于envsettup.mk,如果没有buildspec.mk文件,envsettup.mk则默认一些变量,如TARGET_ARCH:= arm ,TARGET_OS := linux等。   

1.1 envsettup.mk   

   应该说envsettup.mk是config.mk重要组成部分,设置一些主要编译工程的相关参数。

   首先includeversion_defaults.mk,设置以下变量:

        PLATFORM_VERSION

        PLATFORM_SDK_VERSION

        DEFAULT_APP_TARGET_SDK

        BUILD_ID

        BUILD_NUMBER

   其次设定TARGET_PRODUCT,也就是在编译地时候如果没有用makePRODUCT-xxx-xxx,则会在此处设定。否则就要根据product_config.mk文件里的内容进行target和product的相关参数。

   再次,设置一些输出文件路径变量,如TARGET_OUT_XXX之类的。

   最后把一些简单信息显示终端上:

    $(info============================================)

    $(info  PLATFORM_VERSION_CODENAME=$(PLATFORM_VERSION_CODENAME))

    $(info   PLATFORM_VERSION=$(PLATFORM_VERSION))

    $(info   TARGET_PRODUCT=$(TARGET_PRODUCT))

    $(info   TARGET_BUILD_VARIANT=$(TARGET_BUILD_VARIANT))

    $(info   TARGET_SIMULATOR=$(TARGET_SIMULATOR))

    $(info   TARGET_BUILD_TYPE=$(TARGET_BUILD_TYPE))

    $(info   TARGET_ARCH=$(TARGET_ARCH))

    $(info   HOST_ARCH=$(HOST_ARCH))

    $(info   HOST_OS=$(HOST_OS))

    $(info   HOST_BUILD_TYPE=$(HOST_BUILD_TYPE))

    $(info   BUILD_ID=$(BUILD_ID))

    $(info============================================)

 

    envsetup.mk里头最主要的就是product_config.mk

   

    product_config.mk包含三个文件node_fns.mk、product.mk和device.mk。此三文件都是一些宏定义或变量定义,目的是根据make时传进来的参数,从vendor目录和build/target目录下,找到相应的product和devcie信息,即找BoardConfig.mk文件,从而设定TARGET_PRODUCT、TARGET_DEVICE等值。

   

1.2 pathmap.mk,一些头文件路径,及androidframework目录。

     编译系统内部的一些文件:host_static_library.mk、host_shared_library.mk等

         

1.3 BoardConfig.mk

   默认情况下是编译的board是generic。

   查找build/target/board/generic目录上的内容,共有两个mk文件,AndroidBoard.mk和BoardConfig.mk。其中BoardConfig.mk定义一些硬件特性。

 

2 Makefile文件

    build/core/Makefile文件是系统集成了,完成img,app,frameworks、模块的编译(可能有错)

 

 

3 对于framework开发,或者在系统移植时添加应用程序,每写一次代码就要进行编译,而每次用make相关参数命令时,编译的时间会比较长。这时可以考虑以下方式进行编译

    cdanddroid_top_path

    ./build/envsetup.sh

   此时就用mmm,mm和m命令进行编译:

    m表示在顶层目录进行编译

    mm 表示在当前目录下进行模块编译

    mmm path, 编译path目录下的模块。

   一般在写模块时,用mmm命令就可以了。

 

   以下是转载内容,在framework新增加或修改代码,所谓的系统移植了,链接地址为http://xxw8393.blog.163.com/blog/static/3725683420107532137920/

    “

      如何向android的framework里添加新类

    

     google对于所有的类和API,分为开放式和不开放式两种。所谓的开放式就是值javadoc所包含    的,并不是java中有public和private,而是跟javadoc有关系,代码没有关系。


     在开放式的类中增加了一个变量,而又没隐藏,导致和原API的doc不一致造成的就会有错。
     通过提示,有2个方法可以解决 该问题:
     1、将新增加的变量或方法加上"@hide"的注释,注意一点,加"@hide"不是简简单单   的/*@hide */就行了,标准的javadoc要这样 /**  */而且对于 format变量 应该加上 {  },  也就是/**{@hide}*/
     2、如果想在生成的doc中增加该变量或方法的话,必须输入:
     make update-api
     这样的话,系统 自动 将新增加的API添加到current.xml中了。

 

    所以如果要加方法就是按上面的方法加。

 

    如果需要加进新的类 这时候又分2种 :一种是原有的包下面加类 这个最简单 加完之后直接make   update-api就好了 还有一种是加在framework/base下面 这个时候你make update-api是不会在current。xml里生成你的类的。 看了Android。mk才知道 原来需要修改     android源码根目录下的build/core/pathmap.mk把你的目录加进去。然后就好了。


   事实上对于famework的开发,可以通过mmm命令生成新jar包,然后手动的方式传到模块器对应目录,一般是/system/framework/即可,当然也可以自己写个脚本,敲一命令,一步到位亦可。


  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值