欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2. envsetup.sh脚本(Android10)

程序员文章站 2022-07-02 15:58:10
...

建议先阅读:

envsetup.sh分析(旧版本Android)

envsetup.sh分析二(旧版本Android)

新版本的envsetup.sh脚本

1. add_lunch_combo函数被废弃

所谓的lunch-combo指的是大家每次lunch时,打印出来的,可供选择的lunch选项。

旧版本的Android,使用此函数来添加lunch-combo

新版本的Android,执行此函数时会提醒add_lunch_combo is obsolete,告知此命令已经废弃。

并提醒开发者Use COMMON_LUNCH_CHOICES in your AndroidProducts.mk instead.

采用COMMON_LUNCH_CHOICES变量,在AndroidProducts.mk文件中声明lunch-combo

function add_lunch_combo()
{
    if [ -n "$ZSH_VERSION" ]; then
        echo -n "${funcfiletrace[1]}: "
    else
        echo -n "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: "
    fi
    echo "add_lunch_combo is obsolete. Use COMMON_LUNCH_CHOICES in your AndroidProducts.mk instead."
}

2. print_lunch_menu函数

打印出全部的lunch-combo

具体是通过调用get_build_var函数来获得

function print_lunch_menu()
{
    local uname=$(uname)
    echo
    echo "You're building on" $uname
    echo
    echo "Lunch menu... pick a combo:"

    local i=1
    local choice
    for choice in $(TARGET_BUILD_APPS= get_build_var COMMON_LUNCH_CHOICES)
    do
        echo "     $i. $choice"
        i=$(($i+1))
    done

    echo
}

2. get_build_var函数

此函数通过调用build/soong/soong_ui.bash --dumpvar-mode $1来获取build variable编译变量

关于build/soong/soong_ui.bash的分析,见soong_ui.bash脚本

函数代码如下:

# Get the exact value of a build variable.
function get_build_var()
{
    if [ "$BUILD_VAR_CACHE_READY" = "true" ]
    then
        eval "echo \"\${var_cache_$1}\""
    return
    fi

    local T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
    (\cd $T; build/soong/soong_ui.bash --dumpvar-mode $1)
}

2. _lunch函数

_lunch函数是lunch命令执行时的语法补全函数。

即,当执行lunch命令时,按下tab键一次,则执行_lunch函数一次

_lunch函数提供给我们可供选择的lunch选项(显示出匹配的lunch-combo

源码如下:

unset COMMON_LUNCH_CHOICES_CACHE
# Tab completion for lunch.
function _lunch()
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    if [ -z "$COMMON_LUNCH_CHOICES_CACHE" ]; then
        COMMON_LUNCH_CHOICES_CACHE=$(TARGET_BUILD_APPS= get_build_var COMMON_LUNCH_CHOICES)
    fi

    COMPREPLY=( $(compgen -W "${COMMON_LUNCH_CHOICES_CACHE}" -- ${cur}) )
    return 0
}

可以看到这个函数和print_lunch_menu一样都是通过get_build_var函数来获取编译变量COMMON_LUNCH_CHOICES

2. lunch函数

源代码如下,分析见注释:

