一般android编译时,会先执行下面的命令,
source build/envsetup.sh
source作用就是在当前bash环境下读取envsetup.sh,然后执行其中的命令。而envsetup.sh其实包含了很多的shell函数和一些命令,那么具体发生了什么?
$ 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
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(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 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一般都是设置一些全局变量,同时提供公共函数为其他部分使用。