• android编译系统学习


    近日接手了后续android新平台项目搭建的任务。

    本文内容基于sprd公司提供的android5.1源码。

    一、一般的编译工作流程

    我们代码一般情况下是从芯片商SPRD/MTK获得的。

    源码的编译上,一般还是和google官网(http://source.android.com/source/building.html)上要求的一致。分为三步:

    1.source build/envsetup.sh

    2.lunch xxx

    3.make -j8 2>&1 |tee build.log (make就可以,这样写两个目的:1.多核编译 2.输出编译的log)

    4.mmm "模块"可以编译单独的模块(要全编译后才可以编译模块)

    二、原理

    android的编译是基于的linux的make命令的。Make命令在执行的时候,默认会在当前目录找到一个Makefile文件,然后根据Makefile文件中的指令来对代码进行编译。

    Makefile文件最基础的功能就是描述文件之间的依赖关系,以及怎么处理这些依赖关系。

    整个android源码的编译就是由根目录的Makefile文件来执行的。

    现在我们就了解下我们编译过程中的命令做了哪些事情。

    1.source build/envsetup.sh

    执行build/envsetup.sh脚本(ps: source xx.sh命令就是 执行一个脚本的意思。那为什么不直接./xxx.sh呢? 见这篇文章http://blog.csdn.net/coofive/article/details/671835)

    build/envsetup.sh脚本里做了哪些事情呢?

    (1)遍历出device/xxx/xxx/里 所有的 envsetup.sh文件,并将他们都source进来,

    这些 envsetup.sh里面有哪些代码呢

    举一个例子 device/sprd/zsl1805/lava/envsetup.sh

    add_lunch_combo zsl1805_lava-userdebug
    add_lunch_combo zsl1805_lava-user

    add_lunch_combo是什么东西?我们先不管,往下看。

    (2)定义各种函数。

    如:lunch mmm add_lunch_combo等。

    lunch:用来初始化编译环境,例如设置环境变量和指定目标产品型号。后面再说

    m:相当于是在执行make命令。对整个Android源码进行编译。

    mm:如果是在Android源码根目录下执行,那么就相当于是执行make命令对整个源码进行编译。如果是在Android源码根目录下的某一个子目录执行,那么就在会在从该子目录开始,一直往上一个目录直至到根目录,寻找是否存在一个Android.mk文件。如果存在的话,那么就通过make命令对该Android.mk文件描述的模块进行编译。

    mmm:后面可以跟一个或者若干个目录。就是编译模块了。如mmm "packages/apps/Launcher3"

    add_lunch_combo:

     1 unset LUNCH_MENU_CHOICES
     2 function add_lunch_combo()
     3 {
     4     local new_combo=$1
     5     local c
     6     for c in ${LUNCH_MENU_CHOICES[@]} ; do
     7         if [ "$new_combo" = "$c" ] ; then
     8             return
     9         fi
    10     done
    11     LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
    12 }

    这里我们只要知道add_lunch_combo把"zsl1805_lava_userdebug"和"zsl1805_lava_user"add到"LUNCH_MENU_CHOICES"里了。

    到这里,source build/envsetup.sh的工作就做完了。

    此时可以在shell命令行里看到 

    including device/sprd/zsl1805/lava/vendorsetup.sh的字样,这个文件确实被加载进来了

     2.lunch操作

    我们先看下build/envsetup.sh中lunch函数的代码

      1 #打印"LUNCH_MENU_CHOICES"中所有值
      2 function print_lunch_menu()
      3 {
      4     local uname=$(uname)
      5     echo
      6     echo "You're building on" $uname
      7     echo
      8     echo "Lunch menu... pick a combo:"
      9 
     10     local i=1
     11     local choice
     12     for choice in ${LUNCH_MENU_CHOICES[@]}
     13     do
     14         echo "     $i. $choice"
     15         i=$(($i+1))
     16     done
     17 
     18     echo
     19 }
     20 
     21 function lunch()
     22 {
     23     local answer
     24 #如果只输入了lunch命令,会打印"LUNCH_MENU_CHOICES"中所有值
     25     if [ "$1" ] ; then
     26         answer=$1
     27     else
     28         print_lunch_menu
     29         echo -n "Which would you like? [aosp_arm-eng] "
     30         read answer
     31     fi
     32 
     33 #判断lunch后面的值是不是LUNCH_MENU_CHOICES中的值,如果是,则把这个值赋给selection
     34     local selection=
     35 
     36     if [ -z "$answer" ]
     37     then
     38         selection=aosp_arm-eng
     39     elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
     40     then
     41         if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
     42         then
     43             selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
     44         fi
     45     elif (echo -n $answer | grep -q -e "^[^-][^-]*-[^-][^-]*$")
     46     then
     47         selection=$answer
     48     fi
     49 
     50     if [ -z "$selection" ]
     51     then
     52         echo
     53         echo "Invalid lunch combo: $answer"
     54         return 1
     55     fi
     56 
     57     export TARGET_BUILD_APPS=
     58     export CONFIG_TARGET_BUILD_TYPE=
     59 
     60 
     61 #对selection值进行分割操作,得到product和variant
     62 
     63     local product=$(echo -n $selection | sed -e "s/-.*$//")
     64     check_product $product
     65     if [ $? -ne 0 ]
     66     then
     67         echo
     68         echo "** Don't have a product spec for: '$product'"
     69         echo "** Do you have the right repo manifest?"
     70         product=
     71     fi
     72 
     73     local variant=$(echo -n $selection | sed -e "s/^[^-]*-//")
     74     check_variant $variant
     75     if [ $? -ne 0 ]
     76     then
     77         echo
     78         echo "** Invalid variant: '$variant'"
     79         echo "** Must be one of ${VARIANT_CHOICES[@]}"
     80         echo "** Vinton.Wang -----------> variant:'$variant'"
     81         export CONFIG_TARGET_BUILD_TYPE=$(echo $variant | tr '[a-z]' '[A-Z]')
     82         echo "** Vinton.Wang -----------> type:'$CONFIG_TARGET_BUILD_TYPE'"
     83         variant="userdebug"
     84     fi
     85 
     86     if [ -z "$product" -o -z "$variant" ]
     87     then
     88         echo
     89         return 1
     90     fi
     91 #得到TARGET_PRODUCT TARGET_BUILD_VARIANT TARGET_BUILD_TYPE三个值
     92     export TARGET_PRODUCT=$product
     93     export TARGET_BUILD_VARIANT=$variant
     94     export TARGET_BUILD_TYPE=release
     95     export ARCH=$(gettargetarch)
     96     echo "############# ${ARCH} ##############"
     97 
     98     echo
     99     echo
    100     check_hq_version
    101     set_stuff_for_environment  #设置环境变量
    102     printconfig
    103 }

     另外,在check_product()和printconfig()两个方法中,调用了get_build_var()函数。

    # Get the exact value of a build variable.
    function get_build_var()
    {
        T=$(gettop)
        if [ ! "$T" ]; then
            echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
            return
        fi
        (cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core 
          command make --no-print-directory -f build/core/config.mk dumpvar-$1)
    }

    也就是说,在lunch的过程中,编译了build/core/config.mk

    总结一下Lunch流程:

    1.判断是不是没有参数

    2.判断参数是否合法

    3.将参数进行分割操作,得到TARGET_PRODUCT    TARGET_BUILD_VARIANT 。针对我们的例子TARGET_PRODUCT = zsl1805_lava  TARGET_BUILD_VARIANT = user或者userdebug

    4.设置环境变量

    如果我们直接输入lunch,会有下面的界面出现

    You're building on Linux

     
    generic-eng simulator fs100-eng
    Lunch menu... pick a combo:
         1. generic-eng
         2. simulator
         3. fs100-eng
             .....................

            40. zsl1805_lava-userdebug
            41. zsl1805_lava-user

    然后,我们需要lunch zsl1805_lava-userdebug即可。

    到此时,android编译环境的初始化就完成了。

    贴一张初始化完成之后,我们获得的东西

    3.make

    下面就是执行编译了。根目录里的Makefile文件中是这样的

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

    Make其实就是按照main.mk的编译规则来编译的。

    整个编译过程还是比较复杂的,这里有一张main.mk的编译示意图,基本涵盖了所有编译内容。这里,如果对某些细节感兴趣,可以看下面的参考资料再去深入学习。

    如果我们要对编译过程中的流程修改,就按照这个图找到相应的.mk文件进行修改。

    参考资料:

    Android编译系统环境初始化过程分析

    Android编译过程详解(一):http://www.cnblogs.com/mr-raptor/archive/2012/06/07/2540359.html

    Android编译过程详解(二):http://www.cnblogs.com/mr-raptor/archive/2012/06/08/2541571.html

  • 相关阅读:
    svn使用总结
    捕获JS 错误日志
    致敬 54岁的刘德华
    Mac 下 命令收藏
    坑人的七牛CDN
    【No.1】监控Linux性能25个命令行工具
    PAC 自动代理
    jquery 事件 多次绑定,多次触发,怎么清除历史绑定事件
    Squid 操作实践
    ntpdate[16603]: the NTP socket is in use
  • 原文地址:https://www.cnblogs.com/xerrard/p/5145725.html
Copyright © 2020-2023  润新知