编译Android源码(2) ---- envsetup.sh文件分析

在Android源码下载完成后,只需要简单的三个步骤就能把Android编译完成( http://source.android.com/source/building.html):
1.当前目录切换到Android源码下,
. build/envsetup.sh
2.执行lunch命令,选择你要的target

3.make

这些步骤的确很简单,但是背后实际做了什么呢?这篇文章会分析envsetup.sh文件,对shell不熟悉的同学可以打开(http://www.gnu.org/software/bash/manual/bash.html),遇到不懂的地方可以参考一下。

首先我们看envsetup.sh,里面声明了很多方法,但是我们用户一般就使用lunch就够了,所以不一一讲解,不然会昏了。在执行完这个文件后,这些方法都可以在当前的shell里使用,lunch便是其中的一个方法,所以我们必须先执行envsetup.sh,才能使用lunch。我们看看除了方法的声明外,它还做了什么。

77行

VARIANT_CHOICES=(user userdebug eng)

这里定义了一个名为VARIANT_CHOICES的数组,它是作用是让用户选择不同的编译方案,user适合正式的产品发布,userdebug在user基础上提供root和调试工具,eng适合开发,附带调试工具。

191-257行

case `uname -s` in
    Linux)
        function choosesim()
        {
            echo "Build for the simulator or the device?"
            echo "     1. Device"
            echo "     2. Simulator"
            echo

            export TARGET_SIMULATOR=
            local ANSWER
            while [ -z $TARGET_SIMULATOR ]
            do
                echo -n "Which would you like? [1] "
                if [ -z "$1" ] ; then
                    read ANSWER
                else
                    echo $1
                    ANSWER=$1
                fi
                case $ANSWER in
                "")
                    export TARGET_SIMULATOR=false
                    ;;
                1)
                    export TARGET_SIMULATOR=false
                    ;;
                Device)
                    export TARGET_SIMULATOR=false
                    ;;
                2)
                    export TARGET_SIMULATOR=true
                    ;;
                Simulator)
                    export TARGET_SIMULATOR=true
                    ;;
                *)
                    echo
                    echo "I didn't understand your response.  Please try again."
                    echo
                    ;;
                esac
                if [ -n "$1" ] ; then
                    break
                fi
            done

            set_stuff_for_environment
        }
        ;;
    *)
        function choosesim()
        {
            echo "Only device builds are supported for" `uname -s`
            echo "     Forcing TARGET_SIMULATOR=false"
            echo
            if [ -z "$1" ]
            then
                echo -n "Press enter: "
                read
            fi

            export TARGET_SIMULATOR=false
            set_stuff_for_environment
        }
        ;;
esac


这是shell的一个case,其实就像我们平时c,java里面的switch。`uname -s`返回的是内核的名字,如果你使用的是基于Linux内核的系统,如Ubuntu,Fedora,OpenSuse等,此时则返回Linux,使用Mac的就返回Darwin。这个case是根据Linux内核和其他内核定义不同choosesim方法。

434行

unset LUNCH_MENU_CHOICES
清除LUNCH_MENU_CHOICES变量的值

448-449行

add_lunch_combo full-eng
add_lunch_combo full_x86-eng

这2行代码的调用了add_lunch_combo方法

function add_lunch_combo()
{
    local new_combo=$1
    local c
    for c in ${LUNCH_MENU_CHOICES[@]} ; do
        if [ "$new_combo" = "$c" ] ; then
            return
        fi
    done
    LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
}

可以看出是给LUNCH_MENU_CHOICES数组增加内容。

453-455行


if [ "$(uname)" = "Linux" ] ; then
    add_lunch_combo simulator
fi
再次调用uname,获得内核名字,如是Linux则添加simulator的选项。

528行:alias bib=breakfast

设定一个别名,以后调用bib就等于调用breakfast。

924-938行

case `uname -s` in
    Darwin)
        function sgrep()
        {
            find -E . -type f -iregex '.*\.(c|h|cpp|S|java|xml|sh|mk)' -print0 | xargs -0 grep --color -n "$@"
        }

        ;;
    *)
        function sgrep()
        {
            find . -type f -iregex '.*\.\(c\|h\|cpp\|S\|java\|xml\|sh\|mk\)' -print0 | xargs -0 grep --color -n "$@"
        }
        ;;
esac

又一次调用了uname,根据Mac和其他系统的find命令不同,声明了其对应的sgrep方法。

955-980行

case `uname -s` in
    Darwin)
        function mgrep()
        {
            find -E . -type f -iregex '.*/(Makefile|Makefile\..*|.*\.make|.*\.mak|.*\.mk)' -print0 | xargs -0 grep --color -n "$@"
        }

        function treegrep()
        {
            find -E . -type f -iregex '.*\.(c|h|cpp|S|java|xml)' -print0 | xargs -0 grep --color -n -i "$@"
        }

        ;;
    *)
        function mgrep()
        {
            find . -regextype posix-egrep -iregex '(.*\/Makefile|.*\/Makefile\..*|.*\.make|.*\.mak|.*\.mk)' -type f -print0 | xargs -0 grep --color -n "$@"
        }

        function treegrep()
        {
            find . -regextype posix-egrep -iregex '.*\.(c|h|cpp|S|java|xml)' -type f -print0 | xargs -0 grep --color -n -i "$@"
        }

        ;;
esac

跟上者一样。

1590-1597行

_xarray=(a b c)
if [ -z "${_xarray[${#_xarray[@]}]}" ]
then
    _arrayoffset=1 #zero-based (bash)
else
    _arrayoffset=0 #one-based (zsh)
fi
unset _xarray

