android编译分析之2—envsetup.sh

  • envsetupsh
  • 执行lunch函数时发生了什么
  • check_product
  • get_build_var

一般android编译时,会先执行下面的命令,

source build/envsetup.sh

source作用就是在当前bash环境下读取envsetup.sh,然后执行其中的命令。而envsetup.sh其实包含了很多的shell函数和一些命令,那么具体发生了什么?

envsetup.sh

$ source build/envsetup.sh 
WARNING: Only bash is supported, use of other shell would lead to erroneous results
including device/asus/deb/vendorsetup.sh
including device/asus/flo/vendorsetup.sh
including device/asus/fugu/vendorsetup.sh
including device/generic/mini-emulator-arm64/vendorsetup.sh
including device/generic/mini-emulator-armv7-a-neon/vendorsetup.sh
including device/generic/mini-emulator-mips/vendorsetup.sh
including device/generic/mini-emulator-x86_64/vendorsetup.sh
including device/generic/mini-emulator-x86/vendorsetup.sh
including device/htc/flounder/vendorsetup.sh
including device/lge/hammerhead/vendorsetup.sh
including device/moto/shamu/vendorsetup.sh
including sdk/bash_completion/adb.bash
注:从提示log,首先说明只支持bash,其他的shell都会导致编译错误。初次装完ubuntu后,默认的shell是dash,需要修改。此外还including了很多的sh,都是一些函数或者命令。

build/envsetup.sh这个脚本包含了很多的shell函数,有些函数是非常有用的,envsetup.sh中的第一个函数为hmm,类似于–help的功能,提示当执行完source后,android系统目前能干些什么,执行hmm,

$ hmm
Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- lunch:   lunch <product_name>-<build_variant>
- tapas:   tapas [<App1> <App2> ...] [arm|x86|mips|armv5|arm64|x86_64|mips64] [eng|userdebug|user]
- croot:   Changes directory to the top of the tree.
- m:       Makes from the top of the tree.
- mm:      Builds all of the modules in the current directory, but not their dependencies.
- mmm:     Builds all of the modules in the supplied directories, but not their dependencies.
           To limit the modules being built use the syntax: mmm dir/:target1,target2.
