Android的优势就在于其开源,软件开发商可以根据自己的需求来基于Android定制自己的OS,如小米(MIUI),魅族(Flyme),锤子(Smartisan)等,因此,在对Android的源码进行定制的时候,有必要了解Android的编译过程。

Android的官方网站:http://source.android.com/source/building.html,给出了一个通用系统的编译过程

+--------------------------------------------------------------------------------------------------------------------+

本文使用Android版本为2.1

+--------------------------------------------------------------------------------------------------------------------+

首先来看一下google给出的编译步骤:

1> source build/envsetup.sh:加载命令

2> lunch:选择平台编译选项

3> make:执行编译

我们按照编译步骤来分析编译过程的细节,最终添加自己的平台编译选项。

1. source build/envsetup.sh

这个命令是用来将envsetup.sh里的所有用到的命令加载到环境变量里去,我们来分析下它。

envsetup.sh里的主要命令如下:

function help()                  
# 显示帮助信息

function get_abs_build_var()            # 获取绝对变量

function get_build_var()              # 获取绝对变量

function check_product()              # 检查product

function check_variant()              # 检查变量

function setpaths()                # 设置文件路径

function printconfig()               # 打印配置

function set_stuff_for_environment()        # 设置环境变量

function set_sequence_number()            # 设置序号

function settitle()                # 设置标题

function choosetype()               # 设置type

function chooseproduct()              # 设置product

function choosevariant()              # 设置variant

function tapas()                  # 功能同choosecombo

function choosecombo()               # 设置编译参数

function add_lunch_combo()             # 添加lunch项目

function print_lunch_menu()            # 打印lunch列表

function lunch()                  # 配置lunch

function m()                    # make from top

function findmakefile()              # 查找makefile

function mm()                   # make from current directory

function mmm()                   # make the supplied directories

function croot()                  # 回到根目录

function cproj()

function pid()

function systemstack()

function gdbclient()

function jgrep()                  # 查找java文件

function cgrep()                  # 查找c/cpp文件

function resgrep()

function tracedmdump()

function runhat()

function getbugreports()

function startviewserver()

function stopviewserver()

function isviewserverstarted()

function smoketest()

function runtest()

function godir ()                  # 跳到指定目录 405

# add_lunch_combo函数被多次调用,就是它来添加Android编译选项

 # Clear this variable.  It will be built up again when the vendorsetup.sh

 406 # files are included at the end of this file.

 # 清空LUNCH_MENU_CHOICES变量,用来存在编译选项

 407 unset LUNCH_MENU_CHOICES

 408 function add_lunch_combo()   

 409 {

 410     local new_combo=$1         # 获得add_lunch_combo被调用时的参数

 411     local c

     # 依次遍历LUNCH_MENU_CHOICES里的值,其实该函数第一次调用时,该值为空

 412     for c in ${LUNCH_MENU_CHOICES[@]} ; do 

 413         if [ "$new_combo" = "$c" ] ; then    # 如果参数里的值已经存在于LUNCH_MENU_CHOICES变量里,则返回

 414             return

 415         fi

 416     done

     # 如果参数的值不存在,则添加到LUNCH_MENU_CHOICES变量里

 417     LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)

 418 }

# 这是系统自动增加了一个默认的编译项 generic-eng

 420 # add the default one here

 421 add_lunch_combo generic-eng    # 调用上面的add_lunch_combo函数,将generic-eng作为参数传递过去

 422 

 423 # if we're on linux, add the simulator.  There is a special case

 424 # in lunch to deal with the simulator

 425 if [ "$(uname)" = "Linux" ] ; then

 426     add_lunch_combo simulator

 427 fi

# 下面的代码很重要,它要从vendor目录下查找vendorsetup.sh文件,如果查到了,就加载它

1037 # Execute the contents of any vendorsetup.sh files we can find.

1038 for f in `/bin/ls vendor/*/vendorsetup.sh vendor/*/build/vendorsetup.sh 2> /dev/null`

1039 do

1040     echo "including $f"

1041    . $f       # 执行找到的脚本,其实里面就是厂商自己定义的编译选项

1042 done

1043 unset f

envsetup.sh其主要作用如下:

  1. 加载了编译时使用到的函数命令,如:help,lunch,m,mm,mmm等

  2. 添加了两个编译选项:generic-eng和simulator,这两个选项是系统默认选项

  3. 查找vendor/<-厂商目录>/和vendor/<厂商目录>/build/目录下的vendorsetup.sh,如果存在的话,加载执行它,添加厂商自己定义产品的编译选项

 其实,上述第3条是向编译系统添加了厂商自己定义产品的编译选项,里面的代码就是:add_lunch_combo xxx-xxx。

