Android编译系统)——命令执行流程

来源:互联网 发布:网络机柜cad图纸 编辑:程序博客网 时间:2024/05/19 17:51

编译Rom的第一步是source build/envsetup.sh,该步骤将envsetup.sh里的函数声明为当前终端可用的命令,并将所有产品添加至变量LUNCH_MENU_CHOICES里。

编译Rom的第二步是让用户选择他想编译的产品,用户可以使用在source build/envsetup.sh后设置的breakfast或者lunch命令进行选择,接下来我们将详细分析这些命令的执行流程以及执行完breakfast命令或者lunch命令后在会话终端设置的变量

1. 命令执行流程

1.1 breakfast执行流程

流程:

  • 1) 从github上下载cm支持的产品,并添加至产品列表
  • 2) 如果命令参数为空,那么调用lunch函数,让用户选择产品
  • 3) 如果命令参数为1个且$target格式为$product-$build_variant,那么调用lunch $target,这样不需要用户选择产品
  • 4) 如果命令参数为1个且$target格式为$product,那么将其扩展为带build_variant格式的产品,然后调用lunch cm_$target-userdebug,这样不需要用户选择产品
1234567891011121314151617181920212223242526272829303132
target=$1CM_DEVICES_ONLY="true" #只编译CM支持的设备unset LUNCH_MENU_CHOICESadd_lunch_combo full-eng#vendor/cm/vendorsetup.sh 该脚本会从github上下载cm支持的产品,#并添加至LUNCH_MENU_CHOICES变量 ,该变量表示产品列表for f in `/bin/ls vendor/cm/vendorsetup.sh 2> /dev/null`     do        echo "including $f"        . $f      doneunset#如果没有带任何参数,那么调用lunch函数,让用户选择产品if [ $# -eq 0 ]; then         lunchelse#target格式:$product-$build_variant 或者 $product #  示例 cm_i9100-userdebug 或 i9100    echo "z$target" | grep -q "-"    #如果用户输入的产品格式是$product-$build_variant 那么直接调用lunch    if [ $? -eq 0 ]; then         # A buildtype was specified, assume a full device name        lunch $target    else         #如果用户输入的产品格式是$product,        #那么扩展该变量为cm_$target-userdebug格式       # This is probably just the CM model name        lunch cm_$target-userdebug    fifireturn $?

1.2 lunch执行流程

流程:

  • 1) 获取用户指定的产品或者让用户选择产品,并提取$product和$variant
  • 2) 检查是否支持产品
  • 3) 若不支持该产品,从网上下载该产品的相关配置到本地device目录,并再次检查是否支持该产品
  • 4) 若支持该产品,下载产品的最新配置到本地device目录
  • 5) 若还是不支持,告诉用户不支持并退出
  • 6) 设置环境变量export TARGET_PRODUCT,TARGET_BUILD_VARIANT,TARGET_BUILD_TYPE
  • 7) 建立$(OUT_DIR)/target/common目录
  • 8) 设置PROMPT_COMMAND变量,java_home,PATH目录,set_sequence_number
  • 9) 打印选择产品后对应的一些编译配置变量
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
local answerif [ "$1" ] ; then    answer=$1else    #若调用者没有指定产品,那么打印产品列表,让用户选择    print_lunch_menu    echo -n "Which would you like? [full-eng] "    read answerfilocal selection=if [ -z "$answer" ] #默认产品为full-engthen    selection=full-engelif (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#选择的产品为$product-$build_variant格式    elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$")then    selection=$answerfi if [ -z "$selection" ]#selection格式为$product-$build_variantthen    echo    echo "Invalid lunch combo: $answer"    return 1fi export TARGET_BUILD_APPS#提取product变量 product示例cm_i9100local product=$(echo -n $selection | sed -e "s/-.*$//")check_product $product #检查产品是否支持if [ $? -ne 0 ]#若产品不支持then    #if we can't find a product, try to grab it off the CM github    T=$(gettop)    pushd $T > /dev/null    #下载prouct的配置 放在device/$vendor/$product目录    build/tools/roomservice.py $product     popd > /dev/null    check_product $product #再次检查产品是否支持else    #获取最新配置 更新device/$vendor/$product    build/tools/roomservice.py $product truefiif [ $? -ne 0 ]then    echo    echo "** Don't have a product spec for: '$product'"    echo "** Do you have the right repo manifest?"    product=fi#从$product-$build_variant里提取$variantlocal variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")check_variant $variantif [ $? -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 1fi export TARGET_PRODUCT=$productexport TARGET_BUILD_VARIANT=$variantexport TARGET_BUILD_TYPE=release fixup_common_out_dir #建立$(OUT_DIR)/target/common目录 #设置PROMPT_COMMAND变量,java_home,PATH目录,set_sequence_numberset_stuff_for_environment# 打印选择产品后的重要环境变量printconfig

