2. envsetup.sh脚本(Android10)
文章目录
建议先阅读:
新版本的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函数通过查找TOPFILE
即build/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类函数
这类函数,其实就是把find
和grep
命令封装了一下,加上了一些参数,搜索起来针对性更强、效率更高。
函数名和对应的功能,如下:
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信息。
逻辑很简单,分为两点:
-
cat命令打印help信息
-
遍历
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
}