根据上面的内容,可以推测出,如果要想定义自己的产品编译项,简单的办法是直接在envsetup.sh最后,添加上add_lunch_combo myProduct-eng,当然这么做,不太符合上面代码最后的本意,我们还是老实的在vendor目录下创建自己公司名字,然后在公司目录下创建一个新的vendorsetup.sh,在里面添加上自己的产品编译项

#mkdir
vendor/farsight/
#touch
vendor/farsight/vendorsetup.sh
#echo
"add_lunch_combo fs100-eng" > vendor/farsight/vendorsetup.sh

这样,当我们在执行source build/envsetup.sh命令的时候,可以在shell上看到下面的信息:

including
vendor/farsight/vendorsetup.sh

2. 按照android官网的步骤,开始执行lunch full-eng

当然如果你按上述命令执行,它编译的还是通用的eng版本系统,不是我们个性系统,我们可以执行lunch命令,它会打印出一个选择菜单,列出可用的编译选项

如果你按照第一步中添加了vendorsetup.sh那么,你的选项中会出现:

You're
building on Linux
 
generic-eng
simulator fs100-eng
Lunch
menu... pick a combo:
     1.
generic-eng
     2.
simulator
     3.
fs100-eng

其中第3项是我们自己添加的编译项。

lunch命令是envsetup.sh里定义的一个命令,用来让用户选择编译项,来定义Product和编译过程中用到的全局变量。

我们一直没有说明前面的fs100-eng是什么意思,现在来说明下,fs100是我定义的产品的名字,eng是产品的编译类型,除了eng外,还有user, userdebug,分别表示:

eng: 工程机,

user:最终用户机

userdebug:调试测试机

tests:测试机

由此可见,除了eng和user外,另外两个一般不能交给最终用户的。

那么这四个类型是干什么用的呢?其实,在main.mk里有说明,在Android的源码里,每一个目标(也可以看成工程)目录都有一个Android.mk的makefile,每个目标的Android.mk中有一个类型声明:LOCAL_MODULE_TAGS,这个TAGS就是用来指定,当前的目标编译完了属于哪个分类里。

PS:Android.mk和Linux里的makefile不太一样,它是Android编译系统自己定义的一个makefile来方便编译成:c,c++的动态、静态库或可执行程序,或java库或android的程序,

好了,我们来分析下lunch命令干了什么?

function lunch()

{

    local answer

if [ "$1" ] ; then

       # lunch后面直接带参数

        answer=$1

    else

       # lunch后面不带参数,则打印处所有的target product和variant菜单提供用户选择

        print_lunch_menu   

        echo -n "Which would you like? [generic-eng] "

        read answer

    fi

local selection=

if [ -z "$answer" ]

    then

           # 如果用户在菜单中没有选择,直接回车,则为系统缺省的generic-eng

        selection=generic-eng

    elif [ "$answer" = "simulator" ]

    then

        # 如果是模拟器

        selection=simulator

    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")

    then

        # 如果answer是选择菜单的数字,则获取该数字对应的字符串

        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]

        then

            selection=${LUNCH_MENU_CHOICES[$(($answer-$_arrayoffset))]}

        fi

        # 如果 answer字符串匹配 *-*模式(*的开头不能为-)

    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")

    then

        selection=$answer

    fi

if [ -z "$selection" ]

    then

        echo

        echo "Invalid lunch combo: $answer"

        return 1

    fi

# special case the simulator

    if [ "$selection" = "simulator" ]

    then

        # 模拟器模式

        export TARGET_PRODUCT=sim

        export TARGET_BUILD_VARIANT=eng

        export TARGET_SIMULATOR=true

        export TARGET_BUILD_TYPE=debug

    else

# 将 product-variant模式中的product分离出来

        local product=$(echo -n $selection | sed -e "s/-.*$//")

# 检查之,调用关系 check_product()->get_build_var()->build/core/config.mk比较罗嗦,不展开了

        check_product $product

        if [ $? -ne 0 ]

        then

            echo

            echo "** Don't have a product spec for: '$product'"

            echo "** Do you have the right repo manifest?"

            product=

        fi

# 将 product-variant模式中的variant分离出来

        local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")

# 检查之,看看是否在 (user userdebug eng) 范围内

        check_variant $variant

        if [ $? -ne 0 ]

        then

            echo

            echo "** Invalid variant: '$variant'"

            echo "** Must be one of ${VARIANT_CHOICES[@]}"

            variant=

        fi

if [ -z "$product" -o -z "$variant" ]

        then

            echo

            return 1

        fi

 #  导出环境变量,这里很重要,因为后面的编译系统都是依赖于这里定义的几个变量的

        export TARGET_PRODUCT=$product

        export TARGET_BUILD_VARIANT=$variant

        export TARGET_SIMULATOR=false

        export TARGET_BUILD_TYPE=release

    fi # !simulator

echo

