Android系统编译环境变量的设置

本文详细介绍了Android系统编译前的准备,包括envsetup.sh脚本的作用,它负责初始化编译环境并加载vendorsetup.sh,添加lunch选项。lunch命令解析了如何选择设备型号和编译类型,并通过set_stuff_for_environment配置环境,最后check_product确保选定产品合法。内容深入到build系统的核心文件,揭示了Android编译环境的配置流程。

编译之前我们一般都怎么做?

我们在编译android之前,通常会输入一些命令,比如:

. ./bulid/envsetup.sh

...

lunch

...

make

...


这里的envsetup.sh就是设置android的编译环境,初始化各种变量,比如设备类型什么的,下面是我在我的板子上执行上述命令的结果:

mic@micpc:~/work/android4.0.4$ . ./build/envsetup.sh 
including device/moto/stingray/vendorsetup.sh
including device/moto/wingray/vendorsetup.sh
including device/samsung/smdk4x12/vendorsetup.sh
including sdk/bash_completion/adb.bash

##这里看到,加载envsetup.sh后会加载device目录下其他的一些vendorsetup.sh过来。
##另外adb.bash是什么?我也不清楚,看看老罗怎么说。
##“在sdk/bash_completion目录下的adb.bash文件也会加载到当前终端来,它是用来实现adb命令的bash completion功能的。
##也就是说,加载了该文件之后,我们在运行adb相关的命令的时候,通过按tab键就可以帮助我们自动完成命令的输入”


#然后我们又执行了lunch命令,这个命令是在envsetup.sh中实现的。
mic@micpc:~/work/android4.0.4$ lunch

You're building on Linux

Lunch menu... pick a combo:
     1. full-eng
     2. full_x86-eng
     3. vbox_x86-eng
     4. full_stingray-userdebug
     5. full_wingray-userdebug
     6. full_smdk4x12-userdebug
     7. full_smdk4x12-eng

Which would you like? [full-eng] 6

##可以看到,终端输出了一个菜单,并让我们选择一个选项,我选择的是6,然后就会打印出如下信息,这些变量就是我们编译前要设置好到系统变量。通过这些变量,
##我们就配置好了android的编译环境。

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.0.4
TARGET_PRODUCT=full_smdk4x12
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_BUILD_TYPE=release
BUILD_ID=IMM76D
============================================

envsetup.sh干啥用?

/bulid/envsetup.sh这个脚本中实现了很多功能函数,上面的lunch,还有m,mm,mmm等。

加载vendorsetup.sh,添加lunch

在envsetup.sh脚本的最后面有一段,

# Execute the contents of any vendorsetup.sh files we can find.
for f in `/bin/ls vendor/*/vendorsetup.sh vendor/*/*/vendorsetup.sh device/*/*/vendorsetup.sh 2> /dev/null`
do
    echo "including $f"
    . $f
done
unset f

它的作用是遍历 vendor目录和device目录下的vendorsetup.sh,

1.通过echo把这个vnedorsetup.sh打印出来,就是我们前面看到的"6. full_smdk4x12-userdebug"这种东西

2.通过.(source)加载这个vendorsetup.sh


其实vendorsetup.sh的作用就是添加相应的设备型号及其编译类型支持到Lunch菜单中去。比如:

work/android4.0.4/device/samsung/smdk4x12/vendrosetup.sh内容如下

add_lunch_combo full_smdk4x12-userdebug
add_lunch_combo full_smdk4x12-eng

我们看到它通过add_lunch_combo来添加设备型号等信息的,add_lunch_combo在哪呢?答案还是在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)
}

# add the default one here
add_lunch_combo full-eng                      ##看这里,不就是lunch的最开始的打印信息吗,原来它在这里
add_lunch_combo full_x86-eng                  ##这里其实就是初始化LUNCH_MENU_CHOICES数组,里面默认有
add_lunch_combo vbox_x86-eng                  ##三个选项,full-eng full_x86-eng vbox_x86-eng

我们从这个函数的调用来了解它的工作过程。比如
add_lunch_combo full_smdk4x12-userdebug
可见add_lunch_combo是这个函数的名字,full_smdk4x12-userdebug是这个函数的第一个参数。

在函数中,把第一个参数的值给了一个新的变量new_combo。然后通过遍历LUNCH_MENU_CHOICES这个数组,查找这个数组中是否已经有相同的选项了。

只有在没有添加过的情况下才会添加一个新的选项到LUNCH_MENU_CHOICES数组中。

${LUNCH_MENU_CHOICES[@]}表示数组LUNCH_MENU_CHOICES的所有元素。


