Android系统编译前的准备工作,我个人认为由如下三个步骤完成。接下来,我就逐一分析每一步骤都干了什么事情。
1、安装jdk、设置环境变量JAVA_HOME。
2、source build/envsetup.sh
3、lunch <product_name>-<build_variant>
###################################################
博文中出现的get_abs_build_var() 和 get_build_var()请移步到 这里
1、设置JAVA_HMOE环境变量
export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd642、source build/envsetup.sh
该shell脚本实现了许多有用的shell函数,可通过执行hmm命令查看(hmm是envsetup.sh实现的第一个shell函数)。
下面是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. - sgrep: Greps on all local source files. - godir: Go to the directory containing a file.
除了上面实现的shell函数,envsetup.sh还把device和vendor目录下的所有vendorsetup.sh脚本包含进来了。最后,还调用shell函数addcompletions。
if [ "x$SHELL" != "x/bin/bash" ]; then case `ps -o command -p $$` in # $$属于Special Shell Variables,表示Process ID of shell *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. for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null` \ `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null` do echo "including $f" . $f # source找到的所有vendorsetup.sh文件 done unset f addcompletions # 检查bash版本,并source sdk/bash_completion目录下的所有[a-z]*.bash文件$$ 请查看 Special Shell Variables
vendorsetup.sh的内容大多数是调用add_lunch_combo函数添加<product_name>-<build_variant>格式的lunch选项(也可以实现一些shell functions)。如:
add_lunch_combo aosp_flounder-userdebug
接下来,看一下add_lunch_combo函数的实现,File:build/envsetup.sh。
# Clear this variable. It will be built up again when the vendorsetup.sh # files are included at the end of this file. unset 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) # vendorsetup.sh中添加的combo选项都保存在数组LUNCH_MENU_CHOICES中 }我们回到envsetup.sh脚本的最后一行,看一下addcompletions函数的实现,File:build/envsetup.sh。
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 # source 所有[a-z]*.bash脚本 done fi }
3、lunch <product_name>-<build_variant>
lunch命令是一个shell函数,是在执行source build/envsetup.sh时添加到shell环境中的。
function lunch() { local answer if [ "$1" ] ; then answer=$1 else print_lunch_menu # 3.1、循环打印LUNCH_MENU_CHOICES数组中的<product_name>-<build_variant>选项 echo -n "Which would you like? [aosp_arm-eng] " read answer fi local selection= if [ -z "$answer" ] then # 3.2、如果lunch时没有指定或选中任何combo,就默认使用aosp_arm-eng,该combo是执行source build/envsetup.sh时添加到LUNCH_MENU_CHOICES中的 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 if [ -z "$selection" ] then echo echo "Invalid lunch combo: $answer" return 1 fi export TARGET_BUILD_APPS= local product=$(echo -n $selection | sed -e "s/-.*$//") # 把<product_name>赋值给变量product check_product $product # 3.3、检查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 local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//") # 把<build_variant>赋值给变量variant check_variant $variant # 3.4、检查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 export TARGET_PRODUCT=$product export TARGET_BUILD_VARIANT=$variant export TARGET_BUILD_TYPE=release echo set_stuff_for_environment # 3.5、设置编译所需的环境变量 printconfig # 3.6、打印config }
3.1、循环打印LUNCH_MENU_CHOICES数组中的<product_name>-<build_variant>选项。
function print_lunch_menu() { local uname=$(uname) echo echo "You're building on" $uname echo echo "Lunch menu... pick a combo:" local i=1 local choice for choice in ${LUNCH_MENU_CHOICES[@]} # 打印LUNCH_MENU_CHOICES数组中的所有元素 do echo " $i. $choice" i=$(($i+1)) done echo }
3.2、如果lunch时没有指定或选中任何combo,就默认使用aosp_arm-eng,该combo是执行source build/envsetup.sh时添加到LUNCH_MENU_CHOICES中的。
# 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
3.3、检查product是否存在
# check to see if the supplied product is one we can build 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 }3.4、检查variant是否合法
VARIANT_CHOICES=(user userdebug eng)
# check to see if the supplied variant is valid function check_variant() { for v in ${VARIANT_CHOICES[@]} # <build_variant>必须是(user userdebug eng)中的一个。 do if [ "$v" = "$1" ] then return 0 fi done return 1 }
3.5、设置编译所需的环境变量
function set_stuff_for_environment() { settitle # 3.5.1、设置title set_java_home # 3.5.2、设置java home setpaths # 3.5.3、设置paths set_sequence_number # 3.5.4、设置sequence number export ANDROID_BUILD_TOP=$(gettop) # 该变量是android代码树根目录的绝对路径 # 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' # 设置gcc的警告和错误可以彩色显示 }
3.5.1、设置title
function settitle() { if [ "$STAY_OFF_MY_LAWN" = "" ]; then # $STAY_OFF_MY_LAWN默认为空,走if分支 local arch=$(gettargetarch) local product=$TARGET_PRODUCT # 即<product_name> local variant=$TARGET_BUILD_VARIANT # 即<build_name> local apps=$TARGET_BUILD_APPS # 默认为空 if [ -z "$apps" ]; then # $apps默认为空,走if分会 export PROMPT_COMMAND="echo -ne \"\033]0;[${arch}-${product}-${variant}] ${USER}@${HOSTNAME}: ${PWD}\007\"" else export PROMPT_COMMAND="echo -ne \"\033]0;[$arch $apps $variant] ${USER}@${HOSTNAME}: ${PWD}\007\"" fi fi }3.5.2、设置java home
# Force JAVA_HOME to point to java 1.7 or java 1.6 if it isn't already set. # # Note that the MacOS path for java 1.7 includes a minor revision number (sigh). # For some reason, installing the JDK doesn't make it show up in the # JavaVM.framework/Versions/1.7/ folder. function set_java_home() { # Clear the existing JAVA_HOME value if we set it ourselves, so that # we can reset it later, depending on the version of java the build # system needs. # # If we don't do this, the JAVA_HOME value set by the first call to # build/envsetup.sh will persist forever. if [ -n "$ANDROID_SET_JAVA_HOME" ]; then # linux系统,$ANDROID_SET_JAVA_HOME默认为空,不走if分支。 export JAVA_HOME="" fi if [ ! "$JAVA_HOME" ]; then # JAVA_HOME已经在第一步骤中export了。$JAVA_HOME不为空,不走if分支。 if [ -n "$LEGACY_USE_JAVA6" ]; then case `uname -s` in Darwin) export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.6/Home ;; *) export JAVA_HOME=/usr/lib/jvm/java-6-sun ;; esac else case `uname -s` in Darwin) export JAVA_HOME=$(/usr/libexec/java_home -v 1.7) ;; *) export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 ;; esac fi # Keep track of the fact that we set JAVA_HOME ourselves, so that # we can change it on the next envsetup.sh, if required. export ANDROID_SET_JAVA_HOME=true fi }3.5.3、设置paths
function setpaths() { 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 prebuiltdir=$(getprebuilt) gccprebuiltdir=$(get_abs_build_var ANDROID_GCC_PREBUILTS) # defined in core/config.mk targetgccversion=$(get_build_var TARGET_GCC_VERSION) 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) 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; toolchaindir2=aarch64/aarch64-linux-android-$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 [ -d "$gccprebuiltdir/$toolchaindir2" ]; then export ANDROID_TOOLCHAIN_2ND_ARCH=$gccprebuiltdir/$toolchaindir2 fi unset ANDROID_KERNEL_TOOLCHAIN_PATH case $ARCH in arm) # Legacy toolchain configuration used for ARM kernel compilation toolchaindir=arm/arm-eabi-$targetgccversion/bin if [ -d "$gccprebuiltdir/$toolchaindir" ]; then export ARM_EABI_TOOLCHAIN="$gccprebuiltdir/$toolchaindir" ANDROID_KERNEL_TOOLCHAIN_PATH="$ARM_EABI_TOOLCHAIN": fi ;; arm64) # Legacy toolchain configuration used for ARM kernel compilation toolchaindir=arm/arm-eabi-$targetgccversion2/bin if [ -d "$gccprebuiltdir/$toolchaindir" ]; then export ARM_EABI_TOOLCHAIN="$gccprebuiltdir/$toolchaindir" ANDROID_KERNEL_TOOLCHAIN_PATH="$ARM_EABI_TOOLCHAIN": fi ;; *) # No need to set ARM_EABI_TOOLCHAIN for other ARCHs ;; esac export ANDROID_DEV_SCRIPTS=$T/development/scripts:$T/prebuilts/devtools/tools export ANDROID_BUILD_PATHS=$(get_build_var ANDROID_BUILD_PATHS):$ANDROID_TOOLCHAIN:$ANDROID_TOOLCHAIN_2ND_ARCH:$ANDROID_KERNEL_TOOLCHAIN_PATH$ANDROID_DEV_SCRIPTS: # 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 export PATH=$ANDROID_BUILD_PATHS$PATH unset ANDROID_JAVA_TOOLCHAIN unset ANDROID_PRE_BUILD_PATHS if [ -n "$JAVA_HOME" ]; then export ANDROID_JAVA_TOOLCHAIN=$JAVA_HOME/bin # 第1步骤设置的JAVA_HOME环境变量,就在这个地方被使用了。 export ANDROID_PRE_BUILD_PATHS=$ANDROID_JAVA_TOOLCHAIN: export PATH=$ANDROID_PRE_BUILD_PATHS$PATH fi 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) # needed for building linux on MacOS # TODO: fix the path #export HOST_EXTRACFLAGS="-I "$T/system/kernel_headers/host_include }3.5.4、设置sequence number
function set_sequence_number() { export BUILD_ENV_SEQUENCE_NUMBER=10 }3.6、打印config
function printconfig() { 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 }Example of printconfig
~ end ~