赞
踩
源码基于:Android R
今天在编译项目的时候,想看看 envsetup.sh 中变化了些什么,才想起来编译专栏中好像没有详解该脚本,索性现在空余时间比较多,整理一下方便以后查看。
Android envsetup.sh 为编译前的准备工作,提供 lunch、m、mm等命令函数定义,是整个Android 编译系统的第一步。该文件一共1700 行左右,简单总结出两件事情:
本文会结合代码对 envsetup.sh 进行详细的剖析,由于函数比较多,本文会进行长期地补充和维护。
当运行该脚本的时候终端提示:
- including vendor/xxx/common/vendorsetup.sh
- clang compdb: ln -s out/soong/development/ide/compdb/compile_commands.json $ANDROID_BUILD_TOP
- including vendor/qqq/opensource/core-utils/vendorsetup.sh
- including vendor/qqq/proprietary/common/vendorsetup.sh
那执行该脚本的时候到底做了些什么呢?
- build/envsetup.sh
-
- validate_current_shell
- source_vendorsetup
- addcompletions
执行该程序共运行三个函数,分别是 validate_current_shell、source_vendorsetup、addcompletions。下面来看下这三个函数做了些什么事情?
- function validate_current_shell() {
- local current_sh="$(ps -o command -p $$)"
- case "$current_sh" in
- *bash*)
- function check_type() { type -t "$1"; }
- ;;
- *zsh*)
- function check_type() { type "$1"; }
- enable_zsh_completion ;;
- *)
- echo -e "WARNING: Only bash and zsh are supported.\nUse of other shell would lead to erroneous results."
- ;;
- esac
- }
主要是测试下当前的shell 环境是否可用,对于 zsh 环境需要特殊处理,其他环境会其实warning。
- function source_vendorsetup() {
- unset VENDOR_PYTHONPATH
- allowed=
- for f in $(find -L device vendor product -maxdepth 4 -name 'allowed-vendorsetup_sh-files' 2>/dev/null | sort); do
- if [ -n "$allowed" ]; then
- echo "More than one 'allowed_vendorsetup_sh-files' file found, not including any vendorsetup.sh files:"
- echo " $allowed"
- echo " $f"
- return
- fi
- allowed="$f"
- done
-
- allowed_files=
- [ -n "$allowed" ] && allowed_files=$(cat "$allowed")
- for dir in device vendor product; do
- for f in $(test -d $dir && \
- find -L $dir -maxdepth 4 -name 'vendorsetup.sh' 2>/dev/null | sort); do
-
- if [[ -z "$allowed" || "$allowed_files" =~ $f ]]; then
- echo "including $f"; . "$f"
- else
- echo "ignoring $f, not in $allowed"
- fi
- done
- done
- }
例如上面运行 envsetup.sh 时打印 including vendor/xxx/common/vendorsetup.sh,就是在 vendor/xxx/common 目录下找到了 vendorsetup.sh,运行的时候会配置一些环境变量,并打印:
clang compdb: ln -s out/soong/development/ide/compdb/compile_commands.json
- function addcompletions()
- {
- local T dir f
-
- #避免不在 bash 或 zsh 的环境中运行
- #需要提前指定这两个环境变量,如果没有指定,该函数return
- if [ -z "$BASH_VERSION" -a -z "$ZSH_VERSION" ]; then
- return
- fi
-
- #避免运行在太久的版本中,这里是小于 3 的版本
- if [ -n "$BASH_VERSION" -a ${BASH_VERSINFO[0]} -lt 3 ]; then
- return
- fi
-
- local completion_files=(
- system/core/adb/adb.bash
- system/core/fastboot/fastboot.bash
- tools/asuite/asuite.sh
- )
-
- #确认上面几个脚本是否存在,通过should_add_completion确认该脚本是否在白名单中
- for f in ${completion_files[*]}; do
- if [ -f "$f" ] && should_add_completion "$f"; then
- . $f
- fi
- done
-
- if should_add_completion bit ; then
- complete -C "bit --tab" bit
- fi
- if [ -z "$ZSH_VERSION" ]; then
- # Doesn't work in zsh.
- complete -o nospace -F _croot croot
- fi
- complete -F _lunch lunch
-
- complete -F _complete_android_module_names dumpmod
- complete -F _complete_android_module_names pathmod
- complete -F _complete_android_module_names gomod
- complete -F _complete_android_module_names m
- }
详细的 complete 命令可以另外查找,最后就是把一些命令进行补齐的设置。
hmm 函数输出 envsetupsh.sh 的帮助说明,执行 build/envsetup.sh 后可以调用的操作总结:
- 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 and installs all of the modules in the current directory, and their
- dependencies.
- - mmm: Builds and installs all of the modules in the supplied directories, and their
- dependencies.
- To limit the modules being built use the syntax: mmm dir/:target1,target2.
- - mma: Same as 'mm'
- - mmma: Same as 'mmm'
- - 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.
- - gogrep: Greps on all local Go 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 and *.bp files.
- - owngrep: Greps on all local OWNERS 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. or List all modules inside certain directory.
- - gomod: Go to the directory containing a module.
- - dumpmod: Get all info of specific modules from \$ANDROID_PRODUCT_OUT/module-info.json
- - pathmod: Get the directory containing a module.
- - refreshmod: Refresh list of modules for allmod/gomod.
- - ninja-build: Bypass ninja generate procedure, directly use ninja to build a target or module, also build droid is support too by no param given.
- - ninja-query: Query input and output of a ninja target, this is the most powerful tool when digging the compile steps.
- - ninja-commands: Print all build commands, like a --just-print version of ninja-build, also known as the --dry-run purpose
- - mod: Analyze $OUT/module-info.json with parameters, see mod -h for help
- Environment options:
- - SANITIZE_HOST: Set to 'address' to use ASAN for all host modules.
- - 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
- }
最后还列出了完整的函数名,通过:
sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p"
但其操作有一个 bug,用于匹配函数的正则表达式 function
将匹配模式从 function
gettop 函数,从指定的 $TOP 目录或者当前目录开始查找 build/make/core/envsetup.mk,并将能找到该文件的目录返回个调用函数作为操作的根目录:
- function gettop
- {
- local TOPFILE=build/make/core/envsetup.mk
-
- #如果编译环境已经设置了 $TOP,就检查 $TOP/build/make/core/envsetup.mk文件是否存在
- if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then
- # The following circumlocution ensures we remove symlinks from TOP.
- #跳转到$TOP 目录,并pwd将$TOP 目录指向的真实路径存放到PWD中
- (cd $TOP; PWD= /bin/pwd)
- else
- #如果当前路径下能找到 build/make/core/envsetup.mk文件,则将当前目录的真实路径存放到PWD中
- if [ -f $TOPFILE ] ; then
- PWD= /bin/pwd
- else
- #如果当前目录下无法找到build/make/core/envsetup.mk文件,则不断返回到外层目录查找,
- #直至到根目录为止
- local HERE=$PWD
- local T=
- while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
- \cd ..
- T=`PWD= /bin/pwd -P`
- done
- #查找完后回到之前操作的路径
- \cd $HERE
- #如果目录$T包含了build/make/core/envsetup.mk,则说明$T是编译的根目录
- if [ -f "$T/$TOPFILE" ]; then
- echo $T
- fi
- fi
- fi
- }
croot 命令用以将当前目录切换到当前编译环境的根目录。
当然croot 之后可以跟一个参数标记切到根目录之后的下一级目录,例如 croot device 命令。
详细可以查看代码:
- 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
- }
cproj 命令用于切换到当前模块的编译目录下(含Android.mk的目录下)
- function cproj()
- {
- local TOPFILE=build/make/core/envsetup.mk
- local HERE=$PWD #临时保存当前目录
- local T=
-
- #当前目录下build/make/core/envsetup.mk不存在,即当前不是编译根目录,且
- #当前目录不是系统根目录
- while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do
- T=$PWD
- if [ -f "$T/Android.mk" ]; then #如果该目录下有Android.mk文件,则cd过去
- \cd $T
- return
- fi
- \cd ..
- done
- \cd $HERE #恢复之前的目录
- echo "can't find Android.mk"
- }
如上述命令,如果无法找到该模块下的 Android.mk,就会提示:
can't find Android.mk
例如在 packages/apps/Launcher3/protos/ 目录下运行 cproj 命令,则会退到 packages/apps/Launcher3/ 目录下。
- function getprebuilt
- {
- get_abs_build_var ANDROID_PREBUILTS
- }
- function get_abs_build_var()
- {
- if [ "$BUILD_VAR_CACHE_READY" = "true" ]
- then
- eval "echo \"\${abs_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 --abs $1)
- }
函数 get_abs_build_var() 用于查找编译时变量值,这里通过该函数查找变量是 ANDROID_PREBUILTS 这个绝对路径为 $TOP/prebuilt/linux-x86
主要是配置一些环境变量,在lunch 函数或者 choosecombo 函数最后调用:
- function setpaths()
- {
- local T=$(gettop)
- if [ ! "$T" ]; then
- echo "Couldn't locate the top of the tree. Try setting TOP."
- return
- fi
-
- ##################################################################
- # #
- # Read me before you modify this code #
- # #
- # This function sets ANDROID_BUILD_PATHS to what it is adding #
- # to PATH, and the next time it is run, it removes that from #
- # PATH. This is required so lunch can be run more than once #
- # and still have working paths. #
- # #
- ##################################################################
-
- # Note: on windows/cygwin, ANDROID_BUILD_PATHS will contain spaces
- # due to "C:\Program Files" being in the path.
-
- # out with the old
- if [ -n "$ANDROID_BUILD_PATHS" ] ; then
- export PATH=${PATH/$ANDROID_BUILD_PATHS/}
- fi
- if [ -n "$ANDROID_PRE_BUILD_PATHS" ] ; then
- export PATH=${PATH/$ANDROID_PRE_BUILD_PATHS/}
- # strip leading ':', if any
- export PATH=${PATH/:%/}
- fi
-
- # and in with the new
- local prebuiltdir=$(getprebuilt)
- local gccprebuiltdir=$(get_abs_build_var ANDROID_GCC_PREBUILTS)
-
- # defined in core/config.mk
- local targetgccversion=$(get_build_var TARGET_GCC_VERSION)
- local targetgccversion2=$(get_build_var 2ND_TARGET_GCC_VERSION)
- export TARGET_GCC_VERSION=$targetgccversion
-
- # The gcc toolchain does not exists for windows/cygwin. In this case, do not reference it.
- export ANDROID_TOOLCHAIN=
- export ANDROID_TOOLCHAIN_2ND_ARCH=
- local ARCH=$(get_build_var TARGET_ARCH)
- local toolchaindir toolchaindir2=
- case $ARCH in
- x86) toolchaindir=x86/x86_64-linux-android-$targetgccversion/bin
- ;;
- x86_64) toolchaindir=x86/x86_64-linux-android-$targetgccversion/bin
- ;;
- arm) toolchaindir=arm/arm-linux-androideabi-$targetgccversion/bin
- ;;
- arm64) toolchaindir=aarch64/aarch64-linux-android-$targetgccversion/bin;
- toolchaindir2=arm/arm-linux-androideabi-$targetgccversion2/bin
- ;;
- mips|mips64) toolchaindir=mips/mips64el-linux-android-$targetgccversion/bin
- ;;
- *)
- echo "Can't find toolchain for unknown architecture: $ARCH"
- toolchaindir=xxxxxxxxx
- ;;
- esac
- if [ -d "$gccprebuiltdir/$toolchaindir" ]; then
- export ANDROID_TOOLCHAIN=$gccprebuiltdir/$toolchaindir
- fi
-
- if [ "$toolchaindir2" -a -d "$gccprebuiltdir/$toolchaindir2" ]; then
- export ANDROID_TOOLCHAIN_2ND_ARCH=$gccprebuiltdir/$toolchaindir2
- fi
-
- export ANDROID_DEV_SCRIPTS=$T/development/scripts:$T/prebuilts/devtools/tools:$T/external/selinux/prebuilts/bin
-
- # add kernel specific binaries
- case $(uname -s) in
- Linux)
- export ANDROID_DEV_SCRIPTS=$ANDROID_DEV_SCRIPTS:$T/prebuilts/misc/linux-x86/dtc:$T/prebuilts/misc/linux-x86/libufdt
- ;;
- *)
- ;;
- esac
-
- ANDROID_BUILD_PATHS=$(get_build_var ANDROID_BUILD_PATHS):$ANDROID_TOOLCHAIN
- if [ -n "$ANDROID_TOOLCHAIN_2ND_ARCH" ]; then
- ANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$ANDROID_TOOLCHAIN_2ND_ARCH
- fi
- ANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$ANDROID_DEV_SCRIPTS
-
- # Append llvm binutils prebuilts path to ANDROID_BUILD_PATHS.
- local ANDROID_LLVM_BINUTILS=$(get_abs_build_var ANDROID_CLANG_PREBUILTS)/llvm-binutils-stable
- ANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$ANDROID_LLVM_BINUTILS
-
- # Set up ASAN_SYMBOLIZER_PATH for SANITIZE_HOST=address builds.
- export ASAN_SYMBOLIZER_PATH=$ANDROID_LLVM_BINUTILS/llvm-symbolizer
-
- # If prebuilts/android-emulator/<system>/ exists, prepend it to our PATH
- # to ensure that the corresponding 'emulator' binaries are used.
- case $(uname -s) in
- Darwin)
- ANDROID_EMULATOR_PREBUILTS=$T/prebuilts/android-emulator/darwin-x86_64
- ;;
- Linux)
- ANDROID_EMULATOR_PREBUILTS=$T/prebuilts/android-emulator/linux-x86_64
- ;;
- *)
- ANDROID_EMULATOR_PREBUILTS=
- ;;
- esac
- if [ -n "$ANDROID_EMULATOR_PREBUILTS" -a -d "$ANDROID_EMULATOR_PREBUILTS" ]; then
- ANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$ANDROID_EMULATOR_PREBUILTS
- export ANDROID_EMULATOR_PREBUILTS
- fi
-
- # Append asuite prebuilts path to ANDROID_BUILD_PATHS.
- local os_arch=$(get_build_var HOST_PREBUILT_TAG)
- local ACLOUD_PATH="$T/prebuilts/asuite/acloud/$os_arch"
- local AIDEGEN_PATH="$T/prebuilts/asuite/aidegen/$os_arch"
- local ATEST_PATH="$T/prebuilts/asuite/atest/$os_arch"
- export ANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$ACLOUD_PATH:$AIDEGEN_PATH:$ATEST_PATH:
-
- export PATH=$ANDROID_BUILD_PATHS$PATH
-
- # out with the duplicate old
- if [ -n $ANDROID_PYTHONPATH ]; then
- export PYTHONPATH=${PYTHONPATH//$ANDROID_PYTHONPATH/}
- fi
- # and in with the new
- export ANDROID_PYTHONPATH=$T/development/python-packages:
- if [ -n $VENDOR_PYTHONPATH ]; then
- ANDROID_PYTHONPATH=$ANDROID_PYTHONPATH$VENDOR_PYTHONPATH
- fi
- export PYTHONPATH=$ANDROID_PYTHONPATH$PYTHONPATH
-
- export ANDROID_JAVA_HOME=$(get_abs_build_var ANDROID_JAVA_HOME)
- export JAVA_HOME=$ANDROID_JAVA_HOME
- export ANDROID_JAVA_TOOLCHAIN=$(get_abs_build_var ANDROID_JAVA_TOOLCHAIN)
- export ANDROID_PRE_BUILD_PATHS=$ANDROID_JAVA_TOOLCHAIN:
- export PATH=$ANDROID_PRE_BUILD_PATHS$PATH
-
- unset ANDROID_PRODUCT_OUT
- export ANDROID_PRODUCT_OUT=$(get_abs_build_var PRODUCT_OUT)
- export OUT=$ANDROID_PRODUCT_OUT
-
- unset ANDROID_HOST_OUT
- export ANDROID_HOST_OUT=$(get_abs_build_var HOST_OUT)
-
- unset ANDROID_HOST_OUT_TESTCASES
- export ANDROID_HOST_OUT_TESTCASES=$(get_abs_build_var HOST_OUT_TESTCASES)
-
- unset ANDROID_TARGET_OUT_TESTCASES
- export ANDROID_TARGET_OUT_TESTCASES=$(get_abs_build_var TARGET_OUT_TESTCASES)
-
- # needed for building linux on MacOS
- # TODO: fix the path
- #export HOST_EXTRACFLAGS="-I "$T/system/kernel_headers/host_include
- }
首先确认 gettop 是否能找到编译的根目录,如果找不到,则退出该函数;
接着export 一些环境变量:
- function set_sequence_number()
- {
- export BUILD_ENV_SEQUENCE_NUMBER=13
- }
指定环境变量 BUILD_ENV_SEQUENCE_NUMBER,后面 buildspec.mk 中会确认该环境变量的值与CORRECT_BUILD_ENV_SEQUENCE_NUMBER 相等。
- function set_stuff_for_environment()
- {
- 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'
- }
调用 2.6 和 2.7 节的函数,并设定环境变量 ANDROID_BUILD_TOP 和 GCC_COLORS。
之后调用函数 gettop 打印出来的路径,通过 ANDROID_BUILD_TOP 就可以获知。
该函数通常是在choosetype、chooseproduct、lunch 函数中调用。
- function printconfig()
- {
- local 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
- }
调用get_build_var 函数将lunch 之后的编译配置信息:
- ============================================
- PLATFORM_VERSION_CODENAME=REL
- PLATFORM_VERSION=11
- TARGET_PRODUCT=shift
- TARGET_BUILD_VARIANT=userdebug
- TARGET_BUILD_TYPE=release
- TARGET_ARCH=arm64
- TARGET_ARCH_VARIANT=armv8-a
- TARGET_CPU_VARIANT=cortex-a55
- TARGET_2ND_ARCH=arm
- TARGET_2ND_ARCH_VARIANT=armv8-a
- TARGET_2ND_CPU_VARIANT=cortex-a55
- HOST_ARCH=x86_64
- HOST_2ND_ARCH=x86
- HOST_OS=linux
- HOST_OS_EXTRA=Linux-4.15.0-142-generic-x86_64-Ubuntu-16.04.5-LTS
- HOST_CROSS_OS=windows
- HOST_CROSS_ARCH=x86
- HOST_CROSS_2ND_ARCH=x86_64
- HOST_BUILD_TYPE=release
- BUILD_ID=RD2A.211001.002
- OUT_DIR=out
- PRODUCT_SOONG_NAMESPACES=vendor/qqq/opensource/commonsys/packages/apps/Bluetooth vendor/qqq/opensource/commonsys/system/bt/conf external/v4l2_codec2
- ============================================
通常在 lunch 函数设定完环境变量后会调用该函数进行 config 的打印。详细看 lunch 函数。
- function gettargetarch
- {
- get_build_var TARGET_ARCH
- }
通过 get_build_var 函数获取编译目标系统的 CPU 架构,如arm64
- function godir () {
- if [[ -z "$1" ]]; then
- echo "Usage: godir <regex>"
- return
- fi
- local T=$(gettop)
- local FILELIST
- if [ ! "$OUT_DIR" = "" ]; then
- mkdir -p $OUT_DIR
- FILELIST=$OUT_DIR/filelist
- else
- FILELIST=$T/filelist
- fi
- if [[ ! -f $FILELIST ]]; then
- echo -n "Creating index..."
- (\cd $T; find . -wholename ./out -prune -o -wholename ./.repo -prune -o -type f > $FILELIST)
- echo " Done"
- echo ""
- fi
- local lines
- lines=($(\grep "$1" $FILELIST | sed -e 's/\/[^/]*$//' | sort | uniq))
- if [[ ${#lines[@]} = 0 ]]; then
- echo "Not found"
- return
- fi
- local pathname
- local choice
- if [[ ${#lines[@]} > 1 ]]; then
- while [[ -z "$pathname" ]]; do
- local index=1
- local line
- for line in ${lines[@]}; do
- printf "%6s %s\n" "[$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)):1}
- done
- else
- pathname=${lines[@]:0:1}
- fi
- \cd $T/$pathname
- }
这是一个很使用的函数,可以快速的跳转到所指向的目标目录。该命令需要一个目标文件名作为命令行参数。
该函数会在 set_stuff_for_environment 函数之前调用,set_stuff_for_environment 详细看第 2.8 节。
该函数用以将 envsetup.sh 中使用函数 get_build_var、get_abs_build_var 查询的变量都收集到 cached_vars 和 cached_abs_vars 中,然后通过 soong_ui.bash 脚本创建键值对。
- function build_build_var_cache()
- {
- local T=$(gettop)
- # Grep out the variable names from the script.
- 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' ' '`)
- 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.
- build_dicts_script=`\builtin cd $T; build/soong/soong_ui.bash --dumpvars-mode \
- --vars="${cached_vars[*]}" \
- --abs-vars="${cached_abs_vars[*]}" \
- --var-prefix=var_cache_ \
- --abs-var-prefix=abs_var_cache_`
- local ret=$?
- if [ $ret -ne 0 ]
- then
- unset build_dicts_script
- return $ret
- fi
- # Execute the script to store the "<val>=<value>" pairs as shell variables.
- eval "$build_dicts_script"
- ret=$?
- unset build_dicts_script
- if [ $ret -ne 0 ]
- then
- return $ret
- fi
- BUILD_VAR_CACHE_READY="true"
- }
如果在 eval 之前将 $build_dicts_script 打印出来,结果大致如下:
var_cache_2ND_TARGET_GCC_VERSION='4.9' var_cache_ANDROID_BUILD_PATHS='/home/justinwei/work/myproduct/android/out/soong/host/linux-x86/bin:/home/justinwei/work/myproduct/android/out/host/linux-x86/bin' var_cache_COMMON_LUNCH_CHOICES='C3MN-userdebug aosp_arm-eng aosp_arm64-eng aosp_blueline_car-userdebug aosp_bonito_car-userdebug aosp_car_arm-userdebug aosp_car_arm64-userdebug aosp_car_x86-userdebug aosp_car_x86_64-userdebug aosp_cf_arm64_auto-userdebug aosp_cf_arm64_phone-userdebug aosp_cf_x86_64_phone-userdebug aosp_cf_x86_auto-userdebug aosp_cf_x86_phone-userdebug aosp_cf_x86_tv-userdebug aosp_coral_car-userdebug aosp_crosshatch_car-userdebug aosp_flame_car-userdebug aosp_x86-eng aosp_x86_64-eng arm_krait-eng arm_v7_v8-eng armv8-eng armv8_kryo385-eng car_x86_64-userdebug shift-userdebug shift_global-userdebug shift_in-userdebug shiftevb-userdebug qemu_trusty_arm64-userdebug silvermont-eng' var_cache_HOST_PREBUILT_TAG='linux-x86' var_cache_TARGET_ARCH='arm64' var_cache_TARGET_BUILD_VARIANT='user' var_cache_TARGET_DEVICE='shift' var_cache_TARGET_GCC_VERSION='4.9' var_cache_TARGET_PLATFORM_VERSION='RP1A' var_cache_TARGET_PRODUCT='shift' var_cache_print='' var_cache_report_config='============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=11 TARGET_PRODUCT=shift TARGET_BUILD_VARIANT=user TARGET_BUILD_TYPE=release TARGET_ARCH=arm64 TARGET_ARCH_VARIANT=armv8-a TARGET_CPU_VARIANT=cortex-a55 TARGET_2ND_ARCH=arm TARGET_2ND_ARCH_VARIANT=armv8-a TARGET_2ND_CPU_VARIANT=cortex-a55 HOST_ARCH=x86_64 HOST_2ND_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=Linux-5.10.102.1-microsoft-standard-WSL2-x86_64-Ubuntu-18.04.2-LTS HOST_CROSS_OS=windows HOST_CROSS_ARCH=x86 HOST_CROSS_2ND_ARCH=x86_64 HOST_BUILD_TYPE=release BUILD_ID=RD2A.211001.002 OUT_DIR=out PRODUCT_SOONG_NAMESPACES=vendor/qcom/opensource/commonsys/packages/apps/Bluetooth vendor/qcom/opensource/commonsys/system/bt/conf ============================================' abs_var_cache_ANDROID_CLANG_PREBUILTS='/home/justinwei/work/myproduct/android/prebuilts/clang/host/linux-x86' abs_var_cache_ANDROID_GCC_PREBUILTS='/home/justinwei/work/myproduct/android/prebuilts/gcc/linux-x86' abs_var_cache_ANDROID_JAVA_HOME='/home/justinwei/work/myproduct/android/prebuilts/jdk/jdk11/linux-x86' abs_var_cache_ANDROID_JAVA_TOOLCHAIN='/home/justinwei/work/myproduct/android/prebuilts/jdk/jdk11/linux-x86/bin' abs_var_cache_ANDROID_PREBUILTS='/home/justinwei/work/myproduct/android/prebuilt/linux-x86' abs_var_cache_HOST_OUT='/home/justinwei/work/myproduct/android/out/host/linux-x86' abs_var_cache_HOST_OUT_TESTCASES='/home/justinwei/work/myproduct/android/out/host/linux-x86/testcases'
- function get_abs_build_var()
- {
- if [ "$BUILD_VAR_CACHE_READY" = "true" ]
- then
- eval "echo \"\${abs_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 --abs $1)
- }
通过 soog_ui.bash 解析需要查找的变量,该变量已经在之前的 build_build_var_cache 函数中创建了键值对,详细看第 3.1 节。
这些变量都是以 abs_var_cache_ 作为前缀,详细看第 3.1 节中打印的情况。
- 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)
- }
该函数与上面的 get_abs_build_var 差不多的,区别在于 get_abs_build_var 指定的变量都是以 abs_var_cache_ 为前缀,而get_build_var 指定的变量都是以 var_cache_ 为前缀。
- function print_lunch_menu()
- {
- local uname=$(uname)
- local choices=$(TARGET_BUILD_APPS= get_build_var COMMON_LUNCH_CHOICES)
- echo
- echo "You're building on" $uname
- echo
- echo "Lunch menu... pick a combo:"
-
- local i=1
- local choice
- for choice in $(echo $choices)
- do
- echo " $i. $choice"
- i=$(($i+1))
- done
-
- echo
- }
打印 lunch 可选的 combo:
You're building on Linux Lunch menu... pick a combo: 1. C3MN-userdebug 2. aosp_arm-eng 3. aosp_arm64-eng 4. aosp_blueline_car-userdebug 5. aosp_bonito_car-userdebug 6. aosp_car_arm-userdebug 7. aosp_car_arm64-userdebug 8. aosp_car_x86-userdebug 9. aosp_car_x86_64-userdebug 10. aosp_cf_arm64_auto-userdebug 11. aosp_cf_arm64_phone-userdebug 12. aosp_cf_x86_64_phone-userdebug 13. aosp_cf_x86_auto-userdebug 14. aosp_cf_x86_phone-userdebug 15. aosp_cf_x86_tv-userdebug 16. aosp_coral_car-userdebug 17. aosp_crosshatch_car-userdebug 18. aosp_flame_car-userdebug
- function lunch()
- {
- local answer
-
- if [ "$1" ] ; then
- answer=$1
- else
- print_lunch_menu
- echo -n "Which would you like? [aosp_arm-eng] "
- read answer
- fi
-
- local selection=
-
- if [ -z "$answer" ]
- then
- selection=aosp_arm-eng
- elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$")
- then
- 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
- 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
- }
函数是android 系统编译之前的核心操作,大致流程如下:
在分析 m、mm、mmm 等函数之前,需要了解下 _trigger_build 这个函数:
- function _trigger_build()
- (
- local -r bc="$1"; shift
- if T="$(gettop)"; then
- _wrap_build "$T/build/soong/soong_ui.bash" --build-mode --${bc} --dir="$(pwd)" "$@"
- else
- echo "Couldn't locate the top of the tree. Try setting TOP."
- fi
- )
主要调用 $TOP/build/soong/soong_ui.bash 脚本进行编译,然后通过 _wrap_build 函数对结果进行特殊显示,详细见下面。
- function _wrap_build()
- {
- if [[ "${ANDROID_QUIET_BUILD:-}" == true ]]; then
- "$@"
- return $?
- fi
- local start_time=$(date +"%s")
- "$@"
- local ret=$?
- local end_time=$(date +"%s")
- local tdiff=$(($end_time-$start_time))
- local hours=$(($tdiff / 3600 ))
- local mins=$((($tdiff % 3600) / 60))
- local secs=$(($tdiff % 60))
- local ncolors=$(tput colors 2>/dev/null)
- if [ -n "$ncolors" ] && [ $ncolors -ge 8 ]; then
- color_failed=$'\E'"[0;31m"
- color_success=$'\E'"[0;32m"
- color_reset=$'\E'"[00m"
- else
- color_failed=""
- color_success=""
- color_reset=""
- fi
- echo
- if [ $ret -eq 0 ] ; then
- echo -n "${color_success}#### build completed successfully "
- else
- echo -n "${color_failed}#### failed to build some targets "
- fi
- if [ $hours -gt 0 ] ; then
- printf "(%02g:%02g:%02g (hh:mm:ss))" $hours $mins $secs
- elif [ $mins -gt 0 ] ; then
- printf "(%02g:%02g (mm:ss))" $mins $secs
- elif [ $secs -gt 0 ] ; then
- printf "(%s seconds)" $secs
- fi
- echo " ####${color_reset}"
- echo
- return $ret
- }
主要处理结果,以及结果的颜色效果、编译用时。
- function m()
- (
- call_hook ${FUNCNAME[0]} $@
- if [ $? -ne 0 ]; then
- return 1
- fi
-
- _trigger_build "all-modules" "$@"
- )
-
- function mm()
- (
- call_hook ${FUNCNAME[0]} $@
- if [ $? -ne 0 ]; then
- return 1
- fi
-
- _trigger_build "modules-in-a-dir-no-deps" "$@"
- )
-
- function mmm()
- (
- call_hook ${FUNCNAME[0]} $@
- if [ $? -ne 0 ]; then
- return 1
- fi
-
- _trigger_build "modules-in-dirs-no-deps" "$@"
- )
-
- function mma()
- (
- call_hook ${FUNCNAME[0]} $@
- if [ $? -ne 0 ]; then
- return 1
- fi
-
- _trigger_build "modules-in-a-dir" "$@"
- )
-
- function mmma()
- (
- call_hook ${FUNCNAME[0]} $@
- if [ $? -ne 0 ]; then
- return 1
- fi
-
- _trigger_build "modules-in-dirs" "$@"
- )
- function ggrep()
- {
- find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.gradle" \
- -exec grep --color -n "$@" {} +
- }
-
- function gogrep()
- {
- find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.go" \
- -exec grep --color -n "$@" {} +
- }
-
- function jgrep()
- {
- find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.java" \
- -exec grep --color -n "$@" {} +
- }
-
- 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 "$@" {} +
- }
-
- function resgrep()
- {
- local dir
- for dir in `find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -name res -type d`; do
- find $dir -type f -name '*\.xml' -exec grep --color -n "$@" {} +
- done
- }
-
- function mangrep()
- {
- find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o -type f -name 'AndroidManifest.xml' \
- -exec grep --color -n "$@" {} +
- }
-
- function owngrep()
- {
- find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o -type f -name 'OWNERS' \
- -exec grep --color -n "$@" {} +
- }
-
- function sepgrep()
- {
- find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o -name sepolicy -type d \
- -exec grep --color -n -r --exclude-dir=\.git "$@" {} +
- }
-
- function rcgrep()
- {
- find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f -name "*\.rc*" \
- -exec grep --color -n "$@" {} +
- }
搜索的几个函数基本相同,都是使用的 find 命令和 grep 命令结合。
首先, find 会排除一些文件夹:
接着,find 会指定文件类型:
最后,find 通过 -exec 执行 grep 命令
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。