Rockchip RK3566 - orangepi-build脚本分析

在《Rockchip RK3566 - orangepi-build编译》我们介绍了SDK的编译流程,本节将会对编译脚本进行深入的分析。

----------------------------------------------------------------------------------------------------------------------------

开发板 :Orange Pi 3B开发板eMMC32GBLPDDR48GB
显示屏 :15.6英寸HDMI接口显示屏u-boot2017.09linux5.10
----------------------------------------------------------------------------------------------------------------------------

一、build.sh分析

orangepi-build编译命令是由build.sh脚本实现的,其脚本相对来说比较长,这里我们去掉一些非重点代码(比如docker),内容如下:

点击查看代码
# 获取当前脚本所在的目录路径
SRC="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"

# check for whitespace in ${SRC} and exit for safety reasons 空字符串检验
grep -q "[[:space:]]" <<<"${SRC}" && { echo "\"${SRC}\" contains whitespace. Not supported. Aborting." >&2 ; exit 1 ; }

cd "${SRC}" || exit

# 启用调用跟踪
if [[ "${ORANGEPI_ENABLE_CALL_TRACING}" == "yes" ]]; then
        set -T # inherit return/debug traps
        mkdir -p "${SRC}"/output/debug
        echo -n "" > "${SRC}"/output/debug/calls.txt
        trap 'echo "${BASH_LINENO[@]}|${BASH_SOURCE[@]}|${FUNCNAME[@]}" >> ${SRC}/output/debug/calls.txt ;' RETURN
fi

# 执行./script/general.sh脚本
if [[ -f "${SRC}"/scripts/general.sh ]]; then

        # shellcheck source=scripts/general.sh
        source "${SRC}"/scripts/general.sh

else

        echo "Error: missing build directory structure"
        echo "Please clone the full repository by https://github.com/orangepi-xunlong/orangepi-build"
        exit 255

fi

# 校验第一个参数
if [[ "${EUID}" == "0" ]] || [[ "${1}" == "vagrant" ]]; then
        :
elif [[ "${1}" == docker || "${1}" == dockerpurge || "${1}" == docker-shell ]] && grep -q "$(whoami)" <(getent group docker); then
        :
else
        # 以root身份执行脚本
        display_alert "This script requires root privileges, trying to use sudo" "" "wrn"
        sudo "${SRC}/build.sh" "$@"
        exit $?
fi

# 走else分支,为宿主机ubuntu 22.04系统安装基础包,比如dialog、uuid、uuid-runtime等
if [ "$OFFLINE_WORK" == "yes" ]; then
        echo -e "\n"
        display_alert "* " "You are working offline."
        display_alert "* " "Sources, time and host will not be checked"
        echo -e "\n"
        sleep 3s
else
        # check and install the basic utilities here 
        prepare_host_basic
fi

EXTER="${SRC}/external"

# Create userpatches directory if not exists
mkdir -p "${SRC}"/userpatches

