Android 编译(1)——Android编译步骤梳理

张毅
2023-12-01

Android编译步骤

1 source build/envsetup.sh
2 lunch xxx-eng/xxx-userdebug 选择要编译的平台选项配置
3 make 编译

envsetup.sh

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.

执行. build/envsetup.sh或者source build/envsetup.sh还有添加下面这些命令到当前环境下:

# Get the value of a build variable as an absolute path.
function get_abs_build_var()

# Get the exact value of a build variable.
function get_build_var()

# check to see if the supplied product is one we can build
function check_product()

# check to see if the supplied variant is valid
function check_variant()

function setpaths()
function printconfig()
function set_stuff_for_environment()
function set_sequence_number()
function settitle()
function addcompletions()
function choosetype()
function choosevariant()
function choosecombo()
function add_lunch_combo()
function print_lunch_menu()
function gettop
...

除此之外还会包含device目录和vendor目录下的vendorsetup.sh

# 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
done
unset f
including device/generic/mini-emulator-armv7-a-neon/vendorsetup.sh
including device/generic/mini-emulator-arm64/vendorsetup.sh
including device/lge/hammerhead/vendorsetup.sh
including device/lge/mako/vendorsetup.sh
including device/htc/flounder/vendorsetup.sh

vendorsetup.sh

vendorsetup.sh的内容是添加的是编译平台的选项配置,如下,调用add_lunch_combo命令添加对应的编译选项:

add_lunch_combo m_e_arm-userdebug

add_lunch_combo命令

# 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)
}

lunch命令

lunch命令会打印当前检索到的lunch选项,解析传入的编译选项,检查对应的product和variant,配置对应的环境变量:
TARGET_PRODUCT
TARGET_BUILD_VARIANT
TARGET_BUILD_TYPE

function lunch()
{
    local answer

    if [ "$1" ] ; then
        answer=$1
    else
        print_lunch_menu
        echo -n "Which would you like? [aosp_arm-eng] "
        read answer
    fi

    local selection=

    if [ -z "$answer" ]
    then
        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/-.*$//")
    check_product $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/^[^\-]*-//")
    check_variant $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
    printconfig
}

环境变量TARGET_PRODUCT的解析过程可以参考如下文章:

<<Android Makefile中是如何识别 TARGET_PRODUCT 的>>
https://www.cnblogs.com/leaven/p/4337887.html

Android Makefile解析TARGET_PRODUCT后得到PRODUCT_DEVICE,并赋值给TARGET_DEVICE。
通过TARGET_DEVICE,编译系统配置了目标系统的编译属性、决定了目标文件的输出路径、添加了指定目录下的编译文件。

以上是从编译的角度解析了Android的PRODUCT,分析了编译系统是如何解析我们的特定的Product。
正向添加Android Product的可以参考如下文章:

<<01 Android系统之添加Product>>
https://blog.csdn.net/feit2417/article/details/105189947

Android makefile

inherit函数

1、继承通过$1参数传入的所有变量;
2、在 .INHERITS_FROM 变量中记录下这些继承关系;
3、在 ALL_PRODUCTS 变量中标识出已经被访问过的节点。

#
# $(1): product to inherit
#
# Does three things:
#  1. Inherits all of the variables from $1.
#  2. Records the inheritance in the .INHERITS_FROM variable
#  3. Records that we've visited this node, in ALL_PRODUCTS
#
define inherit-product
  $(foreach v,$(_product_var_list), \
      $(eval $(v) := $($(v)) $(INHERIT_TAG)$(strip $(1)))) \
  $(eval inherit_var := \
      PRODUCTS.$(strip $(word 1,$(_include_stack))).INHERITS_FROM) \
  $(eval $(inherit_var) := $(sort $($(inherit_var)) $(strip $(1)))) \
  $(eval inherit_var:=) \
  $(eval ALL_PRODUCTS := $(sort $(ALL_PRODUCTS) $(word 1,$(_include_stack))))
endef
device/companyName/platformName/device.mk
$(call inherit-product, frameworks/native/build/tablet-7in-hdpi-1024-dalvik-heap.mk)

TBC

 类似资料: