[Android源碼淺析]一.編譯系統(上)

本文需要的shell基礎

一.編譯命令

每次編譯系統時,我們都會執行以下命令:

source build/envsetup.sh
lunch
make

我們就圍繞着這3個命令來分析Android的編譯系統

二.envsetup.sh

  • envsetup.sh主要做了兩件事,定義函數和生成編譯配置列表

1.定義函數

  • 這個沒什麼好說的,像我們平時常用到的mm、mmm、croot、godir等都是這裏定義的

2.生成編譯配置列表

  • 下面這段就是搜索device、vendor、product三個目錄下最大深度爲4的vendorsetup.sh
for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
         `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
         `test -d product && find -L product -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort`
do
    echo "including $f"
    . $f
done
unset f
  • addcompletions,這裏是調用了前面定義的函數addcompletions,我們看下這個函數做了什麼
function addcompletions()
{
    local T dir f

    # Keep us from trying to run in something that isn't bash.
    if [ -z "${BASH_VERSION}" ]; then 
        return # bash版本字符串如果是空,return
    fi

    # Keep us from trying to run in bash that's too old.
    if [ ${BASH_VERSINFO[0]} -lt 3 ]; then
        return # bash版本<3,return
    fi

    dir="sdk/bash_completion"
    if [ -d ${dir} ]; then # 如果sdk/bash_completion存在且是一個目錄
        for f in `/bin/ls ${dir}/[a-z]*.bash 2> /dev/null`; do # 遍歷sdk/bash_completion目錄下名字由小寫字母組成後綴是bash的文件
            echo "including $f" # 引用這個文件
            . $f
        done
    fi
}

3.執行source build/envsetup.sh

  • 看下執行結果,與上面分析相符。這要是引用了兩類文件vendorsetup.sh和*.bash
    在這裏插入圖片描述
  • 先看下vendorsetup.sh。我們用的是nexus6,那就看下device/moto/shamu/vendorsetup.sh
add_lunch_combo aosp_shamu-userdebug # 顯然是lunch命令用到的,放到lunch說明
add_lunch_combo aosp_shamu-eng # 這個是我加的
  • 再看下adb.bash。bash的內容很長,可以看到熟悉的install、push、pull等等。其實bash腳本主要是爲命令提供tab提示

三.lunch

  • lunch主要做了兩件事,添加product-variant,設置各種環境變量。下面來分析下如果做的這兩件事。

1.lunch命令格式

命令格式:
lunch <product_name>-<build_variant>

還記得add_lunch_combo aosp_shamu-userdebug嗎?
add_lunch_combo是在envsetup.sh裏定義的函數
aosp_shame就是product_name
userdebug就是build_variant

2.lunch中的重要函數

  • add_lunch_combo
function add_lunch_combo()
{
    local new_combo=$1 # new_combo=aosp_shamu-userdebug
    local c
    for c in ${LUNCH_MENU_CHOICES[@]} ; do # LUNCH_MENU_CHOICES[@]是獲取數組LUNCH_MENU_CHOICES中的所有元素
        if [ "$new_combo" = "$c" ] ; then # 如果已經有了這個元素,就返回
            return
        fi
    done
    LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo) # 新增aosp_shamu-userdebug到LUNCH_MENU_CHOICES
}
  • build_build_var_cache
# Get all the build variables needed by this script in a single call to the build system.
function build_build_var_cache()
{
    T=$(gettop)
    # Grep out the variable names from the script.
    # 提取envsetup.sh的get_build_var的參數,nexus6提取到的是:
    # 2ND_TARGET_GCC_VERSION
    # ANDROID_BUILD_PATHS
    # print
    # report_config
    # TARGET_ARCH
    # TARGET_DEVICE
    # TARGET_GCC_VERSION
    cached_vars=`cat $T/build/envsetup.sh | tr '()' '  ' | awk '{for(i=1;i<=NF;i++) if($i~/get_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`
    # 提取envsetup.sh的get_abs_build_var的參數,nexus6提取到的是:
    # ANDROID_GCC_PREBUILTS
    # ANDROID_PREBUILTS
    # HOST_OUT
    # print
    # PRODUCT_OUT
    cached_abs_vars=`cat $T/build/envsetup.sh | tr '()' '  ' | awk '{for(i=1;i<=NF;i++) if($i~/get_abs_build_var/) print $(i+1)}' | sort -u | tr '\n' ' '`
    # Call the build system to dump the "<val>=<value>" pairs as a shell script.
    # make config.mk,得到cached_vars和cached_abs_vars各項的value
    # dump-many-vars是makefile的一個僞目標
    build_dicts_script=`\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
                        command make --no-print-directory -f build/core/config.mk \
                        dump-many-vars \
                        DUMP_MANY_VARS="$cached_vars" \
                        DUMP_MANY_ABS_VARS="$cached_abs_vars" \
                        DUMP_VAR_PREFIX="var_cache_" \
                        DUMP_ABS_VAR_PREFIX="abs_var_cache_"`
    local ret=$?
    if [ $ret -ne 0 ]
    then
        unset build_dicts_script
        return $ret
    fi
    # Excute the script to store the "<val>=<value>" pairs as shell variables.
    # 給各項參數賦值
    # var_cache_2ND_TARGET_GCC_VERSION=''
	# var_cache_ANDROID_BUILD_PATHS='/home/frezrik/nexus6/out/host/linux-x86/bin'
	# var_cache_print=''
	# var_cache_TARGET_ARCH='arm'
	# var_cache_TARGET_DEVICE='shamu'
	# var_cache_TARGET_GCC_VERSION='4.9'
	# var_cache_report_config=`echo '============================================'; echo 'PLATFORM_VERSION_CODENAME=REL'; echo 'PLATFORM_VERSION=7.1.1'; echo 'TARGET_PRODUCT=aosp_shamu'; echo 'TARGET_BUILD_VARIANT=eng'; echo 'TARGET_BUILD_TYPE=release'; echo 'TARGET_BUILD_APPS='; echo 'TARGET_ARCH=arm'; echo 'TARGET_ARCH_VARIANT=armv7-a-neon'; echo 'TARGET_CPU_VARIANT=krait'; echo 'TARGET_2ND_ARCH='; echo 'TARGET_2ND_ARCH_VARIANT='; echo 'TARGET_2ND_CPU_VARIANT='; echo 'HOST_ARCH=x86_64'; echo 'HOST_2ND_ARCH=x86'; echo 'HOST_OS=linux'; echo 'HOST_OS_EXTRA=Linux-4.4.0-177-generic-x86_64-with-Ubuntu-16.04-xenial'; echo 'HOST_CROSS_OS=windows'; echo 'HOST_CROSS_ARCH=x86'; echo 'HOST_CROSS_2ND_ARCH=x86_64'; echo 'HOST_BUILD_TYPE=release'; echo 'BUILD_ID=NGI77B'; echo 'OUT_DIR=out'; echo '============================================';`
	# abs_var_cache_ANDROID_GCC_PREBUILTS='/home/frezrik/nexus6/prebuilts/gcc/linux-x86'
	# abs_var_cache_ANDROID_PREBUILTS='/home/frezrik/nexus6/prebuilt/linux-x86'
	# abs_var_cache_HOST_OUT='/home/frezrik/nexus6/out/host/linux-x86'
	# abs_var_cache_PRODUCT_OUT='/home/frezrik/nexus6/out/target/product/shamu'
	# abs_var_cache_print=''
    eval "$build_dicts_script
    ret=$?
    unset build_dicts_script
    if [ $ret -ne 0 ]
    then
        return $ret
    fi
    BUILD_VAR_CACHE_READY="true" # get_build_var report_config
}
  • set_stuff_for_environment
