美文网首页Android开发
编译流程(4)

编译流程(4)

作者: xcz1899 | 来源:发表于2018-08-28 09:53 被阅读0次

    Google给出了编译Android的三步骤,分别是:

    1. source build/envsetup.sh:设置环境
    2. lunch aosp_arm-eng:选择目标
    3. make -j16:执行编译 借助-jN参数处理并行任务,N介于编译时所用计算机核心数的1-2倍之间
      下面具体分析这三个步骤:

    1.source流程(加载命令)

    source命令也称为“点命令”,也就是一个点符号(.),其使Shell读入指定的Shell脚本并依次执行脚本中的所有语句。
    先来看看build/envsetup.sh脚本的内容:

    一.加载函数
    1. croot:切换到源码树的根目录
    2. lunch:选择编译板型
    3. m:在源码树的根目录执行make
    4. mm:编译当前目录下的模块,不包含依赖
    5. mmm:编译指定目录下的模块,不包含依赖
    6. mma:编译当前目录下的模块,包含依赖
    7. mmma:编译指定目录下的模块,包含依赖
    8. cgrep:在所有C/C++文件上执行grep
    9. jgrep:在所有Java文件上执行grep
    10. resgrep:在所有res/*.xml文件上执行grep
    11. printconfig:显示当前Build的配置信息

    比如m函数的定义如下:

    #build/envsetup.sh
    function m()
    {
        local T=$(gettop)
        local DRV=$(getdriver $T)
        if [ "$T" ]; then
            $DRV make -C $T -f build/core/main.mk $@
        else
            echo "Couldn't locate the top of the tree.  Try setting TOP."
            return 1
        fi
    }
    
    二.定义3种编译模式:
    #build/envsetup.sh
    VARIANT_CHOICES=(user userdebug eng)
    

    user:权限受限;适用于生产环境
    userdebug:与user类似,但具有root权限和可调试性
    eng: 具有额外调试工具的开发配置

    三. 加载默认的lunch选项到LUNCH_MENU_CHOICES:
    #build/envsetup.sh
    #LUNCH_MENU_CHOICES存放lunch变量,先清空
    unset LUNCH_MENU_CHOICES
    
    add_lunch_combo aosp_arm-eng
    add_lunch_combo aosp_arm64-eng
    ....
    #add_lunch_combo主要是向LUNCH_MENU_CHOICES添加lunch变量
    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)
    }
    

    除了默认的lunch选项外,在“device/厂商/版型”目录中的vendorsetup.sh还有add_lunch_combo的调用,部分摘录如下:

    add_lunch_combo aosp_angler-userdebug
    
    四. 查找所有的vendorsetup.sh脚本并执行:
    #build/envsetup.sh
    #查找的目录层级为4层
    for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \
             `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort`
    do
        echo "including $f"
        . $f
    done
    unset f
    

    2.lunch流程

    由第一步可知,lunch是build/envsetup.sh脚本中定义的用来选择对应的编译项的,下面看看lunch函数都做了哪些事情。

    一.获取编译目标保存到answer变量:
        if [ "$1" ] ; then
            answer=$1
    
    二.根据answer变量从LUNCH_MENU_CHOICES中获取值赋给selection:
        if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ]
        then
            selection=${LUNCH_MENU_CHOICES[$(($answer-1))]}
        fi
    
    三.从selection变量获取product变量
    local product=$(echo -n $selection | sed -e "s/-.*$//") 
    
    四.从selection变量获取VARIANT_CHOICES(eng/user/userdebug)
     local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//")
    
    五.导出宏变量:
        export TARGET_PRODUCT=$product
        export TARGET_BUILD_VARIANT=$variant
        export TARGET_BUILD_TYPE=release
    
    六.调用配置/打印函数
        #set_stuff_for_environment主要就是设置PROMPT_COMMAND,ANDROID_BUILD_PATHS,JAVA_HOME和BUILD_ENV_SEQUENCE_NUMBER等等环境变量
        set_stuff_for_environment
        #printconfig用来打印最终准备好的环境变量
        printconfig 
    

    3.make流程

    3.1 编译入口

    在Android源码根目录下执行make命令,系统会找到根目录下的Makefile文件,里面指向了另外一个mk文件:

    #Makefile
    include build/core/main.mk  
    
    3.2 导入依赖/确定编译模式/定义编译目标/编译
    #build/core/main.mk 
    ....
    #确定shell
    ifdef ANDROID_BUILD_SHELL
    SHELL := $(ANDROID_BUILD_SHELL)
    else
    SHELL := /bin/bash
    endif
    ....
    #检查MAKE版本
    ifneq (1,$(strip $(shell expr $(MAKE_VERSION) \>= 3.81)))
    .PHONY: droid
    DEFAULT_GOAL := droid
    $(DEFAULT_GOAL):
    ....
    #设定默认编译目标
    .PHONY: droid
    DEFAULT_GOAL := droid
    $(DEFAULT_GOAL):
    ....
    #导入工具和编译模块
    include $(BUILD_SYSTEM)/config.mk
    #定义target清除编译文件
    include $(BUILD_SYSTEM)/cleanbuild.mk
    ....
    #确定编译模式 user/userdebug/eng
    user_variant := $(filter user userdebug,$(TARGET_BUILD_VARIANT))
    enable_target_debugging := true
    tags_to_install :=
    ifneq (,$(user_variant))
      ifeq ($(user_variant),userdebug)
        tags_to_install += debug
      else
        enable_target_debugging :=
      endif
    ....
    #查找所有的android.mk
    subdir_makefiles := \
        $(shell build/tools/findleaves.py $(FIND_LEAVES_EXCLUDES) $(subdirs) Android.mk)
    #执行编译
    $(foreach mk, $(subdir_makefiles), $(info including $(mk) ...)$(eval include $(mk)))
    ....
    #定义编译目标 
    .PHONY: ramdisk
    ramdisk: $(INSTALLED_RAMDISK_TARGET)
    

    注意:make update-api

    谷歌对于所有的类和API,分为开方和非开放两种,而开放的类和API,可以通过“Javadoc”标签与源码同步生成“开发文档”;
    当我们修改或者添加一个新的API时,我们有两种方案可以避免出现上述错误.

    1. 将该接口加上非公开的标签:/*{@hide}/;
    2. 在修改后执行:makeupdate-api,将修改内容与API的doc文件更新到一致。同时在frameworks/base/api库下面会产生“.current.txt”文件的差异。

    相关文章

      网友评论

        本文标题:编译流程(4)

        本文链接:https://www.haomeiwen.com/subject/kpjeiftx.html