RK3576 Android15 构建脚本(build.sh)全解析

电子说

1.4w人已加入

描述

 

 

 

 

 

 

一、脚本整体定位

 

 

该脚本是瑞芯微RK3576平台基于Android 15的自动化构建脚本,整合了UBootKernel(含驱动)、Android系统、OTA包、update.img固件等全流程构建逻辑,是平台固件编译的核心入口。开发者掌握该脚本,能精准控制编译流程、定位编译失败点、定制化构建策略(如仅编译内核/UBoot、调整编译参数),是RK3576 Android开发调试的核心抓手。

rk3576

 

 

 

二、脚本核心知识点拆解

 

 

1. 脚本基础框架(Shell脚本核心)

 

 

脚本头声明#!/bin/bash 声明脚本使用Bash解释器执行,是Linux Shell脚本的标准开头。

 

 

用法函数(usage:定义脚本参数说明,当传入非法参数或执行-h/--help(隐式)时打印用法并退出,提升脚本易用性。

 

 

知识点:Shell函数定义、echo输出格式化、exit退出码(exit 1表示异常退出)。

 

 

2. 变量初始化(构建参数预设)

 

 

脚本开头定义了一系列布尔型/字符型变量,作为构建开关和参数容器:

 

 

变量名

 

 

作用

 

 

BUILD_UBOOT

 

 

UBoot编译开关(默认false

 

 

BUILD_KERNEL_WITH_CLANG

 

 

内核是否用Clang编译(默认false

 

 

BUILD_KERNEL

 

 

内核编译开关(默认false

 

 

BUILD_ANDROID

 

 

Android系统编译开关(默认false

 

 

BUILD_UPDATE_IMG

 

 

update.img固件打包开关(默认false

 

 

BUILD_OTA

 

 

OTA升级包编译开关(默认false

 

 

BUILD_PACKING

 

 

编译产物归档开关(默认false

 

 

KERNEL_DTS

 

 

内核设备树文件名(默认空,后续从环境变量读取)

 

 

BUILD_JOBS

 

 

编译并行任务数(默认16,控制make -j的并发数)

 

 

知识点:Shell变量赋值、布尔型变量的Shell表达(true/false为字符串,非原生布尔)。

 

 

3. 命令行参数解析(getopts

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
while getopts "UCKABpouvV" argdo    case $arg in        U) BUILD_UBOOT=true ;;        C) BUILD_KERNEL=true; BUILD_KERNEL_WITH_CLANG=true ;;        # ... 其他参数处理        ?) usage ;; # 非法参数调用usage    esacdone

核心知识点:getoptsShell内置的参数解析工具,支持短参数(如-U-K)解析:

 

 

UCKABpouvV 中,带:的字符(如v)表示参数后需跟值(如-v userdebug);

 

 

case分支匹配参数,实现参数变量的映射;

 

 

非法参数触发usage函数,保证参数合法性。

 

 

4. 环境前置检查与初始化

 

 

1)编译环境校验

 

 

  •  
  •  
  •  
  •  
  •  
  •  
if [ -z "$TARGET_RELEASE" ]; then    echo "Please lunch your product first! e.g."    echo "source build/envsetup.sh"    echo "lunch rk3588_u-trunk_staging-userdebug"    (return 1 2>/dev/null) || exit 1fi

知识点:

 

 

[ -z "$VAR" ] 检查变量是否为空;

 

 

TARGET_RELEASEAndroid编译环境的核心变量,需通过lunch命令初始化,脚本强制要求先执行source build/envsetup.sh && lunch,避免环境缺失导致编译失败;

 

 

(return 1 2>/dev/null) || exit 1 兼容脚本“source执行直接执行两种场景(source执行时return,直接执行时exit)。

 

 

2)编译工具链配置

 

 

  •  

	

知识点:

 

 

export设置环境变量,作用于当前Shell及子进程;

 

 

Android编译对JDK/Clang版本强依赖,脚本固化路径避免版本错误;

 

 

ANDROID_BUILD_TOPAndroid源码顶层路径,由envsetup.sh定义。

 

 

3Android编译变量读取

 

 

  •  
  •  
  •  
BUILD_NUMBER=`get_build_var BUILD_NUMBER`UBOOT_DEFCONFIG=`get_build_var PRODUCT_UBOOT_CONFIG`KERNEL_DEFCONFIG=`get_build_var PRODUCT_KERNEL_CONFIG`

知识点:

 

 

get_build_varAndroid编译系统的工具函数,用于读取Android.mk/BoardConfig.mk中定义的变量;

 

 

脚本通过该方式动态获取产品配置(如UBoot默认配置、内核defconfig),而非硬编码,适配多产品/多版本。

 

 

5. 分模块编译逻辑

 

 

1UBoot编译

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
if [ "$BUILD_UBOOT" = true ] ; then    cd u-boot && make clean &&  make mrproper &&  make distclean && make $UBOOT_DEFCONFIG && ./make.sh && cd -    if [ $? -eq 0 ]; then        echo "Build uboot ok!"    else        echo "Build uboot failed!"        exit 1    fifi

核心知识点:

 

 

make clean/mrproper/distcleanUBoot编译清理,逐步清理临时文件/配置/编译产物,保证编译环境干净;

 

 

make $UBOOT_DEFCONFIG:加载UBoot默认配置(如rk3576_defconfig);

 

 

./make.sh:瑞芯微定制的UBoot编译脚本(替代原生make);

 

 

$? -eq 0:检查上一条命令的退出码(0为成功,非0为失败),失败则立即退出脚本,避免无效编译。

 

 

2Kernel编译(含驱动)

 

 

① 编译器适配(Clang/GCC

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
if [ "$BUILD_KERNEL_WITH_CLANG" = true ] ; then    if [ "$KERNEL_ARCH" = "arm64" ]; then        ADDON_ARGS="CROSS_COMPILE=aarch64-linux-gnu- LLVM=1 LLVM_IAS=1"    else        ADDON_ARGS="CC=clang LD=ld.lld"    fifi

知识点:

 

 

ARM64架构内核用Clang编译时,需指定LLVM=1 LLVM_IAS=1(启用LLVM汇编器);

 

 

32ARM架构直接指定CC=clang LD=ld.lld

 

 

ADDON_ARGS整合编译参数,后续传递给make,实现参数复用。

 

 

② 内核主编译

 

 

  •  
cd $LOCAL_KERNEL_PATH && make clean && make $ADDON_ARGS ARCH=$KERNEL_ARCH $KERNEL_DEFCONFIG && make $ADDON_ARGS ARCH=$KERNEL_ARCH $KERNEL_DTS.img -j$BUILD_JOBS && cd -

知识点:

 

 

$LOCAL_KERNEL_PATH:内核源码路径(如kernel-5.10),由PRODUCT_KERNEL_VERSION动态获取;

 

 

$KERNEL_DTS.img:编译指定设备树的内核镜像(RK平台内核镜像与DTS绑定);

 

 

-j$BUILD_JOBS:并行编译,默认16线程,可通过-J参数调整,平衡编译速度与系统负载。

 

 

③ 外设驱动编译(WiFi/摄像头)

 

 

WiFi驱动:编译external/wifi_driver路径下的驱动,生成.ko文件并剥离调试信息(llvm-strip --strip-debug);

 

 

摄像头驱动:编译hardware/rockchip/rvcam/drivers路径下的驱动,拷贝到预编译目录;

 

 

知识点:内核模块(.ko)编译需指定M=$PWD(模块源码路径),依赖内核源码的编译环境;llvm-strip剥离调试信息减小文件体积。

 

 

3Android系统编译

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
if [ "$BUILD_ANDROID" = true ] ; then    if [ "$BUILD_OTA" = true ] ; then        # OTA包编译逻辑:make → make dist → mkimage_ab.sh/mkimage.sh    else        # 普通编译:make installclean → make -j$BUILD_JOBS    fifi

核心知识点:

 

 

make installclean:清理out目录下的临时产物,保留配置,避免编译缓存导致的问题;

 

 

make dist:生成OTA包所需的target_files.zip(包含系统分区镜像);

 

 

mkimage_ab.sh/mkimage.sh:瑞芯微定制的镜像打包脚本,区分AB分区(无缝更新)和非AB分区;

 

 

每一步编译后检查$?,失败则退出,保证编译链路的可靠性。

 

 

4)固件打包(update.img/OTA

 

 

① update.img打包

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
if [ "$BUILD_UPDATE_IMG" = true ] ; then    cp -f $IMAGE_PATH/* $PACK_TOOL_DIR/rockdev/Image/    if [[ $TARGET_PRODUCT =~ "PX30" ]]; then        cd $PACK_TOOL_DIR/rockdev && ./mkupdate.sh px30 Image    # ... 其他平台适配    fi    mv $PACK_TOOL_DIR/rockdev/update.img $IMAGE_PATH/ -ffi

知识点:

 

 

PACK_TOOL_DIR=RKTools/linux/Linux_Pack_Firmware:瑞芯微官方打包工具路径;

 

 

mkupdate.sh:根据平台(PX30/RK356x/RK3576)调用不同的打包逻辑,生成可用于量产的update.img

 

 

正则匹配[[ $TARGET_PRODUCT =~ "PX30" ]]:适配多产品平台,提升脚本通用性。

 

 

② OTA包打包

 

 

AB分区:make dist生成target_files.zip → mkimage.sh ota生成OTA.zip

 

 

AB分区:make dist → mkimage_ab.sh ota生成AB格式OTA包;

 

 

知识点:Android OTA包依赖target_files.zip,包含分区镜像、升级脚本等,是系统空中升级的核心文件。

 

 

5)编译产物归档(BUILD_PACKING

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
if [ "$BUILD_PACKING" = true ] ; then    mkdir -p $STUB_PATH/IMAGES/    cp $IMAGE_PATH/* $STUB_PATH/IMAGES/    # 生成补丁/提交清单/编译命令日志    .repo/repo/repo forall  -c "$PROJECT_TOP/device/rockchip/common/gen_patches_body.sh"    cp out/commit_id.xml $STUB_PATH/manifest_${DATE}.xmlfi

知识点:

 

 

STUB_PATH:按产品_版本_时间命名归档路径,便于版本追溯;

 

 

repo forall:遍历所有Git仓库,执行补丁生成脚本,记录代码修改;

 

 

归档内容包含镜像文件、编译日志、内核配置、Git提交清单,用于版本管理和问题复现。

 

 

6. 辅助逻辑(路径/时间/日志)

 

 

路径格式化STUB_PATH="$(echo $STUB_PATH | tr '[]' '[]')" 将路径转为大写,统一命名规范;

 

 

时间戳DATE=$(date  +%Y%m%d.%H%M) 生成时间戳,用于归档路径和版本标识;

 

 

日志输出:大量echo "-------------------KERNEL_VERSION:$KERNEL_VERSION" 输出关键参数,便于编译过程调试。

 

 

三、脚本整体流程图

 

 

 

 

 

rk3576

四、掌握该脚本对开发调试的意义

 

 

1. 精准控制编译流程,提升开发效率

 

 

开发阶段无需全量编译:调试UBoot时仅执行./build.sh -U,调试内核时执行./build.sh -K,调试Android时执行./build.sh -A,避免全量编译耗时(RK3576全量编译需1-2小时);

 

 

自定义编译参数:通过-J调整并发数(如低配机器执行./build.sh -A -J 8),通过-v指定编译版本(./build.sh -A -v user),适配不同调试场景。

 

 

2. 快速定位编译失败点

 

 

脚本每一步编译后检查$?并输出日志,失败时直接退出并打印原因(如“Build kernel failed!”);

 

 

开发者可根据日志定位失败模块:

 

 

UBoot失败:检查UBOOT_DEFCONFIG是否正确、u-boot/make.sh是否有语法错误;

 

 

Kernel失败:检查KERNEL_DTS是否存在、Clang版本是否匹配、驱动编译依赖;

 

 

Android失败:检查lunch命令是否正确、Android源码是否完整。

 

 

3. 定制化适配产品需求

 

 

新增产品/版本:修改PRODUCT_KERNEL_DTS/PRODUCT_UBOOT_CONFIG等变量,或在参数解析分支中新增产品适配逻辑;

 

 

定制固件打包:修改BUILD_PACKING逻辑,添加自定义归档内容(如新增模块的编译产物);

 

 

适配新编译工具:调整Clang/JDK路径,兼容新版编译链(如升级Clang版本时修改clang-r530567为新路径)。

 

 

4. 理解RK平台编译体系,掌握量产固件制作

 

 

脚本整合了瑞芯微定制工具([mkupdate.sh](mkupdate.sh)[pack_resource.sh](pack_resource.sh))和Android原生编译逻辑,是RK平台源码量产固件的完整链路;

 

 

掌握脚本后,可自主制作OTA包、update.img量产固件,适配工厂烧录/用户升级场景;

 

 

归档逻辑(BUILD_PACKING)便于版本管理,调试时可追溯某版本固件的编译参数/代码提交/内核配置,快速复现线上问题。

 

 

5. 适配AB分区/OTA升级等高级特性

 

 

脚本区分AB分区(BOARD_USES_AB_IMAGE)和非AB分区的编译逻辑,开发者可通过脚本理解Android 15无缝更新(AB OTA)的实现方式;

 

 

掌握OTA包生成流程,可定制升级脚本(如添加分区校验、预安装脚本),满足产品升级需求。

 

 

总结

 

 

该脚本是RK3576 Android 15平台的编译总控中心,涵盖了从环境初始化到固件量产的全流程。开发者掌握其逻辑,不仅能高效调试各模块(UBoot/Kernel/Android),还能定制化适配产品需求,是RK3576平台开发调试的核心技能。同时,脚本的模块化设计、参数解析、错误处理等Shell编程技巧,也为嵌入式Linux/Android开发提供了通用参考。

 

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分