Android build中的envsetup.sh详解

news/2024/10/18 3:24:24/

源码基于:Android R

0. 前言

今天在编译项目的时候,想看看 envsetup.sh 中变化了些什么,才想起来编译专栏中好像没有详解该脚本,索性现在空余时间比较多,整理一下方便以后查看。

Android envsetup.sh 为编译前的准备工作,提供 lunch、m、mm等命令函数定义,是整个Android 编译系统的第一步。该文件一共1700 行左右,简单总结出两件事情:

  • 函数定义
  • 生成编译配置列表

本文会结合代码对 envsetup.sh 进行详细的剖析,函数比较多,会进行长期地补充和维护。

1. source 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.shvalidate_current_shell
source_vendorsetup
addcompletions

执行该程序共运行三个函数,分别是 validate_current_shell、source_vendorsetup、addcompletions。下面来看下这三个函数做了些什么事情?

1.1 validate_current_shell

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。


1.2 source_vendorsetup

function source_vendorsetup() {unset VENDOR_PYTHONPATHallowed=for f in $(find -L device vendor product -maxdepth 4 -name 'allowed-vendorsetup_sh-files' 2>/dev/null | sort); doif [ -n "$allowed" ]; thenecho "More than one 'allowed_vendorsetup_sh-files' file found, not including any vendorsetup.sh files:"echo "  $allowed"echo "  $f"returnfiallowed="$f"doneallowed_files=[ -n "$allowed" ] && allowed_files=$(cat "$allowed")for dir in device vendor product; dofor f in $(test -d $dir && \find -L $dir -maxdepth 4 -name 'vendorsetup.sh' 2>/dev/null | sort); doif [[ -z "$allowed" || "$allowed_files" =~ $f ]]; thenecho "including $f"; . "$f"elseecho "ignoring $f, not in $allowed"fidonedone
}
  • 首先,查找 device、vendor、product 目录下最大深度为4 的子目录中,是否存在 allowed-vendorsetup_sh-files 文件并排序,但这个文件只能1个,不然会报错退出;
  • 接着,在device、vendor、product 中同样查找最大深度为 4 的子目录中,是否存在 vendorsetup.sh,打印 includeing ... ,然后运行该 vendorsetup.sh 脚本,这些脚本大多是配置一些环境变量;

例如上面的打印 including vendor/xxx/common/vendorsetup.sh,就是在 vendor/xxx/common 目录下找到了 vendorsetup.sh,运行的时候会配置一些环境变量,并打印:

clang compdb: ln -s out/soong/development/ide/compdb/compile_commands.json 


1.3 addcompletions

function addcompletions()
{local T dir f#避免不在 bash 或 zsh 的环境中运行#需要提前指定这两个环境变量,如果没有指定,该函数returnif [ -z "$BASH_VERSION" -a -z "$ZSH_VERSION" ]; thenreturnfi#避免运行在太久的版本中,这里是小于 3 的版本if [ -n "$BASH_VERSION" -a ${BASH_VERSINFO[0]} -lt 3 ]; thenreturnfilocal completion_files=(system/core/adb/adb.bashsystem/core/fastboot/fastboot.bashtools/asuite/asuite.sh)#确认上面几个脚本是否存在,通过should_add_completion确认该脚本是否在白名单中for f in ${completion_files[*]}; doif [ -f "$f" ] && should_add_completion "$f"; then. $ffidoneif should_add_completion bit ; thencomplete -C "bit --tab" bitfiif [ -z "$ZSH_VERSION" ]; then# Doesn't work in zsh.complete -o nospace -F _croot crootficomplete -F _lunch lunchcomplete -F _complete_android_module_names dumpmodcomplete -F _complete_android_module_names pathmodcomplete -F _complete_android_module_names gomodcomplete -F _complete_android_module_names m
}

详细的 complete 命令可以另外查找,最后就是把一些命令进行补齐的设置。

2. 辅助函数

2.1 hmm

hmm 函数输出 envsetupsh.sh 的帮助说明,执行 build/envsetup.sh 后可以调用的操作总结:

function hmm() {
cat <<EOFRun "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 tobuild, and stores those selections in the environment to be read by subsequentinvocations 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 theirdependencies.
- mmm:        Builds and installs all of the modules in the supplied directories, and theirdependencies.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 helpEnvironment 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:
EOFlocal T=$(gettop)local A=""local ifor i in `cat $T/build/envsetup.sh | sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p" | sort | uniq`; doA="$A $i"doneecho $A
}

最后还列出了完整的函数名,通过:

sed -n "/^[[:blank:]]*function /s/function \([a-z_]*\).*/\1/p"

但其操作有一个 bug,用于匹配函数的正则表达式 function \([a-z_]*\).* 会漏掉函数 is64bit()