function set_stuff_for_environment()
{
    settitle # 設置PROMPT_COMMAND,這個在源碼裏未搜到引用的位置
    set_java_home # 設置JAVA_HOME
    setpaths # 設置各種環境變量
    set_sequence_number

    export ANDROID_BUILD_TOP=$(gettop)
    # With this environment variable new GCC can apply colors to warnings/errors
    export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
    export ASAN_OPTIONS=detect_leaks=0
}
  • printconfig
function printconfig()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
    get_build_var report_config # `echo '============================================'; echo 'PLATFORM_VERSION_CODENAME=REL'; echo 'PLATFORM_VERSION=7.1.1'; echo 'TARGET_PRODUCT=aosp_shamu'; echo 'TARGET_BUILD_VARIANT=eng'; echo 'TARGET_BUILD_TYPE=release'; echo 'TARGET_BUILD_APPS='; echo 'TARGET_ARCH=arm'; echo 'TARGET_ARCH_VARIANT=armv7-a-neon'; echo 'TARGET_CPU_VARIANT=krait'; echo 'TARGET_2ND_ARCH='; echo 'TARGET_2ND_ARCH_VARIANT='; echo 'TARGET_2ND_CPU_VARIANT='; echo 'HOST_ARCH=x86_64'; echo 'HOST_2ND_ARCH=x86'; echo 'HOST_OS=linux'; echo 'HOST_OS_EXTRA=Linux-4.4.0-177-generic-x86_64-with-Ubuntu-16.04-xenial'; echo 'HOST_CROSS_OS=windows'; echo 'HOST_CROSS_ARCH=x86'; echo 'HOST_CROSS_2ND_ARCH=x86_64'; echo 'HOST_BUILD_TYPE=release'; echo 'BUILD_ID=NGI77B'; echo 'OUT_DIR=out'; echo '============================================';`
}