1.3 check_product执行流程

流程:

  • 1) export CM_BUILD CM_BUILD示例:若$1是cm_i9100,则CM_BUILD是i9100
  • 2) 调用get_build_var TARGET_DEVICE
123456789101112131415161718
T=$(gettop)if [ ! "$T" ]; then    echo "Couldn't locate the top of the tree.  Try setting TOP." >&2    returnfi if (echo -n $1 | grep -q -e "^cm_") ; then   CM_BUILD=$(echo -n $1 | sed -e 's/^cm_//g')else   CM_BUILD=fiexport CM_BUILDCALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \    TARGET_PRODUCT=$1 \    TARGET_BUILD_VARIANT= \    TARGET_BUILD_TYPE= \    TARGET_BUILD_APPS= \    get_build_var TARGET_DEVICE > /dev/null

1.4 get_build_var执行流程

调用流程:lunch->check_product->get_build_var TARGET_DEVICE

此时的环境变量有

1)TARGET_PRODUCT:cm_i9100

2)CALLED_FROM_SETUP:true

3)BUILD_SYSTEM:build/core

4)export CM_BUILD=i9100

最终调用build/core/config.mk来完成检测是否支持产品$TARGET_PRODUCT

12345678
T=$(gettop)if [ ! "$T" ]; then    echo "Couldn't locate the top of the tree.  Try setting TOP." >&2    returnfiCALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \ #$1的值可能为TARGET_DEVICE  make --no-print-directory -C "$T" -f build/core/config.mk dumpvar-$1

选择好产品后,可用get_build_var查看产品对应的编译变量,它依赖于以下环境变量

export TARGET_PRODUCT=cm_i9100

export TARGET_BUILD_VARIANT=userdebug

export TARGET_BUILD_TYPE=release

export CM_BUILD=i9100

因此makefile里定义的变量并未添加至环境变量,每次调用get_build_var时,其实是调用config.mk依赖的dumpvar.mk实时计算出编译变量的值

比如说LEX变量 HOST_ARCH变量

1.5 printconfig执行流程

123456
T=$(gettop)if [ ! "$T" ]; then    echo "Couldn't locate the top of the tree.  Try setting TOP." >&2    returnfiget_build_var report_config

最终调用build/core/dumpvar.mk来完成变量的打印

示例:

PLATFORM_VERSION_CODENAME=REL

PLATFORM_VERSION=4.2.2

CM_VERSION=10.1-20130822-UNOFFICIAL-i9100

TARGET_PRODUCT=cm_i9100

TARGET_BUILD_VARIANT=userdebug

TARGET_BUILD_TYPE=release

TARGET_BUILD_APPS=

TARGET_ARCH=arm

TARGET_ARCH_VARIANT=armv7-a-neon

HOST_ARCH=x86

HOST_OS=linux

HOST_OS_EXTRA=Linux-2.6.32-33-generic-x86_64-with-Ubuntu-10.04-lucid

HOST_BUILD_TYPE=release

BUILD_ID=JDQ39E

OUT_DIR=/home/android/tmp/android_out/CyanogenMod

1.5 mm执行流程

1234567891011121314151617181920212223242526
local MM_MAKE=makelocal ARG=for ARG in $@ ; do #如果参数中有mka,那么利用mka进行编译    if [ "$ARG" = mka ]; then        MM_MAKE=mka    fidone#如果处在根目录 利用Android根目录的makefile编译选中目标if [ -f build/core/envsetup.mk -a -f Makefile ]; then     $MM_MAKE $@ else        T=$(gettop)    #找到最近的makfile,即当前目录所在工程的makefile    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关键字确定工程所用的makefile,        #并利用Android根目录的makefile进行编译        ONE_SHOT_MAKEFILE=$M $MM_MAKE -C $T all_modules $@     fifi

1.5 mmm执行流程

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
local MMM_MAKE=makeT=$(gettop)if [ "$T" ]; then    local MAKEFILE=    local MODULES=    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        MODULES=`echo $DIR | sed -n -e 's/.*:\(.*$\)/\1/p' | sed 's/,/ /'`        #提取模块 dir格式:dirname:modulename        if [ "$MODULES" = "" ]; then            MODULES=all_modules        fi        DIR=`echo $DIR | sed -e 's/:.*//' -e 's:/$::'`        #如果指定目录有Android.mk,计算出MAKEFILE变量的值        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"            elif [ "$DIR" = mka ]; then                MMM_MAKE=mka            else                echo "No Android.mk in $DIR."                return 1            fi        fi    done    #使用ONE_SHOT_MAKEFILE关键字确定工程所用的makefile,    #并利用Android根目录的makefile进行编译    ONE_SHOT_MAKEFILE="$MAKEFILE" $MMM_MAKE -C $T $DASH_ARGS $MODULES $ARGSelse    echo "Couldn't locate the top of the tree.  Try setting TOP."fi