将匹配模式从 function \([a-z_]*\).*/  修改为 function \([a-z_]\w*\).*  就可以匹配文件中的所有函数了。

2.2 gettop

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 ] ; thenPWD= /bin/pwdelse#如果当前目录下无法找到build/make/core/envsetup.mk文件,则不断返回到外层目录查找,#直至到根目录为止local HERE=$PWDlocal 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" ]; thenecho $Tfififi
}

2.3 croot

croot 命令用以将当前目录切换到当前编译环境的根目录。

当然croot 之后可以跟一个参数标记切到根目录之后的下一级目录,例如 croot device 命令。

详细可以查看代码:

function croot()
{local T=$(gettop)if [ "$T" ]; thenif [ "$1" ]; then\cd $(gettop)/$1else\cd $(gettop)fielseecho "Couldn't locate the top of the tree.  Try setting TOP."fi
}

2.4 cproj

cproj 命令用于切换到当前模块的编译目录下(含Android.mk的目录下)

function cproj()
{local TOPFILE=build/make/core/envsetup.mklocal HERE=$PWD  #临时保存当前目录local T=#当前目录下build/make/core/envsetup.mk不存在,即当前不是编译根目录,且#当前目录不是系统根目录while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; doT=$PWDif [ -f "$T/Android.mk" ]; then  #如果该目录下有Android.mk文件,则cd过去\cd $Treturnfi\cd ..done\cd $HERE   #恢复之前的目录echo "can't find Android.mk"
}

2.5 getprebuilt

function getprebuilt
{get_abs_build_var ANDROID_PREBUILTS
}
function get_abs_build_var()
{if [ "$BUILD_VAR_CACHE_READY" = "true" ]theneval "echo \"\${abs_var_cache_$1}\""returnfilocal T=$(gettop)if [ ! "$T" ]; thenecho "Couldn't locate the top of the tree.  Try setting TOP." >&2returnfi(\cd $T; build/soong/soong_ui.bash --dumpvar-mode --abs $1)
}

主要是通过函数 get_abs_build_var() 中查找变量值,这里查找的是 ANDROID_PREBUILTS 这个绝对路径为 $TOP/prebuilt/linux-x86

2.6 setpaths

主要是配置一些环境变量,在lunch 命令时调用,或者是在 choosecombo 函数中调用:

function setpaths()
{local T=$(gettop)if [ ! "$T" ]; thenecho "Couldn't locate the top of the tree.  Try setting TOP."returnfi###################################################################                                                                ##              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 oldif [ -n "$ANDROID_BUILD_PATHS" ] ; thenexport PATH=${PATH/$ANDROID_BUILD_PATHS/}fiif [ -n "$ANDROID_PRE_BUILD_PATHS" ] ; thenexport PATH=${PATH/$ANDROID_PRE_BUILD_PATHS/}# strip leading ':', if anyexport PATH=${PATH/:%/}fi# and in with the newlocal prebuiltdir=$(getprebuilt)local gccprebuiltdir=$(get_abs_build_var ANDROID_GCC_PREBUILTS)# defined in core/config.mklocal 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 inx86) 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;;esacif [ -d "$gccprebuiltdir/$toolchaindir" ]; thenexport ANDROID_TOOLCHAIN=$gccprebuiltdir/$toolchaindirfiif [ "$toolchaindir2" -a -d "$gccprebuiltdir/$toolchaindir2" ]; thenexport ANDROID_TOOLCHAIN_2ND_ARCH=$gccprebuiltdir/$toolchaindir2fiexport ANDROID_DEV_SCRIPTS=$T/development/scripts:$T/prebuilts/devtools/tools:$T/external/selinux/prebuilts/bin# add kernel specific binariescase $(uname -s) inLinux)export ANDROID_DEV_SCRIPTS=$ANDROID_DEV_SCRIPTS:$T/prebuilts/misc/linux-x86/dtc:$T/prebuilts/misc/linux-x86/libufdt;;*);;esacANDROID_BUILD_PATHS=$(get_build_var ANDROID_BUILD_PATHS):$ANDROID_TOOLCHAINif [ -n "$ANDROID_TOOLCHAIN_2ND_ARCH" ]; thenANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$ANDROID_TOOLCHAIN_2ND_ARCHfiANDROID_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-stableANDROID_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) inDarwin)ANDROID_EMULATOR_PREBUILTS=$T/prebuilts/android-emulator/darwin-x86_64;;Linux)ANDROID_EMULATOR_PREBUILTS=$T/prebuilts/android-emulator/linux-x86_64;;*)ANDROID_EMULATOR_PREBUILTS=;;esacif [ -n "$ANDROID_EMULATOR_PREBUILTS" -a -d "$ANDROID_EMULATOR_PREBUILTS" ]; thenANDROID_BUILD_PATHS=$ANDROID_BUILD_PATHS:$ANDROID_EMULATOR_PREBUILTSexport ANDROID_EMULATOR_PREBUILTSfi# 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 oldif [ -n $ANDROID_PYTHONPATH ]; thenexport PYTHONPATH=${PYTHONPATH//$ANDROID_PYTHONPATH/}fi# and in with the newexport ANDROID_PYTHONPATH=$T/development/python-packages:if [ -n $VENDOR_PYTHONPATH  ]; thenANDROID_PYTHONPATH=$ANDROID_PYTHONPATH$VENDOR_PYTHONPATHfiexport PYTHONPATH=$ANDROID_PYTHONPATH$PYTHONPATHexport ANDROID_JAVA_HOME=$(get_abs_build_var ANDROID_JAVA_HOME)export JAVA_HOME=$ANDROID_JAVA_HOMEexport ANDROID_JAVA_TOOLCHAIN=$(get_abs_build_var ANDROID_JAVA_TOOLCHAIN)export ANDROID_PRE_BUILD_PATHS=$ANDROID_JAVA_TOOLCHAIN:export PATH=$ANDROID_PRE_BUILD_PATHS$PATHunset ANDROID_PRODUCT_OUTexport ANDROID_PRODUCT_OUT=$(get_abs_build_var PRODUCT_OUT)export OUT=$ANDROID_PRODUCT_OUTunset ANDROID_HOST_OUTexport ANDROID_HOST_OUT=$(get_abs_build_var HOST_OUT)unset ANDROID_HOST_OUT_TESTCASESexport ANDROID_HOST_OUT_TESTCASES=$(get_abs_build_var HOST_OUT_TESTCASES)unset ANDROID_TARGET_OUT_TESTCASESexport 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
}