# Create example configs if none found in userpatches
if ! ls "${SRC}"/userpatches/{config-example.conf,config-docker.conf,config-vagrant.conf} 1> /dev/null 2>&1; then

        # Migrate old configs
        if ls "${SRC}"/*.conf 1> /dev/null 2>&1; then
                display_alert "Migrate config files to userpatches directory" "all *.conf" "info"
                cp "${SRC}"/*.conf "${SRC}"/userpatches  || exit 1
                rm "${SRC}"/*.conf
                [[ ! -L "${SRC}"/userpatches/config-example.conf ]] && ln -fs config-example.conf "${SRC}"/userpatches/config-default.conf || exit 1
        fi

        display_alert "Create example config file using template" "config-default.conf" "info"

        # Create example config
        if [[ ! -f "${SRC}"/userpatches/config-example.conf ]]; then
                cp "${EXTER}"/config/templates/config-example.conf "${SRC}"/userpatches/config-example.conf || exit 1
                ln -fs config-example.conf "${SRC}"/userpatches/config-default.conf || exit 1
        fi

        # Create Docker config
        if [[ ! -f "${SRC}"/userpatches/config-docker.conf ]]; then
                cp "${EXTER}"/config/templates/config-docker.conf "${SRC}"/userpatches/config-docker.conf || exit 1
        fi

        # Create Docker file
        if [[ ! -f "${SRC}"/userpatches/Dockerfile ]]; then
                cp "${EXTER}"/config/templates/Dockerfile "${SRC}"/userpatches/Dockerfile || exit 1
        fi

        # Create Vagrant config
        if [[ ! -f "${SRC}"/userpatches/config-vagrant.conf ]]; then
                cp "${EXTER}"/config/templates/config-vagrant.conf "${SRC}"/userpatches/config-vagrant.conf || exit 1
        fi

        # Create Vagrant file
        if [[ ! -f "${SRC}"/userpatches/Vagrantfile ]]; then
                cp "${EXTER}"/config/templates/Vagrantfile "${SRC}"/userpatches/Vagrantfile || exit 1
        fi

fi

# 不会进入
if [[ -z "${CONFIG}" && -n "$1" && -f "${SRC}/userpatches/config-$1.conf" ]]; then
        CONFIG="userpatches/config-$1.conf"
        shift
fi

# usind default if custom not found
if [[ -z "${CONFIG}" && -f "${SRC}/userpatches/config-default.conf" ]]; then
        CONFIG="userpatches/config-default.conf"
fi
# source build configuration file
CONFIG_FILE="$(realpath "${CONFIG}")"

if [[ ! -f "${CONFIG_FILE}" ]]; then
        display_alert "Config file does not exist" "${CONFIG}" "error"
        exit 254
fi

CONFIG_PATH=$(dirname "${CONFIG_FILE}")

# Source the extensions manager library at this point, before sourcing the config.
# This allows early calls to enable_extension(), but initialization proper is done later.
# shellcheck source=scripts/extensions.sh
source "${SRC}"/scripts/extensions.sh

display_alert "Using config file" "${CONFIG_FILE}" "info"
pushd "${CONFIG_PATH}" > /dev/null || exit
# shellcheck source=/dev/null
source "${CONFIG_FILE}"
popd > /dev/null || exit

[[ -z "${USERPATCHES_PATH}" ]] && USERPATCHES_PATH="${CONFIG_PATH}"

# Script parameters handling
while [[ "${1}" == *=* ]]; do

        parameter=${1%%=*}
        value=${1##*=}
        shift
        display_alert "Command line: setting $parameter to" "${value:-(empty)}" "info"
        eval "$parameter=\"$value\""

done


if [[ "${BUILD_ALL}" == "yes" || "${BUILD_ALL}" == "demo" ]]; then

        # shellcheck source=scripts/build-all-ng.sh
        source "${SRC}"/scripts/build-all-ng.sh

else

        # shellcheck source=scripts/main.sh
        source "${SRC}"/scripts/main.sh

fi

接下来我们针对该脚本内容从上往下依次分析。

1.1 开启调用追踪

如果我们需要启动调用跟踪,在执行命令时设置ORANGEPI_ENABLE_CALL_TRACING即可,比如:

ORANGEPI_ENABLE_CALL_TRACING=yes && ./build.sh

如果环境变量 ORANGEPI_ENABLE_CALL_TRACING 设置为 "yes",将启用函数调用跟踪;

if [[ "${ORANGEPI_ENABLE_CALL_TRACING}" == "yes" ]]; then
        set -T # inherit return/debug traps
        # 创建调试目录
        mkdir -p "${SRC}"/output/debug
        # 初始化一个空的calls.txt文件,用于存储调试信息
        echo -n "" > "${SRC}"/output/debug/calls.txt
        # 设置一个陷阱,在脚本退出时记录函数调用详情 
        trap 'echo "${BASH_LINENO[@]}|${BASH_SOURCE[@]}|${FUNCNAME[@]}" >> ${SRC}/output/debug/calls.txt ;' RETURN
fi
1.2 执行general.sh脚本

接着是使用source命令执行general.sh脚本,该脚本位于<SDK>/scripts目录下;

if [[ -f "${SRC}"/scripts/general.sh ]]; then
    source "${SRC}"/scripts/general.sh
else
    echo "错误:缺少构建目录结构"
    echo "请通过 https://github.com/orangepi-xunlong/orangepi-build 克隆完整的存储库"
    exit 255
fi

使用source命令执行脚本的一些注意事项:

  • 环境变量和函数的影响:被执行的脚本可以修改当前shell的环境变量和定义的函数,这些修改将持续影响到当前shell的会话,直到会话结束或者重新定义了这些变量和函数。
  • 退出状态:被执行的脚本的退出状态(即最后一个命令的退出状态)会影响到当前shell。可以通过$?变量来获取最近一次执行命令的退出状态;
  • 交互性:与直接执行脚本不同,使用source执行脚本时,不会创建新的shell环境,因此不会有新的子shell进程。这使得它适合于需要脚本和当前shell环境之间相互影响的场景,例如定义函数或设置环境变量。
1.3 执行prepare_host_basic脚本

prepare_host_basic脚本是在general.sh中定义的,为宿主机ubuntu 22.04系统安装基础包,比如dialoguuiduuid-runtime等。

1.4 创建userpatches目录

如果userpatches目录不存在则创建userpatches目录;

EXTER="${SRC}/external"

# Create userpatches directory if not exists
mkdir -p "${SRC}"/userpatches
1.4.1 创建example config

接着这段脚本代码主要用于检查和创建示例配置文件和相关文件,如果在 ${SRC}/userpatches 目录下找不到特定的配置文件,则创建相应的示例配置文件和相关文件;

# Create example configs if none found in userpatches  检查是否存在示例配置文件,如果都不存在则进入
if ! ls "${SRC}"/userpatches/{config-example.conf,config-docker.conf,config-vagrant.conf} 1> /dev/null 2>&1; then
        # Migrate old configs  迁移旧配置文件,不会进入
        if ls "${SRC}"/*.conf 1> /dev/null 2>&1; then
                display_alert "Migrate config files to userpatches directory" "all *.conf" "info"
                cp "${SRC}"/*.conf "${SRC}"/userpatches  || exit 1
                rm "${SRC}"/*.conf
                [[ ! -L "${SRC}"/userpatches/config-example.conf ]] && ln -fs config-example.conf "${SRC}"/userpatches/config-default.conf || exit 1
        fi

        display_alert "Create example config file using template" "config-default.conf" "info"

        # Create example config
        if [[ ! -f "${SRC}"/userpatches/config-example.conf ]]; then
                cp "${EXTER}"/config/templates/config-example.conf "${SRC}"/userpatches/config-example.conf || exit 1
                ln -fs config-example.conf "${SRC}"/userpatches/config-default.conf || exit 1
        fi

        # Create Docker config
        if [[ ! -f "${SRC}"/userpatches/config-docker.conf ]]; then
                cp "${EXTER}"/config/templates/config-docker.conf "${SRC}"/userpatches/config-docker.conf || exit 1
        fi

        # Create Docker file
        if [[ ! -f "${SRC}"/userpatches/Dockerfile ]]; then
                cp "${EXTER}"/config/templates/Dockerfile "${SRC}"/userpatches/Dockerfile || exit 1
        fi

        # Create Vagrant config
        if [[ ! -f "${SRC}"/userpatches/config-vagrant.conf ]]; then
                cp "${EXTER}"/config/templates/config-vagrant.conf "${SRC}"/userpatches/config-vagrant.conf || exit 1
        fi

        # Create Vagrant file
        if [[ ! -f "${SRC}"/userpatches/Vagrantfile ]]; then
                cp "${EXTER}"/config/templates/Vagrantfile "${SRC}"/userpatches/Vagrantfile || exit 1
        fi

fi

检查是否存在示例配置文件,如果都不存在:

  • 迁移旧配置文件:正常不会进入该分支;
  • 创建示例配置文件:如果 ./userpatches/config-example.conf 不存在,则从 ./external/config/templates/ 目录复制 config-example.conf./userpatches/ 目录,并创建一个指向config-example.conf的符号链接 config-default.conf
  • 创建Docker相关文件:如果./userpatches/config-docker.conf./userpatches/Dockerfile不存在,则分别从 ./external/config/templates/目录复制config-docker.confDockerfile./userpatches/目录;
  • 创建Vagrant相关文件:如果./userpatches/config-vagrant.conf./userpatches/Vagrantfile不存在,则分别从 ./external/config/templates/目录复制config-vagrant.confVagrantfile${SRC}/userpatches/目录。

因此执行完成后会在userpatches目录下创建config-default.confconfig-docker.confconfig-example.confconfig-vagrant.confVagrantfile文件;

root@ubuntu:/work/sambashare/rk3566/orangepi-build$ ll userpatches/
lrwxrwxrwx  1 root root    19  7月 10 14:20 config-default.conf -> config-example.conf
-rw-r--r--  1 root root  5846  7月 10 14:20 config-docker.conf
-rw-r--r--  1 root root  1274  7月 10 17:57 config-example.conf
-rw-r--r--  1 root root   715  7月 10 14:20 config-vagrant.conf
-rw-r--r--  1 root root  3111  7月 10 14:20 Dockerfile
-rw-r--r--  1 root root  1715  7月 10 14:20 Vagrantfile
1.4.2 使用默认配置

确定要使用的配置文件路径,并确保该配置文件存在。如果未找到任何自定义配置文件 ($1),则将使用默认配置文件 (config-default.conf);

# 检查自定义配置文件的存在性,由于参数1为指定因此不会进入
if [[ -z "${CONFIG}" && -n "$1" && -f "${SRC}/userpatches/config-$1.conf" ]]; then
        CONFIG="userpatches/config-$1.conf"
        shift
fi

# usind default if custom not found
if [[ -z "${CONFIG}" && -f "${SRC}/userpatches/config-default.conf" ]]; then
        CONFIG="userpatches/config-default.conf"
fi

# source build configuration file, 获取配置文件绝对路径,<SDK>/userpatches/config-example.conf
CONFIG_FILE="$(realpath "${CONFIG}")"

# 检查配置文件的实际存在性,由于文件的确存在因此不会进入
if [[ ! -f "${CONFIG_FILE}" ]]; then
        display_alert "Config file does not exist" "${CONFIG}" "error"
        exit 254
fi

# 获取配置文件所在目录,<SDK>/userpatches
CONFIG_PATH=$(dirname "${CONFIG_FILE}")
1.5 执行extensions.sh脚本

接着是使用source命令执行extensions.sh脚本,该脚本位于<SDK>/scripts目录下;

# Source the extensions manager library at this point, before sourcing the config.
# This allows early calls to enable_extension(), but initialization proper is done later.
# shellcheck source=scripts/extensions.sh
source "${SRC}"/scripts/extensions.sh
1.6 加载配置文件

接着是输出当前使用的配置文件夹信息,然后切换工作目录并加载配置文件:

display_alert "Using config file" "${CONFIG_FILE}" "info"

# 将当前工作目录切换到 ${CONFIG_PATH}
pushd "${CONFIG_PATH}" > /dev/null || exit

# shellcheck source=/dev/null,加载${CONFIG_FILE}中的shell脚本
source "${CONFIG_FILE}"

# 恢复之前的工作目录
popd > /dev/null || exit

# 设置USERPATCHES_PATH=${CONFIG_PATH}
[[ -z "${USERPATCHES_PATH}" ]] && USERPATCHES_PATH="${CONFIG_PATH}"

# Script parameters handling,由于未指定参数1因此不会进入
while [[ "${1}" == *=* ]]; do
        parameter=${1%%=*}
        value=${1##*=}
        shift
        display_alert "Command line: setting $parameter to" "${value:-(empty)}" "info"
        eval "$parameter=\"$value\""
done
1.6.1 config-example.conf

CONFIG_FILE被定义为了<SDK>/userpatches/config-example.conf,内容如下:

KERNEL_CONFIGURE=""                     # leave empty to select each time, set to "yes" or "no" to skip dialog prompt
CLEAN_LEVEL="debs,oldcache"             # comma-separated list of clean targets: "make" = make clean for selected kernel and u-boot,
                                        # "debs" = delete packages in "./output/debs" for current branch and family,
                                        # "alldebs" = delete all packages in "./output/debs", "images" = delete "./output/images",
                                        # "cache" = delete "./output/cache", "sources" = delete "./sources"
                                        # "oldcache" = remove old cached rootfs except for the newest 8 files

DEST_LANG="en_US.UTF-8"                 # sl_SI.UTF-8, en_US.UTF-8

# advanced
EXTERNAL_NEW="prebuilt"                 # compile and install or install prebuilt additional packages
INSTALL_HEADERS=""                      # install kernel headers package
LIB_TAG="master"                        # change to "branchname" to use any branch currently available.
USE_TORRENT="yes"                       # use torrent network for faster toolchain and cache download
DOWNLOAD_MIRROR="china"                 # set to "china" to use mirrors.tuna.tsinghua.edu.cn

BOARD=""
BRANCH=""
RELEASE=""
WIREGUARD="no"
BUILD_KSRC="no"
INSTALL_KSRC="no"
IGNORE_UPDATES="yes"
COMPRESS_OUTPUTIMAGE="no"
NO_APT_CACHER="yes"

#install_balena_etcher="yes"
#install_zfs="yes"
#install_docker="yes"
#install_chromium="yes"
#install_firefox="yes"

该脚本中定义的一些变量将会被加载到当前shell中。

1.7 进入main.sh

脚本的最后使用source命令执行main.sh脚本;

if [[ "${BUILD_ALL}" == "yes" || "${BUILD_ALL}" == "demo" ]]; then
        # shellcheck source=scripts/build-all-ng.sh
        source "${SRC}"/scripts/build-all-ng.sh
else
        # shellcheck source=scripts/main.sh
        source "${SRC}"/scripts/main.sh
fi

二、general.sh分析

general.sh是一个通用脚本,该脚本位于<SDK>/scripts目录下,脚本提供了通用功能;

  • cleaning
  • exit_with_error
  • get_package_list_hash
  • create_sources_list
  • clean_up_git
  • waiter_local_git
  • fetch_from_repo
  • improved_git
  • distro_menu
  • addtorepo
  • repo-remove-old-packages
  • wait_for_package_manager
  • install_pkg_deb
  • prepare_host_basic
  • prepare_host
  • webseed
  • download_and_verify
  • show_developer_warning
  • show_checklist_variables
2.1 display_alert

display_alert用于在终端中显示带有不同类型标签的警告信息;

#--------------------------------------------------------------------------------------------------------------------------------
# Let's have unique way of displaying alerts
#--------------------------------------------------------------------------------------------------------------------------------
display_alert()
{
        # log function parameters to install.log
        [[ -n "${DEST}" ]] && echo "Displaying message: $@" >> "${DEST}"/${LOG_SUBPATH}/output.log

        local tmp=""
        [[ -n $2 ]] && tmp="[\e[0;33m $2 \x1B[0m]"

		# 根据第三个参数 $3 的不同取值,输出不同类型的警告信息
        case $3 in
                err)
                # 红色文字
                echo -e "[\e[0;31m error \x1B[0m] $1 $tmp"
                ;;

                wrn)
                # 洋红色文字
                echo -e "[\e[0;35m warn \x1B[0m] $1 $tmp"
                ;;

                ext)
                # 绿色文字
                echo -e "[\e[0;32m o.k. \x1B[0m] \e[1;32m$1\x1B[0m $tmp"
                ;;

                info)
                # 加粗绿色文字
                echo -e "[\e[0;32m o.k. \x1B[0m] $1 $tmp"
                ;;

                *)
                # 绿色样式(作为通用信息)
                echo -e "[\e[0;32m .... \x1B[0m] $1 $tmp"
                ;;
        esac
}
2.2 prepare_host_basic

prepare_host_basic为宿主机ubuntu 22.04系统安装基础包,比如dialoguuiduuid-runtime等;

# prepare_host_basic
#
# * installs only basic packages
#
prepare_host_basic()
{
        # command:package1 package2 ...
        # list of commands that are neeeded:packages where this command is
        local check_pack install_pack
        local checklist=(
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Graceful_scenery

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值