这里是要测试当前shell的数组第一个元素的index是从1还是0开始。这里有点复杂,有的同学可能没看懂,那我就慢慢解释一下了,首先

${#_xarray[@]}

是获取_xarry数组的元素个数,这里返回3。然后

${_xarray[${#_xarray[@]}]}

就是获取_xarray中index为3的元素,如果使用的bash,这里返回空,因为bash是zero-based,如果是zsh,则返回 'c' ,因为zsh是one-based。如果返回的是空,也就是当前使用bash,则设置_arrayoffset = 1 , 否则设置为0.

这里一开始不太明白,因为bash是zero-based的,不是应该设置_arrayoffset = 0 吗?怎么倒过来了,想了好久,后来看了下它的具体使用情况,如下篇文章会说到的lunch命令,直接执行lunch命令时,会列出各种combo:

You're building on Linux

Lunch menu... pick a combo:
     1. full-eng
     2. full_x86-eng
     3. simulator
     4. generic_sholest-userdebug
     5. cyanogen_ace-eng
     6. cyanogen_anzu-eng
     7. cyanogen_blade-eng
     8. cyanogen_bravo-eng
     9. cyanogen_bravoc-eng
     10. cyanogen_buzz-eng
     11. cyanogen_c660-eng
     12. cyanogen_click-eng
     13. cyanogen_captivatemtd-eng
     14. cyanogen_coconut-eng
     15. cyanogen_cooper-eng
     16. cyanogen_crespo-eng
     17. cyanogen_crespo4g-eng
     18. cyanogen_desirec-eng
     19. cyanogen_dream_sapphire-eng
     20. cyanogen_droid2-eng
     21. cyanogen_droid2we-eng
     22. cyanogen_e510-eng
     23. cyanogen_e730-eng
     24. cyanogen_encore-eng
     25. cyanogen_epicmtd-eng
     26. cyanogen_es209ra-eng
     27. cyanogen_espresso-eng
     28. cyanogen_fascinatemtd-eng
     29. cyanogen_galaxys2-eng
     30. cyanogen_galaxys2att-eng
     31. cyanogen_galaxysbmtd-eng
     32. cyanogen_galaxysmtd-eng
     33. cyanogen_generic-eng
     34. cyanogen_glacier-eng
     35. cyanogen_hallon-eng
     36. cyanogen_hero-eng
     37. cyanogen_heroc-eng
     38. cyanogen_inc-eng
     39. cyanogen_iyokan-eng
     40. cyanogen_jordan-eng
     41. cyanogen_legend-eng
     42. cyanogen_leo-eng
     43. cyanogen_liberty-eng
     44. cyanogen_mango-eng
     45. cyanogen_mecha-eng
     46. cyanogen_mesmerizemtd-eng
     47. cyanogen_mimmi-eng
     48. cyanogen_morrison-eng
     49. cyanogen_motus-eng
     50. cyanogen_one-eng
     51. cyanogen_olympus-eng
     52. cyanogen_p500-eng
     53. cyanogen_p920-eng
     54. cyanogen_p925-eng
     55. cyanogen_p970-eng
     56. cyanogen_p990-eng
     57. cyanogen_p999-eng
     58. cyanogen_passion-eng
     59. cyanogen_robyn-eng
     60. cyanogen_saga-eng
     61. cyanogen_satsuma-eng
     62. cyanogen_shadow-eng
     63. cyanogen_shakira-eng
     64. cyanogen_sholes-eng
     65. cyanogen_showcasemtd-eng
     66. cyanogen_smb_a1002-eng
     67. cyanogen_smb_a1004-eng
     68. cyanogen_smb_a1011-eng
     69. cyanogen_smb_b9701-eng
     70. cyanogen_smultron-eng
     71. cyanogen_speedy-eng
     72. cyanogen_supersonic-eng
     73. cyanogen_tass-eng
     74. cyanogen_u8150-eng
     75. cyanogen_u8220-eng
     76. cyanogen_urushi-eng
     77. cyanogen_v9-eng
     78. cyanogen_vega-eng
     79. cyanogen_vision-eng
     80. cyanogen_vivo-eng
     81. cyanogen_vivow-eng
     82. cyanogen_z71-eng
     83. cyanogen_zeppelin-eng
     84. cyanogen_zero-eng
     85. cyanogen_zeus-eng
     86. cyanogen_zeusc-eng
     87. cyanogen_sholest-eng

Which would you like? [full-eng]

可以看到是从序号1开始递增的,这时用户是输入序号或者相应的字符串以选择想要的combo,如果用户使用了序号,看看lunch中的处理:

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

answer变量是用户输入的数值,如我输入了87,要获得相应的字符串,则必须减去_arrayoffset,就是减去1,也就解释了为什么当使用bash时要设_arrayoffset为1了!

1600-1605行

for f in `{ setopt nullglob; /bin/ls vendor/*/vendorsetup.sh vendor/*/build/vendorsetup.sh device/*/*/vendorsetup.sh; } 2> /dev/null`
do
    echo "including $f"
    . $f
done
unset f

setopt是zsh的东西,我使用bash就没管它了。这里使用ls列出了vendor下指定位置的vendorsetup.sh,把文件列表传给for循环,

echo打印出include了哪个文件,并且执行了它。

其实vendorsetup.sh的内容就是一堆add_lunch_combo,到此为止,我们的envsetup.sh已经执行完了,其实它的作用主要是2点:

1.声明了之后会使用的各种方法和变量。

2.设定好lunch命令需要使用的combos。

你可能感兴趣的:(编译Android源码(2) ---- envsetup.sh文件分析)