当前位置:   article > 正文

android编译分析之2—envsetup.sh_source build/envsetup.sh 无法运行

source build/envsetup.sh 无法运行


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

source build/envsetup.sh
  • 1

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
注:从提示log,首先说明只支持bash,其他的shell都会导致编译错误。初次装完ubuntu后,默认的shell是dash,需要修改。此外还including了很多的sh,都是一些函数或者命令。
  • 1

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
注:有几个命令非常有用:
1.croot,切到项目根目录下,android目录层次实在是太多了,不需要../..
2.*grep,在各种类型的文件中执行grep,快速
3.godir,cd到包含某个文件的文件夹下
  • 1
  • 2
  • 3
  • 4

上面注释的都很清楚,平时用的最多的是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] 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

假如我们执行了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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

实际是调用了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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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

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

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一般都是设置一些全局变量,同时提供公共函数为其他部分使用。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/327281
推荐阅读
相关标签
  

闽ICP备14008679号