lunch的实现解析

当我们输入lunch后,等待我们输入一个编号,比如我输入的是6,这个过程是什么样的呢?我们来看看lunch的实现。


function lunch()
{
    local answer

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

    local selection=

    if [ -z "$answer" ]
    then
        selection=full-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
}

1.lunch执行的时候,可以带参数执行,也可以先不带参数,比如

我们可以先lunch,回车,这时候会让你输入一个参数,我们再输入一个6或者其他;

我们也可以直接输入lunch 6,这样也是一样的。所以,lunch开始的时候判断执行lunch时带没带参数,如果带了参数,那么把参数赋给变量answer

2.对answer进行检查,判断answer是否为空,如果为空默认selection为full-eng;如果不为空,有三种情况:

   (1)数字:输入数字就像我们输入"6",要保证我们输入的数字不大于lunch菜单项的总数,根据这个数字去LUNCH_MENU_CHOICES这个数组中去获取相应的selection,即获取相应的设备型号,编译类型等信息。

mic@micpc:~/work/android4.0.4$ lunch 6

   (2)非数字:就像如下这种情况,需要正确输入格式<product>-<variant>。其中<product>表示设备型号,而<variant>表示编译类型。

mic@micpc:~/work/android4.0.4$ lunch full_smdk4x12-userdebug

   (3)其他情况:这种情况就是非法情况了,那样selection的值就为空,那么下面lunch就不会向下执行了。

3.解析selection,我们上面就是为了获取selection。通过sed命令分别把<product>和<variant>解析出来存到变量product和变量variant中。得到变量后就要对变量进行检查,看它是否合法,所以会调用check_product $product 和check_variant $variant ,不合发会打印出出错信息。


4.获得合法的product和variant之后,

    export TARGET_PRODUCT=$product
    export TARGET_BUILD_VARIANT=$variant
    export TARGET_BUILD_TYPE=release
把变量付给TARGET_PRODUCT,TARGET_BUILD_VARINAT等变量,并通过export导出供其他人使用。


5.调用set_stuff_for_environment函数来配置环境,例如设置Java SDK路径和交叉编译工具路径等。(老罗)


6.调用printconfig函数来把设置好的配置打印出来,就是我们看到的

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.0.4
TARGET_PRODUCT=full_smdk4x12
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_BUILD_TYPE=release
BUILD_ID=IMM76D
============================================


check_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
    CALLED_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
    # hide successful answers, but allow the errors to show
}

gettop是用来返回android源码根目录。老罗说“函数gettop用来返回Android源代码工程的根目录。函数check_product需要在Android源代码工程根目录或者子目录下调用。否则的话,函数check_product就出错返回。”。

CALLED_FROM_SETUP         ##如果这个值为true,说明接下来的make使用来初始化android编译环境
<pre name="code" class="plain">BUILD_SYSTEM              ##android编译系统核心目录
TARGET_PRODUCT            ##要检查的产品名称,也就是我们调用参数是传递的第一个参数$1


使用get_build_var来检查TARGET_PRODUCT指定的产品是否合法。为啥参数是TARGET_DEVICE???

# Get the exact value of a build variable.
function get_build_var()
{
    T=$(gettop)
    if [ ! "$T" ]; then
        echo "Couldn't locate the top of the tree.  Try setting TOP." >&2
        return
    fi
    CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
      make --no-print-directory -C "$T" -f build/core/config.mk dumpvar-$1
}
可以看到,指定目录为android源码根目录调用make,执行build/core/config.mk,目标是dumpvar-TARGET_DEVICE。

bulid/core/config.mk内容多,截取一部分。


# ---------------------------------------------------------------
# Define most of the global variables.  These are the ones that
# are specific to the user's build configuration.
include $(BUILD_SYSTEM)/envsetup.mk

# Boards may be defined under $(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)
# or under vendor/*/$(TARGET_DEVICE).  Search in both places, but
# make sure only one exists.
# Real boards should always be associated with an OEM vendor.
board_config_mk := \
	$(strip $(wildcard \
		$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)/BoardConfig.mk \
		device/*/$(TARGET_DEVICE)/BoardConfig.mk \
		vendor/*/$(TARGET_DEVICE)/BoardConfig.mk \
	))
ifeq ($(board_config_mk),)
  $(error No config file found for TARGET_DEVICE $(TARGET_DEVICE))
endif
ifneq ($(words $(board_config_mk)),1)
  $(error Multiple board config files for TARGET_DEVICE $(TARGET_DEVICE): $(board_config_mk))
