基于nexus6,AOSP 7.1.1源码
本文需要的shell基础
- 为了分析Android编译系统,需知道少量shell基础知识。以下两篇可对比查阅
[shell命令一]条件判断if
[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 # 清除各项的值
}