2.7 printconfig

function printconfig()
{local T=$(gettop)if [ ! "$T" ]; thenecho "Couldn't locate the top of the tree.  Try setting TOP." >&2returnfiget_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
============================================

2.8 


http://www.ppmy.cn/news/107272.html

相关文章

个人博客搭建详细步骤

1. 安装 jdk 和 tomcat 下面将带大家安装 jdk 和部署 tomcat; 首先在本地下载好 jdk 和 tomcat 安装压缩包在服务器新建一个目录&#xff0c;比如在服务器新建一个目录 soft&#xff0c;上传 jdk, tomcat 到服务器 mkdir soft cd soft rz 选择上传的文件名称 //上传文件新建…

2022年长三角高校数学建模竞赛C题隧道的升级改造与设计解题全过程文档及程序

2022年长三角高校数学建模竞赛 C题 隧道的升级改造与设计 原题再现&#xff1a; 某地现存一旧式双洞隧道&#xff0c;现计划将该隧道在旧貌基础上升级改造。在升级改造前&#xff0c;需进行定标与设计。考虑到该隧道洞壁附着特殊涂料&#xff0c;无人机在洞内通信信号较差&am…

共同成长 合力致远,就在2023亚马逊云科技合作伙伴峰会

在云计算蓬勃发展的今天&#xff0c;在推动业务发展、实现共赢的过程中&#xff0c;价值成就&#xff0c;是亚马逊云科技对合作伙伴自始至终的承诺。为助力合作伙伴成就价值&#xff0c;共建成长路径&#xff0c;2023亚马逊云科技合作伙伴峰会将于6月27日在上海世博中心重磅启幕…

C语言---分支和循环语句

1、什么是语句 C语言语句可以分为五类&#xff1a; 表达式语句函数调用语句控制语句复合语句空语句 C语言有九种控制语句 可以分成一下三类&#xff1a; 条件判断语句也叫分支语句&#xff1a;if语句&#xff0c;switch语句&#xff1b;循环执行语句&#xff1a;do while语…

AI创作工具的使用体验报告

下面是AI创作工具的使用体验报告&#xff0c;围绕以下三点展开&#xff1a; 一、工具的使用体验如何&#xff1f; CSDN博客AI创作工具是一款非常易用的工具&#xff0c;操作简单&#xff0c;可以很快地开始创建内容。在使用过程中&#xff0c;我发现它的语言模型很智能&#…

HHDESK及HHDBCS快捷升级功能

为提升用户体验&#xff0c;HHDESK及HHDBCS新增了一项功能&#xff0c;一键升级。 1 使用软件时快捷升级 在产品首页点击帮助&#xff0c;选择软件升级 弹出如下对话框&#xff1b;点击确定 随即弹出对话框&#xff1b;点击浏览&#xff0c;选择下载到本机上的新版本产品…

【移动计算技术(Android)】期末复习

目录 选择题 选择题知识点汇总 Activity Intent Broadcast BroadcastReceiver 如何自定义Receiver 如何注册接收器 Service SharedPreferences 三种访问模式 如何创建 如何存储/修改 如何读取 内部存储 openFileOutput openFileInput SD卡 资源文件 SQLite…