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


编译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命令时,会觉得时间比较长,如果是本地产品,你可以注释那些检查的代码,这样会很快。


更多相关文章

  1. Mac OS X系统下android环境变量配置和真机调试
  2. Ubuntu 配置Android SDK NDK环境变量
  3. Android Apk反编译函数对应法则
  4. Android 的一些实用的函数
  5. android binder机制及其源码解析之第二节 重要函数讲解之常用数
  6. Android中共享全局变量
  7. Android studio安装之前配置环境变量
  8. Android SDK的安装与环境变量配置

随机推荐

  1. Android(安卓)Support Multidex原理分析
  2. android 调用系统日历
  3. android 图片叠加效果实现
  4. Android(安卓)发送通知 notification
  5. Android中Intent传值
  6. Android的ArrayAdapter
  7. Android(安卓)NDK之----- C调用Java [Get
  8. docker入门到进阶一
  9. 登录表单和iframe后台架构
  10. docker入门到进阶四