3.lunch函數說明

function lunch()
{
    local answer

    if [ "$1" ] ; then
        answer=$1 # lunch後面帶參數
    else
        print_lunch_menu # 打印add_lunch_combo中賦值的LUNCH_MENU_CHOICES
        echo -n "Which would you like? [aosp_shamu-eng] "
        read answer
    fi

    local selection=

    if [ -z "$answer" ]
    then
        selection=aosp_shamu-eng # 如果未輸入,則使用缺省配置
    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$") # 匹配數字
    then
        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ] # ${#LUNCH_MENU_CHOICES[@]}是獲取LUNCH_MENU_CHOICES數組長度,如果選擇的數字小於數組長度
        then
            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
        fi
    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$") # 匹配*-*模式(*不能爲-)
    then
        selection=$answer
    fi

    if [ -z "$selection" ] # 如果selection未被賦值
    then
        echo
        echo "Invalid lunch combo: $answer"
        return 1
    fi

    export TARGET_BUILD_APPS=

    local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//") # 將 product-variant的variant分離出來
    check_variant $variant # 只能是(user userdebug eng)
    if [ $? -ne 0 ]
    then
        echo
        echo "** Invalid variant: '$variant'"
        echo "** Must be one of ${VARIANT_CHOICES[@]}"
        variant=
    fi

    local product=$(echo -n $selection | sed -e "s/-.*$//") # 將 product-variant的product分離出來
    TARGET_PRODUCT=$product \
    TARGET_BUILD_VARIANT=$variant \
    build_build_var_cache
    if [ $? -ne 0 ]
    then
        echo
        echo "** Don't have a product spec for: '$product'"
        echo "** Do you have the right repo manifest?"
        product=
    fi

    if [ -z "$product" -o -z "$variant" ]
    then
        echo
        return 1
    fi

    export TARGET_PRODUCT=$product
    export TARGET_BUILD_VARIANT=$variant
    export TARGET_BUILD_TYPE=release

    echo

    set_stuff_for_environment
    printconfig
    destroy_build_var_cache # 清除各項的值
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章