2. breakfast或者lunch命令执行后在会话终端定义的变量

在执行完breakfast或者lunch命令后,会在当前终端设置许多变量,这些变量有些只能在当前shell里使用,有些能继续在子shell里使用(用sh执行某个shell脚本即在子shell里)。根据变量定义位置,将变量分为3类:

  • 1) 函数:是在函数定义的变量,但并未用export显示指出,在子shell里不可用,当前shell可用
  • 2) export:导出的环境变量,子Shell也可用
  • 3) 文件:文件里定义的变量
变量类型说明T 
函数 
根目录 
TARGET_BUILD_TYPE 
export
release或者debug 
TARGET_PRODUCT 
export
示例:cm_find5 
TARGET_BUILD_VARIANT 
export
可能的值为user,userdebug,eng 
TARGET_BUILD_APPS 
export
需要编译的App集合 
CM_BUILD 
export
示例find5 
VARIANT_CHOICES 
文件 
(user userdebug eng) 
LUNCH_MENU_CHOICES 
函数 
产品列表 
prebuiltdir 
函数 
$(getprebuilt) 
gccprebuiltdir 
函数 
$(get_abs_build_var ANDROID_GCC_PREBUILTS) 
ANDROID_EABI_TOOLCHAIN 
export
工具链所在目录:以下选项之一 
$ gccprebuiltdir /x86/i686-linux-android-4.6/bin 
$ gccprebuiltdir /arm/arm-linux-androideabi-4.6/bin 
$ gccprebuiltdir /mips/mipsel-linux-android-4.6/bin 
ANDROID_TOOLCHAIN 
export
$ANDROID_EABI_TOOLCHAIN 
ANDROID_QTOOLS 
export
$T/development/emulator/qtools 
ANDROID_DEV_SCRIPTS 
export
$T/development/scripts 
ANDROID_BUILD_PATHS 
export
$(get_build_var ANDROID_BUILD_PATHS): 
$ANDROID_QTOOLS: 
$ANDROID_TOOLCHAIN: 
$ARM_EABI_TOOLCHAIN_PATH: 
$CODE_REVIEWS:$ANDROID_DEV_SCRIPTS:
ARM_EABI_TOOLCHAIN 
export
$gccprebuiltdir/ arm/arm-eabi-4.6/bin 
ARM_EABI_TOOLCHAIN_PATH
函数 
$gccprebuiltdir/ arm/arm-eabi-4.6/bin 
toolchaindir 
函数 
以下三个选项之一 
x86/i686-linux-android-4.6/bin 
arm/arm-linux-androideabi-4.6/bin 
mips/mipsel-linux-android-4.6/bin 
ANDROID_JAVA_TOOLCHAIN 
export
$JAVA_HOME/bin 
ANDROID_PRE_BUILD_PATHS
export
$ANDROID_JAVA_TOOLCHAIN 
ANDROID_PRODUCT_OUT 
export
$(get_abs_build_var PRODUCT_OUT) 
OUT 
export
$ANDROID_PRODUCT_OUT 
ANDROID_HOST_OUT 
export
$(get_abs_build_var HOST_OUT) 
OPROFILE_EVENTS_DIR 
export
$T/external/oprofile/events 
BUILD_ENV_SEQUENCE_NUMBER
export
export BUILD_ENV_SEQUENCE_NUMBER=10 
PROMPT_COMMAND 
export
命令提示符 
CM_DEVICES_ONLY 
函数 
true 表示只支持CM的设备,如果使用breakfast命令会将改变量设置为true 
MODVERSION 
函数 
$(get_build_var CM_VERSION) 
ZIPFILE 
函数 
cm-$MODVERSION.zip 
ZIPPATH 
函数 
$OUT/$ZIPFILE 
TOPFILE 
函数 
build/core/envsetup.mk 

用户下一步将使用mka进行编译,会利用这前两步设置的变量和函数命令,虽然breakfast命令和lunch命令有利用到一些makefile检查选择的产品是否符合要求,但是makefile里的变量都引入到当前shell,仅仅用于检查产品是否符合要求而已。

我们现在了解到breakfast命令会从网上下载产品列表,而lunch命令会下载产品的最新配置,所以我们在使用breakfast命令或者lunch命令时,会觉得时间比较长,如果是本地产品,你可以注释那些检查的代码,这样会很快


转自:http://www.cloudchou.com/android/post-261.html

0 0
原创粉丝点击