function lunch()
{
    # 定义局部变量`answer`来存放用户通过`lunch`命令传进来的参数(即`lunch-combo`,可以是字符串或数字)
    local answer

    if [ "$1" ] ; then
        answer=$1
    else # 如果用户没有没有传进来任何值,则打印出`lunch-combo`列表,提示用户输入
        print_lunch_menu
        echo -n "Which would you like? [aosp_arm-eng] "
        read answer
    fi

    # 定义局部变量`selection`,用来存放`lunch-combo`字符串
    local selection=

    if [ -z "$answer" ] # 如果`answer`为空,则把`selection`设置为默认的`aosp_arm-eng`
    then
        selection=aosp_arm-eng
    elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
    then # 如果`answer`是数字,则把`selection`设置为对应的`lunch-combo`字符串
        local choices=($(TARGET_BUILD_APPS= get_build_var COMMON_LUNCH_CHOICES))
        if [ $answer -le ${#choices[@]} ]
        then
            # array in zsh starts from 1 instead of 0.
            if [ -n "$ZSH_VERSION" ]
            then
                selection=${choices[$(($answer))]}
            else
                selection=${choices[$(($answer-1))]}
            fi
        fi
    else # 如果`answer`是字符串,则把`selection`赋值为`answer`
        selection=$answer
    fi

    export TARGET_BUILD_APPS=

    local product variant_and_version variant version

    product=${selection%%-*} # Trim everything after first dash
    variant_and_version=${selection#*-} # Trim everything up to first dash
    if [ "$variant_and_version" != "$selection" ]; then
        variant=${variant_and_version%%-*}
        if [ "$variant" != "$variant_and_version" ]; then
            version=${variant_and_version#*-}
        fi
    fi

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

    TARGET_PRODUCT=$product \
    TARGET_BUILD_VARIANT=$variant \
    TARGET_PLATFORM_VERSION=$version \
    build_build_var_cache
    if [ $? -ne 0 ]
    then
        return 1
    fi

    export TARGET_PRODUCT=$(get_build_var TARGET_PRODUCT)
    export TARGET_BUILD_VARIANT=$(get_build_var TARGET_BUILD_VARIANT)
    if [ -n "$version" ]; then
      export TARGET_PLATFORM_VERSION=$(get_build_var TARGET_PLATFORM_VERSION)
    else
      unset TARGET_PLATFORM_VERSION
    fi
    export TARGET_BUILD_TYPE=release

    echo

    set_stuff_for_environment
    printconfig
    destroy_build_var_cache
}

3. addcompletions函数

4. make函数

5. m函数

6. mm函数

7. mmm函数

8. gettop函数

gettop函数通过查找TOPFILEbuild/make/core/envsetup.mk文件,来判断当前目录是否为Android源码顶层目录

如果当前目录不是顶层目录,则循环cd往上一级目录走,直到找到为止(或者走到根目录,然后报错)。

代码如下:

function gettop
{
    local TOPFILE=build/make/core/envsetup.mk
    if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then
        # The following circumlocution ensures we remove symlinks from TOP.
        (cd $TOP; PWD= /bin/pwd)
    else
        if [ -f $TOPFILE ] ; then
            # The following circumlocution (repeated below as well) ensures
            # that we record the true directory name and not one that is
            # faked up with symlink names.
            PWD= /bin/pwd
        else
            local HERE=$PWD
            local T=
            while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
                \cd ..
                T=`PWD= /bin/pwd -P`
            done
            \cd $HERE
            if [ -f "$T/$TOPFILE" ]; then
                echo $T
            fi
        fi
    fi
}

9. croot函数

跳转到Android源码顶层目录

通过gettop函数获得顶层目录路径

function croot()
{
    local T=$(gettop)
    if [ "$T" ]; then
        if [ "$1" ]; then
            \cd $(gettop)/$1
        else
            \cd $(gettop)
        fi
    else
        echo "Couldn't locate the top of the tree.  Try setting TOP."
    fi
}

10. xgrep类函数

这类函数,其实就是把findgrep命令封装了一下,加上了一些参数,搜索起来针对性更强、效率更高。

函数名和对应的功能,如下:

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.
mgrep:      Greps on all local Makefiles files.
sepgrep:    Greps on all local sepolicy files.
sgrep:      Greps on all local source files.

这里以cgrep为例子

function cgrep()
{
    find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( -name '*.c' -o -name '*.cc' -o -name '*.cpp' -o -name '*.h' -o -name '*.hpp' \) \
        -exec grep --color -n "[email protected]" {} +
}

find命令

  • -name参数指定搜索的文件名(例:find -name "MyCProgram.c" \在根目录下查找MyCProgram.c文件)
  • -iname参数指定搜索的文件名且忽略大小写(例:find -iname "MyCProgram.c" \)
  • -a
  • -o
  • -not!
  • -prune就像一个判断语句,当发现-prune前面的表达式math时,执行到-prune之后就会输出一个结果1(类似于$?值为1)与-o配合就是如果满足前面的条件则不执行后面的参数
  • -type指定搜索的文件类型(例:s指socket,d指目录,f指文件)
  • \( \)括号内部的参数是对括号前面参数的补充(我理解为子参数)
  • -exec指定查找结束后,要执行的命令。{}将会被当前文件名取代(例:find -iname "MyCProgram.c" -exec md5sum {} \找到该文件后,用md5sum命令计算该文件的MD5验证和)

grep命令

  • --color带色彩显示搜索结果
  • -n显示行号

"[email protected]"是从命令行传进来的位置参数(即用户在shell中输入的跟在cgrep后面的参数)

大家弄明白了这些参数,是不是就理解cgrep的逻辑了。

以此类推:

  • ggrep就是搜索.gradle文件
  • jgrep就是搜索.java文件
  • resgrep就是搜索.xml文件
  • mangrep就是搜索AndroidManifest.xml文件
  • sepgrep就是搜索sepolicy目录下的文件
  • rcgrep就是搜索.rc文件
  • mgrep就是搜索makefile文件
  • treegrep就是搜索c|h|cpp|hpp|S|java|xml文件

详细的代码分析,这里就不赘述了。

11.hmm函数

hmm函数或者是hmm命令,用来打印help信息。

逻辑很简单,分为两点:

  1. cat命令打印help信息

  2. 遍历envsetup.sh查找函数并打印出来

第一点没啥说的,第二点的逻辑如下:

for i in `cat $T/build/envsetup.sh | sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p" | sort | uniq`; do
  A="$A $i"
done

for循环中的逻辑很好理解A="$A $i",循环中不停的把变量i的值追加在变量A后面。

for循环每次迭代,从cat $T/build/envsetup.sh | sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p" | sort | uniq中获取值

我们可以将这个长指令,通过管道分割为一个个子命令:

cat $T/build/envsetup.sh cat envsetup.sh脚本

sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p" 搜索envsetup.sh脚本中的包含^[[:blank:]]*function的行,并将其function后面的关键字(即函数名)提取出来

sort 对函数名进行排序

uniq 去除重复函数(uniq于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用)

源码如下:

function hmm() {
cat <<EOF

Run "m help" for help with the build system itself.

Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- lunch:      lunch <product_name>-<build_variant>
              Selects <product_name> as the product to build, and <build_variant> as the variant to
              build, and stores those selections in the environment to be read by subsequent
              invocations of 'm' etc.
- tapas:      tapas [<App1> <App2> ...] [arm|x86|mips|arm64|x86_64|mips64] [eng|userdebug|user]
- croot:      Changes directory to the top of the tree, or a subdirectory thereof.
- 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.
- provision:  Flash device with all required partitions. Options will be passed on to fastboot.
- 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.
- mgrep:      Greps on all local Makefiles files.
- sepgrep:    Greps on all local sepolicy files.
- sgrep:      Greps on all local source files.
- godir:      Go to the directory containing a file.
- allmod:     List all modules.
- gomod:      Go to the directory containing a module.
- pathmod:    Get the directory containing a module.
- refreshmod: Refresh list of modules for allmod/gomod.

Environment 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.
- ANDROID_QUIET_BUILD: set to 'true' to display only the essential messages.

Look at the source to view more functions. The complete list is:
EOF
    local T=$(gettop)
    local A=""
    local i
    for i in `cat $T/build/envsetup.sh | sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p" | sort | uniq`; do
      A="$A $i"
    done
    echo $A
}
相关标签: Android底层