build/envsetup.sh概要
43201 ワード
build/envsetupについて何編も見ました.shの紹介、メモのまとめ
build/envsetup.sh
コンパイルを開始するたびに最初のコマンドはsource build/envsetupです.sh、sourceコマンドはshellスクリプトコマンドを実行するために使用され、機能は「」に等しい.したがって、この命令も等価である.build/envsetup.sh.ファイルでshは、現在のセッション端末が利用可能なコマンドを宣言し、ここで注意しなければならないのは、現在のセッション端末であり、すなわち、新しい端末を開くたびに、これらのコマンドをもう一度実行しなければならないことを意味する.build/envsetup.shファイルが存在する意味は,いくつかの環境変数とshell関数を設定して後続のコンパイル作業に備えることである.次にenvsetupを分析します.sh.
コマンド--envsetup.shの関数の概要
envsetupをインポートします.shシステムはすべていくつかの命令を出して、先に命令の作用を見ます
よく使うコマンド
コンパイル命令
説明する
mm
現在のパスの下にあるすべてのモジュールをコンパイルしますが、依存は含まれません.
mmm [module_path]
指定したパスの下にあるすべてのモジュールをコンパイルしますが、依存は含まれません.
mma
現在のパスの下にあるすべてのモジュールをコンパイルし、依存を含む
mmma [module_path]
指定したパスの下にあるすべてのモジュールをコンパイルし、依存を含む
make [module_name]
パラメータなしでAndroidコード全体をコンパイルする
cgrep
現在のディレクトリの下にあるすべてのC/C++ファイルの検索操作
jgrep
現在のディレクトリの下にあるすべてのJavaファイルの検索操作
ggrep
現在のディレクトリの下にあるすべてのGradleファイルの検索操作
mangrep [keyword]
現在のディレクトリの下にあるすべてのAndroidManifest.xmlファイル実行検索操作
mgrep [keyword]
現在のディレクトリの下にあるすべてのAndroid.mkファイル実行検索操作
sepgrep [keyword]
すべてのsepolicyファイルで検索操作を実行
resgrep [keyword]
現在のディレクトリの下にあるすべてのローカルres/*xmlファイル実行検索操作
sgrep [keyword]
現在のディレクトリの下で(c
croot
Androidルートディレクトリに切り替え
cproj
プロジェクトのルートディレクトリに切り替え
godir [filename]
ファイルを含むディレクトリに移動
hmm
すべての命令help情報をクエリー
Tips:Androidソースコードは非常に膨大で、grepを直接採用してコードを検索するのは、方法が不器用で時間を浪費するだけでなく、無意味な混同結果を多く検索します.具体的なニーズに応じて、適切なコード検索命令を選択し、コード検索時間を節約し、検索結果の精度を高め、目標コードの位置決めを便利にすることができる.godir[filename]は最初の実行速度が遅く、その後findコマンドよりも動作効率が高い(詳細は後述)
source build/envsetup.sh実行フロー
envsetup.shは多くの関数を定義し、それ以外にも他の操作を実行し、以下は関数部分を除去するコードである.
VARIANT_CHOICES=(user userdebug eng)# 3 ,
# Clear this variable. It will be built up again when the vendorsetup.sh
# files are included at the end of this file.
#LUNCH_MENU_CHOICES prodcut ,
# source build/envsetup.sh LUNCH_MENU_CHOICES
# include vendor/cm/vendorsetup.sh LUNCH_MENU_CHOICES ,
#
unset LUNCH_MENU_CHOICES
# LUNCH_MENU_CHOICES , , , LUNCH_MENU_CHOICES
function add_lunch_combo()
{
local new_combo=$1
local c
for c in ${LUNCH_MENU_CHOICES[@]} ; do
if [ "$new_combo" = "$c" ] ; then
return
fi
done
LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo)
}
# 6
# add the default one here
add_lunch_combo aosp_arm-eng
add_lunch_combo aosp_arm64-eng
add_lunch_combo aosp_mips-eng
add_lunch_combo aosp_mips64-eng
add_lunch_combo aosp_x86-eng
add_lunch_combo aosp_x86_64-eng
# lunch _lunch , _lunch lunch
complete -F _lunch lunch
#shell , bash, shell WARNING
if [ "x$SHELL" != "x/bin/bash" ]; then
case `ps -o command -p $$` in
*bash*)
;;
*)
echo "WARNING: Only bash is supported, use of other shell would lead to erroneous results"
;;
esac
fi
# Execute the contents of any vendorsetup.sh files we can find.
#source vendor device 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`
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
fi
# Keep us from trying to run in bash that's too old.
if [ ${BASH_VERSINFO[0]} -lt 3 ]; then
return
fi
dir="sdk/bash_completion"
if [ -d ${dir} ]; then
for f in `/bin/ls ${dir}/[a-z]*.bash 2> /dev/null`; do
echo "including $f"
. $f
done
fi
}
BASHのバージョンが空または3未満の場合は、android/sdk/bash_を印刷します.completion/ディレクトリの下の.bashの最後のすべてのファイルを実行します.bashファイル、Linux端末下adbコマンドの補完を実現
これで、source build/envsetup.shの過程は分析が終わった.
build/envsetup.sh常用関数の紹介
lunchプロセス
ソースフローの直後にlunch操作が実行する、lunch操作はbuild/envsetupが実行される.shスクリプトのlunch関数は、コードを直接見ます.
function lunch()
{
local answer
# lunch , answer ;
# lunch , print_lunch_menu , answer 。
if [ "$1" ] ; then
answer=$1
else
print_lunch_menu # LUNCH_MENU_CHOICES
echo -n "Which would you like? [aosp_arm-eng] "
read answer
fi
local selection=
# answer , selection aosp_arm-eng;
# answer , answer LUNCH_MENU_CHOICES ;
# anwser , ”-” , ”-” ”-”, , selection。
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
elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")
then
selection=$answer
fi
# selection ,
if [ -z "$selection" ]
then
echo
echo "Invalid lunch combo: $answer"
return 1
fi
export TARGET_BUILD_APPS=
# selection “-” product,
local product=$(echo -n $selection | sed -e "s/-.*$//")
# product , make
check_product $product
if [ $? -ne 0 ]
then
echo
echo "** Don't have a product spec for: '$product'"
echo "** Do you have the right repo manifest?"
product=
fi
# selection “-” variant, check_variant variant 。check_variant , source "user userdebug eng" VARIANT_CHOICES , variant , 0, 1。
local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
check_variant $variant
if [ $? -ne 0 ]
then
echo
echo "** Invalid variant: '$variant'"
echo "** Must be one of ${VARIANT_CHOICES[@]}"
variant=
fi
if [ -z "$product" -o -z "$variant" ]
then
echo
return 1
fi
# shell
export TARGET_PRODUCT=$product
export TARGET_BUILD_VARIANT=$variant
export TARGET_BUILD_TYPE=release
echo
# PROMPT_COMMAND,ANDROID_BUILD_PATHS,JAVA_HOME BUILD_ENV_SEQUENCE_NUMBER
set_stuff_for_environment
#
printconfig
}
Tips:set_stuff_for_Environmentの中のset_java_home関数は、実際の状況に応じてjavaパスなどを変更することができ、異なるandroidバージョンのコンパイルやjavaバージョンの手動切り替えを避けることができます.
_lunch関数
lunchコマンドの補完を実現するには:
まずlunch関数を定義しました
そして定義しましたlunch関数
completeコマンドの使用
# Tab completion for lunch.
function _lunch()
{
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
COMPREPLY=( $(compgen -W "${LUNCH_MENU_CHOICES[*]}" -- ${cur}) )
return 0
}
++complete -F _lunch lunch++は、上記のコードの中で最も重要な行です.
bashがlunchという言葉に出会ったとき、_が呼び出されます.lunch関数.この関数には、補完するコマンド名、現在のカーソルがある語、現在のカーソルがある語の前の語の3つのパラメータが入力されます.補完結果はCOMPREPLY変数に格納し、bash取得を待つ必要があります.
gettop
function gettop
{
local TOPFILE=build/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
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
}
-n変数が存在するか
-a論理と
-fファイルが存在するか
PWDカレントディレクトリの印刷
この関数は主にAndroidソースのルートディレクトリを取得し、ルートディレクトリの下のbuild/core/envsetupに基づいています.mkファイルで判断しました.
注意:この関数を呼び出すときに要求があります.ソースコードのルートディレクトリのサブディレクトリで、ルートディレクトリの上位ディレクトリで呼び出すと失敗します.この関数はcdを呼び出すためです.コマンドを実行し、ファイルbuild/core/envsetup.mkはソースコードルートディレクトリを判断する.
hmm
function hmm() {
cat <<EOF
Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
- lunch: lunch -
- tapas: tapas [ ...] [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:
EOF
T=$(gettop)
local A
A=""
for i in `cat $T/build/envsetup.sh | sed -n "/^[ \t]*function /s/function \([a-z_]*\).*/\1/p" | sort | uniq`; do
A="$A $i"
done
echo $A
}
ヘルプ関数、cat$T/build/envsetup.sh | sed -n “/^[\t]function/s/function ([a-z_]).*/\1/p"|sort|uniqというスクリプトは主にenvsetupを取得する.shの中のfunctionで始まる関数は、関数名がアルファベットで、関数名を印刷します.sed-n"/^[t]*function/p"は、functionで始まる行s/function([a-z_])./を印刷する1この部分は関数名を抽出してsortソートuniqを重み付けします
mm
function mm()
{
local T=$(gettop)
local DRV=$(getdriver $T)
# 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
$DRV make $@
else
# Find the closest Android.mk file.
local M=$(findmakefile)
local MODULES=
local GET_INSTALL_PATH=
local ARGS=
# 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."
return 1
elif [ ! "$M" ]; then
echo "Couldn't locate a makefile from the current directory."
return 1
else
for ARG in $@; do
case $ARG in
GET-INSTALL-PATH) GET_INSTALL_PATH=$ARG;;
esac
done
if [ -n "$GET_INSTALL_PATH" ]; then
MODULES=
ARGS=GET-INSTALL-PATH
else
MODULES=all_modules
ARGS=$@
fi
ONE_SHOT_MAKEFILE=$M $DRV make -C $T -f build/core/main.mk $MODULES $ARGS
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を呼び出す方法を知るだけでいい
mmm
mmmコマンドは、指定したディレクトリの下からすべてのモジュールのコンパイルを開始します.
function mmm()
{
local T=$(gettop)
local DRV=$(getdriver $T)
if [ "$T" ]; then
local MAKEFILE=
local MODULES=
local ARGS=
local DIR TO_CHOP
local GET_INSTALL_PATH=
local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^-.*$/')
local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^[^-].*$/')
for DIR in $DIRS ; do
MODULES=`echo $DIR | sed -n -e 's/.*:\(.*$\)/\1/p' | sed 's/,/ /'`
if [ "$MODULES" = "" ]; then
MODULES=all_modules
fi
DIR=`echo $DIR | sed -e 's/:.*//' -e 's:/$::'`
if [ -f $DIR/Android.mk ]; then
local TO_CHOP=`(\cd -P -- $T && pwd -P) | wc -c | tr -d ' '`
local TO_CHOP=`expr $TO_CHOP + 1`
local START=`PWD= /bin/pwd`
local 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
case $DIR in
showcommands | snod | dist | incrementaljavac | *=*) ARGS="$ARGS $DIR";;
GET-INSTALL-PATH) GET_INSTALL_PATH=$DIR;;
*) echo "No Android.mk in $DIR."; return 1;;
esac
fi
done
if [ -n "$GET_INSTALL_PATH" ]; then
ARGS=$GET_INSTALL_PATH
MODULES=
fi
ONE_SHOT_MAKEFILE="$MAKEFILE" $DRV make -C $T -f build/core/main.mk $DASH_ARGS $MODULES $ARGS
else
echo "Couldn't locate the top of the tree. Try setting TOP."
return 1
fi
}
まずT=$(gettop)ソースコードルートディレクトリを取得し、
local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^-.*$/')
mmmの後のパラメータに基づいて、-で始まる文字列を取得します.たとえば、mmm-B frameworks/baseではDASH_ARGS = -B
local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^[^-].*$/')
mmmの後のパラメータに基づいて、-で始まる文字列ではなく、スペースで区切られた文字列を取得します.例:DIRS=frameworks/base/
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/androidであれば、MFILE="
if [ "$MFILE" = "" ] ; then
MFILE=$DIR/Android.mk
else
MFILE=$MFILE/frameworks/base/Android.mk
fi
ここでは、現在のディレクトリがソースディレクトリであるか否かを判断する、もしそうであればMFILEは空であるため、MFILE=frameworks/base/Androidとなる.mk
それ以外の場合:MFILE=$MFILE/frameworks/base/Android.mk
要するに、現在のディレクトリの前のソースコードのルートディレクトリを行って、それから後ろのmmm-B**パラメータの部分の相対的なディレクトリを加えて、最後にAndroidを加えます.mkは最後のAndroidだmkファイルの相対パス.
ONE_SHOT_MAKEFILE=”MAKEFILE” make -C T T DASH_ARGS all_modules $ARGS
make-C/home/admin/android-Ball_に相当modules ONE_SHOT_MAKEFILE=frameworks/base/Android.mk
godir
function godir () {
#
if [[ -z "$1" ]]; then
echo "Usage: godir "
return
fi
T=$(gettop)
# OUT_DIR OUT_DIR , FILELIST
if [ ! "$OUT_DIR" = "" ]; then
mkdir -p $OUT_DIR
FILELIST=$OUT_DIR/filelist
else
FILELIST=$T/filelist
fi
# filelist ,
if [[ ! -f $FILELIST ]]; then
echo -n "Creating index..."
# find "-type f"( out .repo ), $FILELIST
# out .repo :
# - "-wholename ./out -prune"
# - "-wholename ./.repo -prune"
# find "-wholename pattern" , "-path pattern" , find
# filelist out .repo
(\cd $T; find . -wholename ./out -prune -o -wholename ./.repo -prune -o -type f > $FILELIST)
echo " Done"
echo ""
fi
local lines
# godir , filelist , sed lines
# "sed -e 's/\/[^/]*$//'"
lines=($(\grep "$1" $FILELIST | sed -e 's/\/[^/]*$//' | sort | uniq))
# lines , filelist grep sed ,
if [[ ${#lines[@]} = 0 ]]; then
echo "Not found"
return
fi
local pathname
local choice
# lines 1 ,
if [[ ${#lines[@]} > 1 ]]; then
while [[ -z "$pathname" ]]; do
# 1
local index=1
local line
for line in ${lines[@]}; do
# :
printf "%6s %s
" "[$index]" $line
#
index=$(($index + 1))
done
echo
echo -n "Select one: "
unset choice
#
read choice
if [[ $choice -gt ${#lines[@]} || $choice -lt 1 ]]; then
echo "Invalid choice"
continue
fi
#
pathname=${lines[$(($choice-1))]}
done
else
# , pathname
pathname=${lines[0]}
fi
\cd $T/$pathname
}
godirは、コンパイルパスの下でマッチングモードのディレクトリを検索し、このディレクトリにジャンプします.frameworks/base/core/res/res/res/valuesのようなファイルのパスをすばやく検索するために使用できます.overlayが直接godir frameworks/base/core/res/res/values/このパスを含むすべてのフォルダを検索し、上書きする可能性のあるすべての場所を検索します.
sgrep
case `uname -s` in
Darwin)
function sgrep()
{
find -E . -name .repo -prune -o -name .git -prune -o -type f -iregex '.*\.(c|h|cc|cpp|S|java|xml|sh|mk|aidl)' -print0 | xargs -0 grep --color -n "$@"
}
;;
*)
function sgrep()
{
# .repo, .git
# (c|h|cc|cpp|S|java|xml|sh|mk|aidl|vts) grep
find . -name .repo -prune -o -name .git -prune -o -type f -iregex '.*\.\(c\|h\|cc\|cpp\|S\|java\|xml\|sh\|mk\|aidl\)' -print0 | xargs -0 grep --color -n "$@"
}
;;
esac
ここでなぜoutディレクトリを行かなかったのか理解できない
他のコード検索原理は似ていますが、一つ一つ列挙しません.