endif
include $(board_config_mk)
TARGET_DEVICE_DIR := $(patsubst %/,%,$(dir $(board_config_mk)))
board_config_mk :=
.....
.....
include $(BUILD_SYSTEM)/dumpvar.mk 

主要功能是加载3个文件:

1.include $(BUILD_SYSTEM)/envsetup.mk

2.include $(board_config_mk)

3.include $(BUILD_SYSTEM)/dumpvar.mk

老罗说“

上述代码主要就是将envsetup.mk、BoardConfig,mk和dumpvar.mk三个Makefile片段文件加载进来。其中,envsetup.mk文件位于$(BUILD_SYSTEM)目录中,也就是build/core目录中,BoardConfig.mk文件的位置主要就是由环境变量TARGET_DEVICE来确定,它是用来描述目标产品的硬件模块信息的,例如CPU体系结构。环境变量TARGET_DEVICE用来描述目标设备,它的值是在envsetup.mk文件加载的过程中确定的。一旦目标设备确定后,就可以在$(SRC_TARGET_DIR)/board/$(TARGET_DEVICE)、device/*/$(TARGET_DEVICE)和vendor/*/$(TARGET_DEVICE)目录中找到对应的BoradConfig.mk文件。注意,变量SRC_TARGET_DIR的值等于build/target。最后,dumpvar.mk文件也是位于build/core目录中,它用来打印已经配置好的编译环境信息。”


中间有些过程我还没有理解,但是最终会调用到device/samsung/smdk4x12/full_smdk4x12.mk

# Discard inherited values and use our own instead.
PRODUCT_NAME := full_smdk4x12
PRODUCT_DEVICE := smdk4x12
PRODUCT_MANUFACTURER := S.LSI Division, TOPEET Electronics Co., Ltd.
PRODUCT_BRAND := Android
PRODUCT_MODEL := iTOP-4412
这里指定了PRODUCT_DEVICE :=smdk4x12,所以就会调用到device/samsung/smdk4x12/BoardConfig.mk

它描述了产品的Boot Loader、Kernel、CPU体系结构、CPU ABI和Opengl加速等信息。




VARIANT_CHOICES=(user userdebug eng)

# check to see if the supplied variant is valid
function check_variant()
{
    for v in ${VARIANT_CHOICES[@]}
    do
        if [ "$v" = "$1" ]
        then
            return 0
        fi
    done
    return 1
}


这个函数表示在VARIANT_CHOICES这个数组中,分别用数组中的元素user,userdebug,eng来和参数比较。

这三个值user、userdebug和eng。其中,user表示发布版本,userdebug表示带调试信息的发布版本,而eng表标工程机版本。





