Android Donut Makefile分析 (build/envsetup.sh)


build/envsetup.sh 腳本主體部分

看源代碼之前需要了解代碼分佈和結構,分析Makefile應該是最好的方法。在Blog記錄之以備以後查看,也供有興趣朋友參考。

在編譯donut之前,需要運行

cd ~/mydroid
. build/envsetup.sh
lunch aosp_dream_us-eng
make

build/envsetup.sh 是編譯android的入口。該shell腳本定義了一些函數,並設定了編譯的環境變量。

lunch aosp_dream_us-eng 配置用戶需要編譯的目標產品(target product)和變體(variant)。

aosp_dream_us-eng 字符串包含了target product  和variant,它們用減號-隔開,aosp_dream_us是target product,eng是variant。

variant 有三種選擇user userdebug eng,可以從字面上看出其意義,但具體的差別還不是特別清楚,待後面分析之。

lunch 的入口是讓用戶指定或者選擇需要編譯的target product 和 variant,出口是設定編譯相關的環境變量。

build/envsetup.sh 定義了很多函數,並且執行的腳本很分散,因此下面將所有的函數都刪除掉了,剩餘下腳本的主體,便於代碼分析和走讀。

該主體主要做的事情是:

1. 首先腳本設定了兩個缺省的target product,一個是generic-eng,一個是simulator

2. 運行所有vendor下的 vendorsetup.sh文件,在google官方的 donut源代碼中,爲vendor/aosp/vendorsetup.sh,內容如下:

add_lunch_combo aosp_emulator_us-eng
add_lunch_combo aosp_emulator_eu-eng
add_lunch_combo aosp_dream_us-userdebug
add_lunch_combo aosp_dream_eu-userdebug
add_lunch_combo aosp_dream_us-eng
add_lunch_combo aosp_dream_eu-eng
add_lunch_combo aosp_sapphire_us-userdebug
add_lunch_combo aosp_sapphire_eu-userdebug
add_lunch_combo aosp_sapphire_us-eng
add_lunch_combo aosp_sapphire_eu-eng

可以看出,又添加了一些 和 aosp 相關的 target product 和 variant。

下面是腳本主體,用藍色添加了一下注釋,便於閱讀:

# 定義了 variant的字符範圍
VARIANT_CHOICES=(user userdebug eng)

# 如果是Linux環境,定義了幾個和simulator相關的函數
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


# 首先將 LUNCH_MENU_CHOICES 變量消除
# Clear this variable.  It will be built up again when the vendorsetup.sh
# files are included at the end of this file.
unset LUNCH_MENU_CHOICES          


# 當前 LUNCH_MENU_CHOICES = generic-eng
# add the default one here
add_lunch_combo generic-eng         


# 當前 LUNCH_MENU_CHOICES = generic-eng simulator
# if we're on linux, add the simulator.  There is a special case
# in lunch to deal with the simulator
if [ "$(uname)" = "Linux" ] ; then    
    add_lunch_combo simulator       
fi


# 這裏是MAC OS的環境,不考慮
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


# 設定當前shell環境的數組下標從0開始還是1開始,並記錄在 _arrayoffset
# determine whether arrays are zero-based (bash) or one-based (zsh)
_xarray=(a b c)
if [ -z "${_xarray[${#_xarray[@]}]}" ]
then
    _arrayoffset=1
else
    _arrayoffset=0
fi
unset _xarray


# 運行所有vendor下的 vendorsetup.sh文件
#存在vendor/aosp/vendorsetup.sh
當前 LUNCH_MENU_CHOICES = generic-eng simulator aosp_emulator_us-eng aosp_emulator_eu-eng aosp_dream_us-userdebug aosp_dream_eu-userdebug aosp_dream_us-eng aosp_dream_eu-eng aosp_sapphire_us-userdebug aosp_sapphire_eu-userdebug aosp_sapphire_us-eng aosp_sapphire_eu-eng

# Execute the contents of any vendorsetup.sh files we can find.
for f in `/bin/ls vendor/*/vendorsetup.sh vendor/*/build/vendorsetup.sh 2> /dev/null` 
do
    echo "including $f"
    . $f
done
unset f

明天接下來看 lunch()函數


build/envsetup.sh 腳本分析(lunch函數)

lunch函數提供了一個菜單,讓開發人員選擇需要編譯的目標產品(target product)和變體(variant),並做一些檢查,設置環境變量,並打印出主要的環境變量。

直接運行lunch(必須先運行 build/envsetup.sh,讓lunch函數駐留到環境變量中)

ning@ning-desktop:~/donut-compare/mydroid$ lunch

You're building on Linux

generic-eng simulator aosp_emulator_us-eng aosp_emulator_eu-eng aosp_dream_us-userdebug aosp_dream_eu-userdebug aosp_dream_us-eng aosp_dream_eu-eng aosp_sapphire_us-userdebug aosp_sapphire_eu-userdebug aosp_sapphire_us-eng aosp_sapphire_eu-eng
Lunch menu... pick a combo:
     1. generic-eng
     2. simulator
     3. aosp_emulator_us-eng
     4. aosp_emulator_eu-eng
     5. aosp_dream_us-userdebug
     6. aosp_dream_eu-userdebug
     7. aosp_dream_us-eng
     8. aosp_dream_eu-eng
     9. aosp_sapphire_us-userdebug
     10. aosp_sapphire_eu-userdebug
     11. aosp_sapphire_us-eng
     12. aosp_sapphire_eu-eng

Which would you like? [generic-eng] 7

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=1.6
TARGET_PRODUCT=aosp_dream_us
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=Donut
============================================

用戶也可以直接輸入參數,不使用菜單

ning@ning-desktop:~/donut-compare/mydroid$ lunch aosp_dream_us-eng

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=1.6
TARGET_PRODUCT=aosp_dream_us
TARGET_BUILD_VARIANT=eng
TARGET_SIMULATOR=false
TARGET_BUILD_TYPE=release
TARGET_ARCH=arm
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=Donut
============================================

下面是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
}
原文鏈接:http://www.lupaworld.com/home.php?mod=space&uid=131820&do=blog&id=149463

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章