# 设置到环境变量,比较多,不再一一列出,最简单的方法 set >env.txt 可获得

    set_stuff_for_environment

    # 打印一些主要的变量, 调用关系 printconfig()->get_build_var()->build/core/config.mk->build/core/envsetup.mk 比较罗嗦,不展开了

    printconfig

}

由上面分析可知,lunch命令可以带参数和不带参数,最终导出一些重要的环境变量,从而影响编译系统的编译结果。导出的变量如下(以实际运行情况为例)

TARGET_PRODUCT=fs100
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=release

执行完上述两个步骤,就该执行:make命令了,下篇来分析。

Android编译过程详解(一)的更多相关文章

  1. Android编译过程详解(三)

    前面两节讲解了自定义Android编译项和创建Product产品配置文件,除了编译和定义产品相关环境变量外,还需要定义Board相关环境变量. 1. build/core/config.mk 109 ...

  2. Android编译过程详解(二)

    通过上篇文章,我们分析了编译android时source build/envsetup.sh和lunch命令,在执行完上述两个命令后, 我们就可以进行编译android了. 1. make  执行ma ...

  3. Android 核心分析 之八Android 启动过程详解

    Android 启动过程详解 Android从Linux系统启动有4个步骤: (1) init进程启动 (2) Native服务启动 (3) System Server,Android服务启动 (4) ...

  4. cegui-0.8.2编译过程详解

    cegui 编译过程详解(cegui-0.8.2) cegui配置整了好长时间了,在一位大牛帮助下终于搞定了,网上的教程大多是老版本的,cegui-0.8.2版的配置寥寥无几,现在总结一下,献给正在纠 ...

  5. GCC 概述:C 语言编译过程详解

    Tags: C Description: 关于 GCC 的个人笔记 GCC 概述 对于 GCC 6.1 以及之后的版本,默认使用的 C++ 标准是 C++ 14:使用 -std=c++11 来指定使用 ...

  6. uboot主Makefile分析(t配置和编译过程详解)

    1.编译uboot前需要三次make make distcleanmake x210_sd_configmake -j4 make distclean为清楚dist文件. make x210_sd_c ...

  7. uboot配置和编译过程详解【转】

    本文转载自:http://blog.csdn.net/czg13548930186/article/details/53434566 uboot主Makefile分析1 1.uboot version ...

  8. uboot配置和编译过程详解

    根据朱有鹏老师讲解整理 一.uboot主Makefile分析 1.uboot version确定(Makefile的24-29行) include/version_autogenerated.h文件是 ...

  9. Cocos2dx-3.0版本 从开发环境搭建(Win32)到项目移植Android平台过程详解

    作为重量级的跨平台开发的游戏引擎,Cocos2d-x在现今的手游开发领域占有重要地位.那么问题来了,作为Cocos2dx的学习者,它的可移植特性我们就需要掌握,要不然总觉得少一门技能.然而这个时候各种 ...

随机推荐

  1. #pragma预处理指令讲解

    在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的 ...

  2. Hibernate4.1.4配置二级缓存EHCache步骤

    1.当然首先引入EHCache相关的jar包 这些包不需要另外下载,在Hibernate官方网站下载Hibernate4.1.7的压缩包(如:hibernate-release-4.1.7.Final ...

  3. Hardwood Species

    http://poj.org/problem?id=2418 #include<cstdio> #include<cstring> #include<string> ...

  4. android 动态改变listview的内容

    本文模拟:点击一个按钮,为已有的listview添加一行数据 <?xml version="1.0" encoding="utf-8"?> < ...

  5. Java经典书籍

    Java Web开发教程---孙霞JSP应用开发详解(第三版)---刘晓华.张健.周慧贞Spring in Action---Craig Walls精通Struts基于MVC的Java Web设计与开 ...

  6. SPRING IN ACTION 第4版笔记-第九章Securing web applications-004-对密码加密passwordEncoder

    一. 1.Focusing on the authentication query, you can see that user passwords are expected to be stored ...

  7. Spring的依赖注入

    依赖注入—手工装配(XML方式)--通过属性注入(相应属性必须有setter方法才行,同时,要有无参构造方法): <!-- 通过属性注入(setter方法) --> <bean id ...

  8. POJ3295——Tautology

    Tautology Description WFF 'N PROOF is a logic game played with dice. Each die has six faces represen ...

  9. 手动添加 memcached.jar包

    由于目前java memcached client没有官方的maven repository可供使用,因此使用时需要手动将其安装到本地repository. java memcached client ...

  10. Android Framework------之Input子系统

    下面这是基于Android4.2代码的关于Input子系统的笔记.在这篇笔记中,只涉及Android相关的东西,关于Linux内核中对各种输入设备的统一,在本文中不作说明.此外,由于才疏学浅,文中难免 ...