Android 开发之envsetup.sh
1,基本概述
Android源码下载之后一般编译之前都需要source环境变量build/envsetup.sh。脚本主要是一些基本函数,和配置编译工具和路径等。
export PATH=$PWD/bootable/bootloader/uboot-imx/tools:$PATH
export ARCH=arm
export CROSS_COMPILE=$PWD/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-
然后就是查找一些vendorsetup.sh文件并执行:
for f in `/bin/ls vendor/*/vendorsetup.sh vendor/*/*/vendorsetup.sh device/*/*/vendorsetup.sh 2 >/dev/null`
do
echo "including $f"
. $f
done
unset f
2,函数介绍
下面主要介绍5个常用函数:
1)gettop
function gettop { local TOPFILE=build/core/envsetup.mk if [ -n "$TOP" -a -f "$TOP/TOPFILE" ] ; then echo $TOP else if [ -f $TOPFILE ] ; then PWD= /bin/pwd else local HERE=$PWD T= while [ \( ! (\ -f $TOPFILE \) \) -a \( $PWD != "/" \) ] ; do cd .. > /dev/null T=`PWD= /bin/pwd` done cd $HERE > /dev/null if [ -f "$T/TOPFILE" ] ; then echo $T fi fi fi }
这个函数主要是获取Android源码的根目录,根据根目录下的build/core/envsetup.mk文件来判断的。
注意:调用这个函数的时候有个要求:就是你必须在源码根目录的子目录中,如果你处在根目录的上级目录则调用失败,因为这个函数是通过不停的调用cd ..命令,然后通过文件build/core/envsetup.mk来判断源码根目录的。
2)help
function help() { cat <<EOF Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment: - 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. - mmm: Builds all of the modules in the supplied directories. - cgrep: Greps on all local C/C++ files. - jgrep: Greps on all local Java files. - resgrep: Greps on all local res/*.xml files. - godir: Go to the directory containing a file. Look at the source to view more functions. The complete list is: EOF T=$(gettop) local A A="" for i in `cat $T/build/envsetup.sh | sed -n "/^function /s/function \([a-z_]*\).*/\1/p" | sort`; do A="$A $i" done echo $A }
帮助函数,cat $T/build/envsetup.sh | sed -n "/^function /s/function \([a-z_]*\).*/\1/p" | sort 这句脚本主要是获取envsetup.sh里面的以function开头的函数,并将函数名打印出来。
3)m
m函数就是从源码根目录下开始编译。
function m() { T=$(gettop) if [ "$T" ]; then make -C $T $@ else echo "Couldn't locate the top of the tree. Try setting TOP." fi }
其中make -C $T $@ 就是在源码根目录下执行:make 后面的$@就是执行m命令时后面携带的参数。
注意:bash中$@和$*都表示参数,但是$*表示的是所有参数用一个双引号""括起来,而$@表示多个参数分别用""括起来。
$*为"1 2 3"(一起被引号包住)
$@为"1" "2" "3"(分别被包住)
4)mm
mm函数是编译当前目录下的所有模块。
function mm() { # If we're sitting in the root of the build tree, just do a # normal make. if [ -f build/core/envsetup.mk -a -f Makefile ]; then make $@ else # Find the closest Android.mk file. T=$(gettop) local M=$(findmakefile) # Remove the path to top as the makefilepath needs to be relative local M=`echo $M|sed 's:'$T'/::'` if [ ! "$T" ]; then echo "Couldn't locate the top of the tree. Try setting TOP." elif [ ! "$M" ]; then echo "Couldn't locate a makefile from the current directory." else ONE_SHOT_MAKEFILE=$M make -C $T all_modules $@ fi fi }
如果当前处在源码根目录下,且存在Makefile文件,直接执行make $@命令。
如果不是在源码根目录下:循环调用cd .. 调用findmakefile函数查找Android.mk文件,直到根目录,将Android.mk文件的绝对路径返回给M.
如找到了:M=/home/admin/android/frameworks/base/Android.mk,调用: local M=`echo $M|sed 's}'$T'/}}'`这句就是将源码根目录/home/admin/android/去掉,取得相对目录后,M=frameworks/base/Android.mk
最后执行:ONE_SHOT_MAKEFILE=frameworks/base/android.mk make -C /home/admin/android all_modules
相当于make -C /home/admin/android all_modules ONE_SHOT_MAKEFILE=frameworks/base/android.mk
接下来会调用到:源码根目录下的Makefile中,我们发现内容是include build/core/main.mk,即走到了build/core/main.mk文件中。后面就设计到Makefile的问题,我们后面会分析。现在只需要知道mm命令是怎么调用makefile里面去就行。
5)mmm
mmm 命令就是从指定目录下开始编译所有模块
function mmm() { T=$(gettop) if [ "$T" ]; then local MAKEFILE= local ARGS= local DIR TO_CHOP local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^-.*$/') local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^[^-].*$/') for DIR in $DIRS ; do DIR=`echo $DIR | sed -e 's:/$::'` if [ -f $DIR/Android.mk ]; then TO_CHOP=`(cd -P -- $T && pwd -P) | wc -c | tr -d ' '` TO_CHOP=`expr $TO_CHOP + 1` START=`PWD= /bin/pwd` MFILE=`echo $START | cut -c${TO_CHOP}-` if [ "$MFILE" = "" ] ; then MFILE=$DIR/Android.mk else MFILE=$MFILE/$DIR/Android.mk fi MAKEFILE="$MAKEFILE $MFILE" else if [ "$DIR" = snod ]; then ARGS="$ARGS snod" elif [ "$DIR" = showcommands ]; then ARGS="$ARGS showcommands" elif [ "$DIR" = dist ]; then ARGS="$ARGS dist" elif [ "$DIR" = incrementaljavac ]; then ARGS="$ARGS incrementaljavac" else echo "No Android.mk in $DIR." return 1 fi fi done ONE_SHOT_MAKEFILE="$MAKEFILE" make -C $T $DASH_ARGS all_modules $ARGS else echo "Couldn't locate the top of the tree. Try setting TOP." fi }
最后mmm函数:首先T=$(gettop)获取源码根目录,
local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^-.*$/') 根据mmm后面的参数获取以空格隔开,以-开头的字符串
如:mmm -B frameworks/ 则DASH_ARGS = -B
local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^[^-].*$/') 表示根据mmm后面参数获取以空格隔开,不以-开头的字符串。
如:DIRS=frameworks/base/
for DIR in $DIRS ; do
DIR=`echo $DIR | sed -e 's:/$::'` 去掉DIR结尾的/,DIR=frameworks/base
if [ -f $DIR/Android.mk ] ;then
TO_CHOP=`(cd -P -- $T && pwd -P) | wc -c | tr -d ' '`
上面这句命令是:跳到源码根目录,pwd -P打印出来,获取到字符串长度如:/home/admin/androids TO_CHOP就是20
TO_CHOP=`expr $TO_CHOP + 1`
START=`PWD= /bin/pwd`
MFILE=`echo $START | cut -c${TO_CHOP}-`
这句话命令是:获取当前目录字符串,去掉前面21个字符,如:当前目录为/home/admin/androids,则MFILE=""
if [ "$MFILE" = "" ] ; then
这里进行判断当前目录是否就是源码目录,如果是的话,MFILE为空,所以MFILe=frameworks/base/Android.mk
MFILE=$DIR/Android.mk
else
否则:MFILE=$MFILE/frameworks/base/Android.mk
总之:就是把当前目录的前面源码根目录去了,然后加上后面mmm -B **参数部分相对的目录,最后加上Android.mk就是,最后Android.mk文件的相对路径。
MFILE=$MFILE/$DIR/Android.mk
fi
MAKEFILE=$MAKEFILE $MFILE
else
done
ONE_SHOT_MAKEFILE="MAKEFILE" make -C $T $DASH_ARGS all_modules $ARGS
相当于:make -C /home/admin/android -B all_modules ONE_SHOT_MAKEFILE=frameworks/base/Android.mk