<think>首先,用户的问题是关于设置Android编译环境所需的环境变量的。具体来说,他们想知道如何设置这些环境变量。 从系统级指令中,我需要: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户提供了几个引用,这些引用是关于Android环境变量配置的: - 引用[1]:关于JDK、JRE和SDK环境变量配置。 - 引用[2]:使用docker构建Android编译环境。 - 引用[3]:设置FFmpeg的环境变量。 - 引用[4]:Ubuntu18.04构建Android8.0编译环境。 用户的问题焦点是设置Android编译所需的环境变量。核心环境变量包括: - `JAVA_HOME`:指向JDK安装目录。 - `ANDROID_HOME` 或 `ANDROID_SDK_ROOT`:指向Android SDK目录。 - `PATH`:添加JDK和Android SDK的bin目录。 步骤: 1. 安装JDK并设置`JAVA_HOME`。 2. 安装Android SDK并设置`ANDROID_HOME`。 3. 更新`PATH`变量以包括JDK和SDK的bin目录。 4. 可能还需要设置其他变量如`ANDROID_NDK_HOME`,如果使用NDK的话。 在回答中,我需要引用提供的参考来支持我的回答。例如: - 引用[1]提到JDK和SDK配置。 - 引用[3]提到编辑环境变量文件如`.bash_profile`。 - 引用[4]提到在特定目录下执行命令。 结构回答: - 开头解释环境变量的重要性。 - 逐步指导如何设置每个环境变量。 - 包括示例命令或代码块。 - 结束时生成相关问题。 使用中文回答。 最后,生成相关问题,基于系统指令示例。 完整回答结构: 1. 介绍:简要说明Android编译环境需要设置的环境变量。 2. 详细步骤: - 设置JDK环境变量。 - 设置Android SDK环境变量。 - 更新PATH。 - 验证设置。 3. 示例代码块:展示如何编辑环境变量文件。 4. 引用:在相关部分添加引用标识。 5. 相关问题:在最后生成几个相关问题。</think>### Android编译环境所需的环境变量设置指南 设置Android编译环境的环境变量是确保编译工具正确运行的关键步骤。主要涉及配置JDK(Java Development Kit)和Android SDK的环境变量,包括`JAVA_HOME`、`ANDROID_HOME`(或`ANDROID_SDK_ROOT`)以及更新`PATH`变量。以下我将逐步指导您完成设置过程,基于标准Android开发实践和相关引用。操作假设您使用的是Linux系统(如Ubuntu),但Windows或macOS的流程类似,需调整文件路径和命令。 #### 1. **设置JDK环境变量** JDK是编译Android应用的基础,需设置`JAVA_HOME`指向JDK安装目录,并将JDK的`bin`目录添加到`PATH`中。 - **步骤**: - 确认JDK已安装:运行`java -version`检查版本。如果未安装,可从Oracle或OpenJDK官网下载。 - 编辑环境变量文件:使用文本编辑器(如vim)打开用户级配置文件(例如`~/.bashrc`或`~/.bash_profile`)。 ```bash vim ~/.bashrc # 或 ~/.bash_profile ``` - 添加以下行(替换`/path/to/jdk`为您的JDK实际路径,如`/usr/lib/jvm/java-11-openjdk-amd64`): ```bash export JAVA_HOME=/path/to/jdk export PATH=$JAVA_HOME/bin:$PATH ``` - 保存文件并应用更改: ```bash source ~/.bashrc ``` - **验证**:运行`echo $JAVA_HOME`和`java -version`,应输出JDK路径和版本信息。 - 引用支持:类似引用[1]中提到的JDK配置,环境变量需指向JDK而非JRE以确保编译功能[^1]。 #### 2. **设置Android SDK环境变量** Android SDK包含编译工具、平台库等。设置`ANDROID_HOME`指向SDK目录,并添加SDK工具到`PATH`。 - **步骤**: - 确认SDK已安装:Android Studio自动安装SDK,或手动下载SDK命令行工具。 - 编辑环境变量文件(同上): ```bash vim ~/.bashrc ``` - 添加以下行(替换`/path/to/android-sdk`为您的SDK路径,如`~/Android/Sdk`): ```bash export ANDROID_HOME=/path/to/android-sdk export PATH=$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$PATH ``` - 注意:`tools`和`platform-tools`是SDK的关键子目录,包含`adb`、`sdkmanager`等工具。 - 保存并应用更改: ```bash source ~/.bashrc ``` - **验证**:运行`echo $ANDROID_HOME`和`adb version`,应输出路径和工具版本。 - 引用支持:引用[1]强调SDK环境变量配置的重要性,特别是`ANDROID_HOME`的路径设置[^1]。引用[3]展示了类似方法编辑`~/.bash_profile`来添加工具目录到`PATH`[^3]。 #### 3. **可选:设置NDK或其他工具变量** 如果编译涉及本地代码(如C/C++),还需设置Android NDK(Native Development Kit)环境变量。 - **步骤**: - 编辑`~/.bashrc`文件: ```bash export ANDROID_NDK_HOME=/path/to/android-ndk # 替换为您的NDK路径 export PATH=$ANDROID_NDK_HOME:$PATH ``` - 应用更改:`source ~/.bashrc`。 - 引用支持:引用[4]提到在特定平台(如rockchip)的编译环境中,可能需要额外工具链路径[^4]。 #### 4. **验证整个环境** 运行以下命令检查所有变量: ```bash echo $JAVA_HOME && echo $ANDROID_HOME && java -version && adb version ``` 输出应显示正确路径和工具版本。如果编译错误(如“command not found”),请检查路径拼写或重新加载文件。 #### 常见问题与提示 - **文件选择**:使用`~/.bashrc`(针对bash shell)或`~/.profile`(通用)。在Ubuntu中,`.bashrc`更常用。 - **路径示例**: - JDK路径:通常位于`/usr/lib/jvm/`下。 - SDK路径:Android Studio默认安装到`~/Android/Sdk`。 - **Docker环境**:如果使用docker构建编译环境(如引用[2]所述),环境变量需在Dockerfile中设置,例如: ```dockerfile ENV JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 ENV ANDROID_HOME=/opt/android-sdk ENV PATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME/tools ``` 这能确保容器内变量一致[^2]。 - **持久性**:环境变量设置后,重启终端或系统仍有效。如果问题持续,检查文件权限或使用`export`命令临时测试。 通过以上步骤,您的Android编译环境应能正确处理Java和Android工具链。如果编译特定项目(如AOSP),还需参考项目文档添加额外变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值