- mma:     Builds all of the modules in the current directory, and their dependencies.
- mmma:    Builds all of the modules in the supplied directories, and their dependencies.
- cgrep:   Greps on all local C/C++ files.
- ggrep:   Greps on all local Gradle files.
- jgrep:   Greps on all local Java files.
- resgrep: Greps on all local res/*.xml files.
- mangrep: Greps on all local AndroidManifest.xml files.
- sepgrep: Greps on all local sepolicy files.
- sgrep:   Greps on all local source files.
- godir:   Go to the directory containing a file.

Environemnt options:
- SANITIZE_HOST: Set to 'true' to use ASAN for all host modules. Note that
                 ASAN_OPTIONS=detect_leaks=0 will be set by default until the
                 build is leak-check clean.

Look at the source to view more functions. The complete list is:
addcompletions add_lunch_combo cgrep check_product check_variant choosecombo chooseproduct choosetype choosevariant core coredump_enable coredump_setup cproj croot findmakefile get_abs_build_var getbugreports get_build_var getdriver getlastscreenshot get_make_command getprebuilt getscreenshotpath getsdcardpath gettargetarch gettop ggrep godir hmm is isviewserverstarted jgrep key_back key_home key_menu lunch _lunch m make mangrep mgrep mm mma mmm mmma pez pid printconfig print_lunch_menu qpid rcgrep resgrep runhat runtest sepgrep set_java_home setpaths set_sequence_number set_stuff_for_environment settitle sgrep smoketest stacks startviewserver stopviewserver systemstack tapas tracedmdump treegrep
注:有几个命令非常有用:
1.croot,切到项目根目录下,android目录层次实在是太多了,不需要../..
2.*grep,在各种类型的文件中执行grep,快速
3.godir,cd到包含某个文件的文件夹下

上面注释的都很清楚,平时用的最多的是lunch和mm命令,很多命令也没研究,后续研究了再总结。接着执行lunch命令。

执行lunch函数时发生了什么

$ lunch

You're building on Linux

Lunch menu... pick a combo:
     1. aosp_arm-eng
     2. aosp_arm64-eng
     3. aosp_mips-eng
     4. aosp_mips64-eng
     5. aosp_x86-eng
     6. aosp_x86_64-eng
     7. aosp_deb-userdebug
     8. aosp_flo-userdebug
     9. full_fugu-userdebug
     10. aosp_fugu-userdebug
     11. mini_emulator_arm64-userdebug
     12. m_e_arm-userdebug
     13. mini_emulator_mips-userdebug
     14. mini_emulator_x86_64-userdebug
     15. mini_emulator_x86-userdebug
     16. aosp_flounder-userdebug
     17. aosp_hammerhead-userdebug
     18. aosp_hammerhead_fp-userdebug
     19. aosp_shamu-userdebug

Which would you like? [aosp_arm-eng] 

lunch提示你做选择,可以直接回车,可以输入序号,也可以输入序号后的字符串,函数如下所示,

function lunch()
{
    local answer
#如果lunch有参数,例如直接调用lunch aosp_arm-eng和调用lunch 选择1是同样的作用
    if [ "$1" ] ; then
        answer=$1
    else
        print_lunch_menu
#如果直接调用lunch,读取输入,
        echo -n "Which would you like? [aosp_arm-eng] "
        read answer
    fi

    local selection=
    #如果直接回车,默认为aosp_arm-eng
    if [ -z "$answer" ]
    then
        selection=aosp_arm-eng
    #可以直接输入数字
    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
    then
        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
        then
            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
        fi
    #也可以直接输入aosp_arm-eng这种类型的
    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
    then
        selection=$answer
    fi

    if [ -z "$selection" ]
    then
        echo
        echo "Invalid lunch combo: $answer"
        return 1
    fi

    export TARGET_BUILD_APPS=
    #将secection中的-.*结尾的东西替换为空,就是留下前面的
    # aosp_arm-eng 替换后product=aosp_arm
    local product=$(echo -n $selection | sed -e "s/-.*$//")
    # 调用check_product aosp_arm
    #调用check_product检测product
    check_product $product
    #返回必须ok,否则报错
    if [ $? -ne 0 ]
    then
        echo
        echo "** Don't have a product spec for: '$product'"
        echo "** Do you have the right repo manifest?"
        product=
    fi

    #替换掉-前面的字符串为空
    #aosp_arm-eng 替换后variant=eng
    local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
    #用check_variant检查variant
    check_variant $variant
    if [ $? -ne 0 ]
    then
        echo
        echo "** Invalid variant: '$variant'"
        echo "** Must be one of ${VARIANT_CHOICES[@]}"
        variant=
    fi

    #如果product和variant有一个为空,则返回
    if [ -z "$product" -o -z "$variant" ]
    then
        echo
        return 1
    fi

    #这三个全局的变量很重要,TARGET_PRODUCT,TARGET_BUILD_VARIANT,而TARGET_BUILD_TYPE一般为release
    export TARGET_PRODUCT=$product
    export TARGET_BUILD_VARIANT=$variant
    export TARGET_BUILD_TYPE=release

    echo

    set_stuff_for_environment
    printconfig
}

假如我们执行了lunch后,选择了aosp_arm-eng,下面看具体发生了什么。

check_product()

这时候执行的是check_product(aosp_arm),check_product()函数如下,

# 输入参数为aosp_arm 即$1为aosp_arm
function check_product()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree. Try setting TOP." >&2
        return
    fi
        TARGET_PRODUCT=$1 \
        TARGET_BUILD_VARIANT= \
        TARGET_BUILD_TYPE= \
        TARGET_BUILD_APPS= \
        get_build_var TARGET_DEVICE > /dev/null
    # hide successful answers, but allow the errors to show
    # 标准输入输出到/dev/null ,如果要将标准错误,重定向到/dev/bull 可以用 2 > &1
}

实际是调用了get_build_var()函数,输入参数为TARGET_DEVICE,执行前设置了全局变量 TARGET_PRODUCT=aosp_arm

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
    #调用config.mk
    (\cd $T; CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
      command make --no-print-directory -f build/core/config.mk dumpvar-$1)
}

顾名思义,这个函数的功能就是获取某个全局变量的值,例如函数输入参数为TARGET_DEVICE,既是执行下面的命令:

  make --no-print-directory -f build/core/config.mk dumpvar-TARGET_DEVICE

make的目标为dumpvar-TARGET_DEVICE,即make内置变量MAKECMDGOALS为dumpvar-TARGET_DEVICE。
至此,在执行make之前,几个重要的变量和参数如下:

TARGET_PRODUCT=aosp_arm;
CALLED_FROM_SETUP=true;
BUILD_SYSTEM=build/core;
MAKECMDGOALS=dumpvar-TARGET_DEVICE;

在makefile中一般通过include来包含其他的makefile文件,形成一个大的组合makefile,然后再逐条执行每个make语句。我觉得之所以android要提供那么多的单个makefile,是为了实现代码的重用,就跟写软件一样每个模块实现的功能不同,不同模块拼凑到一起可以实现不同的功能。 后续在分析config.mk之前先分析几个需要用到的“工具”makefile,这些makefile一般都是设置一些全局变量,同时提供公共函数为其他部分使用。

你可能感兴趣的:(android编译分析之2—envsetup.sh)