Rockchip RK3566 - orangepi-build脚本分析
目录
----------------------------------------------------------------------------------------------------------------------------
开发板 :Orange Pi 3B
开发板
eMMC
:32GB
LPDDR4
:2GB
显示屏 :15.6
英寸HDMI
接口显示屏
u-boot
:2017.09
linux
:6.6
----------------------------------------------------------------------------------------------------------------------------
在《Rockchip RK3566 - orangepi-build
编译》我们介绍了SDK
的编译流程,本节将会对编译脚本进行深入的分析。
一、build.sh
分析
orangepi-build
编译命令是由build.sh
脚本实现的,其脚本相对来说比较长,这里我们去掉一些非重点代码(比如docker
),内容如下:
View Code
# 获取当前脚本所在的目录路径
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"
,将启用函数调用跟踪,并将日志记录到./output/debug/calls.txt
;
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
系统安装基础包,比如dialog
、uuid
、uuid-runtime
等,这个我们在单独介绍general.sh
时再来说。
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.conf
和Dockerfile
到./userpatches/
目录; - 创建
Vagrant
相关文件:如果./userpatches/config-vagrant.conf
和./userpatches/Vagrantfile
不存在,则分别从./external/config/templates/
目录复制config-vagrant.conf
和Vagrantfile
到${SRC}/userpatches/
目录。
因此执行完成后会在userpatches
目录下创建config-default.conf
、config-docker.conf
、config-example.conf
、config-vagrant.conf
、Vagrantfile
文件;
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 使用config-default.conf
确定要使用的配置文件路径,并确保该配置文件存在。如果未找到任何自定义配置文件 ($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, 获取配置文件绝对路径,由于config-default.conf链接到了config-example.conf,因此此处值为<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
CONFIG_FILE
被定义为了<SDK>/userpatches/config-example.conf
,该脚本中定义的一些变量将会被加载到当前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
二、main.sh
分析
main.sh
脚本位于<SDK>/scripts
目录下,该脚本比较重要,可以认为就是编译的主程序。
这里我们去掉一些非重点代码(比如docker
),内容如下:
View Code
#!/bin/bash
#
# Copyright (c) 2013-2021 Igor Pecovnik, igor.pecovnik@gma**.com
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# Main program
#
cleanup_list() {
local varname="${1}"
local list_to_clean="${!varname}"
list_to_clean="${list_to_clean#"${list_to_clean%%[![:space:]]*}"}"
list_to_clean="${list_to_clean%"${list_to_clean##*[![:space:]]}"}"
echo ${list_to_clean}
}
# default umask for root is 022 so parent directories won't be group writeable without this
# this is used instead of making the chmod in prepare_host() recursive
# 设置文件创建的默认权限
umask 002
# destination 确定目标路径
if [ -d "$CONFIG_PATH/output" ]; then
DEST="${CONFIG_PATH}"/output
else
DEST="${SRC}"/output
fi
# 进入
[[ -z $REVISION ]] && REVISION="3.0.8"
# 进入
[[ $DOWNLOAD_MIRROR == "china" ]] && NTP_SERVER="cn.pool.ntp.org"
# 进入,根据终端的当前尺寸设置 TTY_X(宽度)和 TTY_Y(高度)
if [[ $BUILD_ALL != "yes" ]]; then
# override stty size
[[ -n $COLUMNS ]] && stty cols $COLUMNS
[[ -n $LINES ]] && stty rows $LINES
TTY_X=$(($(stty size | awk '{print $2}')-6)) # determine terminal width
TTY_Y=$(($(stty size | awk '{print $1}')-6)) # determine terminal height
fi
# We'll use this title on all menus 设置标题和菜单
backtitle="Orange Pi building script, http://www.orangepi.org"
titlestr="Choose an option"
# Warnings mitigation 设置语言和终端的字符集编码
[[ -z $LANGUAGE ]] && export LANGUAGE="en_US:en" # set to english if not set
[[ -z $CONSOLE_CHAR ]] && export CONSOLE_CHAR="UTF-8" # set console to UTF-8 if not set
# Libraries include
# shellcheck source=debootstrap.sh
source "${SRC}"/scripts/debootstrap.sh # system specific install
# shellcheck source=image-helpers.sh
source "${SRC}"/scripts/image-helpers.sh # helpers for OS image building
# shellcheck source=distributions.sh
source "${SRC}"/scripts/distributions.sh # system specific install
# shellcheck source=desktop.sh
source "${SRC}"/scripts/desktop.sh # desktop specific install
# shellcheck source=compilation.sh
source "${SRC}"/scripts/compilation.sh # patching and compilation of kernel, uboot, ATF
# shellcheck source=compilation-prepare.sh
#source "${SRC}"/scripts/compilation-prepare.sh # drivers that are not upstreamed
# shellcheck source=makeboarddeb.sh
source "${SRC}"/scripts/makeboarddeb.sh # board support package
# shellcheck source=general.sh
source "${SRC}"/scripts/general.sh # general functions
# shellcheck source=chroot-buildpackages.sh
source "${SRC}"/scripts/chroot-buildpackages.sh # chroot packages building
# shellcheck source=pack.sh
source "${SRC}"/scripts/pack-uboot.sh
# set log path 设置输出日志路径
LOG_SUBPATH=${LOG_SUBPATH:=debug}
# compress and remove old logs
mkdir -p "${DEST}"/${LOG_SUBPATH}
(cd "${DEST}"/${LOG_SUBPATH} && tar -czf logs-"$(<timestamp)".tgz ./*.log) > /dev/null 2>&1
rm -f "${DEST}"/${LOG_SUBPATH}/*.log > /dev/null 2>&1
date +"%d_%m_%Y-%H_%M_%S" > "${DEST}"/${LOG_SUBPATH}/timestamp
# delete compressed logs older than 7 days
(cd "${DEST}"/${LOG_SUBPATH} && find . -name '*.tgz' -mtime +7 -delete) > /dev/null
# 设置缓存目录
SHOW_WARNING=yes
if [[ $USE_CCACHE != no ]]; then
CCACHE=ccache
export PATH="/usr/lib/ccache:$PATH"
# private ccache directory to avoid permission issues when using build script with "sudo"
# see https://ccache.samba.org/manual.html#_sharing_a_cache for alternative solution
[[ $PRIVATE_CCACHE == yes ]] && export CCACHE_DIR=$EXTER/cache/ccache
else
CCACHE=""
fi
# if BUILD_OPT, KERNEL_CONFIGURE, BOARD, BRANCH or RELEASE are not set, display selection menu
# 创建了一个用户界面,用户可以从菜单中选择构建选项(u-boot、kernel、rootfs、image)
if [[ -z $BUILD_OPT ]]; then
options+=("u-boot" "U-boot package")
options+=("kernel" "Kernel package")
options+=("rootfs" "Rootfs and all deb packages")
options+=("image" "Full OS image for flashing")
menustr="Compile image | rootfs | kernel | u-boot"
BUILD_OPT=$(whiptail --title "${titlestr}" --backtitle "${backtitle}" --notags \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $BUILD_OPT ]] && exit_with_error "No option selected"
[[ $BUILD_OPT == rootfs ]] && ROOT_FS_CREATE_ONLY="yes"
fi
# 如果选择了kernel或image则进入,选择内核配置
if [[ ${BUILD_OPT} =~ kernel|image ]]; then
if [[ -z $KERNEL_CONFIGURE ]]; then
options+=("no" "Do not change the kernel configuration")
options+=("yes" "Show a kernel configuration menu before compilation")
menustr="Select the kernel configuration."
KERNEL_CONFIGURE=$(whiptail --title "${titlestr}" --backtitle "$backtitle" --notags \
--menu "${menustr}" $TTY_Y $TTY_X $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $KERNEL_CONFIGURE ]] && exit_with_error "No option selected"
fi
fi
# 进入,选择开发板型号
if [[ -z $BOARD ]]; then
#options+=("orangepir1" "Allwinner H2+ quad core 256MB RAM WiFi SPI 2xETH")
#options+=("orangepizero" "Allwinner H2+ quad core 256MB/512MB RAM WiFi SPI")
#options+=("orangepipc" "Allwinner H3 quad core 1GB RAM")
#options+=("orangepipcplus" "Allwinner H3 quad core 1GB RAM WiFi eMMC")
#options+=("orangepione" "Allwinner H3 quad core 512MB RAM")
#options+=("orangepilite" "Allwinner H3 quad core 512MB RAM WiFi")
#options+=("orangepiplus" "Allwinner H3 quad core 1GB/2GB RAM WiFi GBE eMMC")
#options+=("orangepiplus2e" "Allwinner H3 quad core 2GB RAM WiFi GBE eMMC")
#options+=("orangepizeroplus2h3" "Allwinner H3 quad core 512MB RAM WiFi/BT eMMC")
#options+=("orangepipch5" "Allwinner H5 quad core 1GB RAM")
#options+=("orangepipc2" "Allwinner H5 quad core 1GB RAM GBE SPI")
#options+=("orangepioneh5" "Allwinner H5 quad core 512MB/1GB RAM")
#options+=("orangepiprime" "Allwinner H5 quad core 2GB RAM GBE WiFi/BT")
#options+=("orangepizeroplus" "Allwinner H5 quad core 512MB RAM GBE WiFi SPI")
#options+=("orangepizeroplus2h5" "Allwinner H5 quad core 512MB RAM WiFi/BT eMMC")
options+=("orangepi3" "Allwinner H6 quad core 1GB/2GB RAM GBE WiFi/BT eMMC USB3")
options+=("orangepi3-lts" "Allwinner H6 quad core 2GB RAM GBE WiFi/BT-AW859A eMMC USB3")
#options+=("orangepilite2" "Allwinner H6 quad core 1GB RAM WiFi/BT USB3")
#options+=("orangepioneplus" "Allwinner H6 quad core 1GB RAM GBE")
options+=("orangepizero2" "Allwinner H616 quad core 512MB/1GB RAM WiFi/BT GBE SPI")
#options+=("orangepizero2-b" "Allwinner H616 quad core 512MB/1GB RAM WiFi/BT GBE SPI")
#options+=("orangepizero2-lts" "Allwinner H616 quad core 1.5GB RAM WiFi/BT GBE SPI")
options+=("orangepizero3" "Allwinner H618 quad core 1GB/1.5GB/2GB/4GB RAM WiFi/BT GBE SPI")
options+=("orangepizero2w" "Allwinner H618 quad core 1GB/1.5GB/2GB/4GB RAM WiFi/BT SPI")
#options+=("orangepir1b" "Allwinner H618 quad core 1.5GB/2GB/4GB RAM WiFi/BT GBE SPI")
#options+=("orangepi400" "Allwinner H616 quad core 4GB RAM WiFi/BT GBE eMMC VGA")
options+=("orangepi4" "Rockchip RK3399 hexa core 4GB RAM GBE eMMC USB3 USB-C WiFi/BT")
options+=("orangepi4-lts" "Rockchip RK3399 hexa core 4GB RAM GBE eMMC USB3 USB-C WiFi/BT")
options+=("orangepi800" "Rockchip RK3399 hexa core 4GB RAM GBE eMMC USB3 USB-C WiFi/BT VGA")
options+=("orangepi5" "Rockchip RK3588S octa core 4-16GB RAM GBE USB3 USB-C NVMe")
options+=("orangepicm5" "Rockchip RK3588S octa core 4-16GB RAM GBE USB3 USB-C")
options+=("orangepicm5-tablet" "Rockchip RK3588S octa core 4-16GB RAM USB3 USB-C WiFi/BT")
options+=("orangepi5b" "Rockchip RK3588S octa core 4-16GB RAM GBE USB3 USB-C WiFi/BT eMMC")
#options+=("orangepitab" "Rockchip RK3588S octa core 4-16GB RAM USB-C WiFi/BT NVMe")
#options+=("orangepi900" "Rockchip RK3588 octa core 4-16GB RAM 2.5GBE USB3 USB-C WiFi/BT NVMe")
options+=("orangepi5pro" "Rockchip RK3588S octa core 4-16GB RAM GBE USB3 WiFi/BT NVMe eMMC")
options+=("orangepi5max" "Rockchip RK3588 octa core 4-16GB RAM 2.5GBE USB3 WiFi/BT NVMe eMMC")
options+=("orangepi5plus" "Rockchip RK3588 octa core 4-32GB RAM 2.5GBE USB3 USB-C WiFi/BT NVMe eMMC")
options+=("orangepicm4" "Rockchip RK3566 quad core 2-8GB RAM GBE eMMC USB3 NvMe WiFi/BT")
options+=("orangepi3b" "Rockchip RK3566 quad core 2-8GB RAM GBE eMMC USB3 NvMe WiFi/BT")
#options+=("orangepir1plus" "Rockchip RK3328 quad core 1GB RAM 2xGBE USB2 SPI")
#options+=("orangepi3plus" "Amlogic S905D3 quad core 2/4GB RAM SoC eMMC GBE USB3 SPI WiFi/BT")
menustr="Please choose a Board."
BOARD=$(whiptail --title "${titlestr}" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $BOARD ]] && exit_with_error "No option selected"
fi
# 加载板载配置文件external/config/boards/orangepi3b.conf
BOARD_TYPE="conf"
# shellcheck source=/dev/null
source "${EXTER}/config/boards/${BOARD}.${BOARD_TYPE}"
LINUXFAMILY="${BOARDFAMILY}"
[[ -z $KERNEL_TARGET ]] && exit_with_error "Board configuration does not define valid kernel config"
# 进入,选择内核版本
if [[ -z $BRANCH ]]; then
options=()
[[ $KERNEL_TARGET == *current* ]] && options+=("current" "Recommended. Come with best support")
[[ $KERNEL_TARGET == *legacy* ]] && options+=("legacy" "Old stable / Legacy")
[[ $KERNEL_TARGET == *next* ]] && options+=("next" "Use the latest kernel")
menustr="Select the target kernel branch\nExact kernel versions depend on selected board"
# do not display selection dialog if only one kernel branch is available
if [[ "${#options[@]}" == 2 ]]; then
BRANCH="${options[0]}"
else
BRANCH=$(whiptail --title "${titlestr}" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
fi
unset options
[[ -z $BRANCH ]] && exit_with_error "No kernel branch selected"
[[ $BRANCH == dev && $SHOW_WARNING == yes ]] && show_developer_warning
fi
# 如果选择了kernel或image,并且未设置RELEASE则进入选择Linux发行版的类型
if [[ $BUILD_OPT =~ rootfs|image && -z $RELEASE ]]; then
options=()
distros_options
menustr="Select the target OS release package base"
RELEASE=$(whiptail --title "Choose a release package base" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
#echo "options : ${options}"
[[ -z $RELEASE ]] && exit_with_error "No release selected"
unset options
fi
# don't show desktop option if we choose minimal build,如果设置了Minimal版本版本
[[ $BUILD_MINIMAL == yes ]] && BUILD_DESKTOP=no
# 选择镜像的类型,有桌面和无桌面
if [[ $BUILD_OPT =~ rootfs|image && -z $BUILD_DESKTOP ]]; then
# read distribution support status which is written to the orangepi-release file
set_distribution_status
options=()
options+=("no" "Image with console interface (server)")
options+=("yes" "Image with desktop environment")
menustr="Select the target image type"
BUILD_DESKTOP=$(whiptail --title "Choose image type" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $BUILD_DESKTOP ]] && exit_with_error "No option selected"
if [[ ${BUILD_DESKTOP} == "yes" ]]; then
BUILD_MINIMAL=no
SELECTED_CONFIGURATION="desktop"
fi
fi
# 对于无桌面的镜像,选择Standard版本或者Minimal版本
if [[ $BUILD_OPT =~ rootfs|image && $BUILD_DESKTOP == no && -z $BUILD_MINIMAL ]]; then
options=()
options+=("no" "Standard image with console interface")
options+=("yes" "Minimal image with console interface")
menustr="Select the target image type"
BUILD_MINIMAL=$(whiptail --title "Choose image type" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $BUILD_MINIMAL ]] && exit_with_error "No option selected"
if [[ $BUILD_MINIMAL == "yes" ]]; then
SELECTED_CONFIGURATION="cli_minimal"
else
SELECTED_CONFIGURATION="cli_standard"
fi
fi
#prevent conflicting setup 处理冲突配置
if [[ $BUILD_DESKTOP == "yes" ]]; then
BUILD_MINIMAL=no
SELECTED_CONFIGURATION="desktop"
elif [[ $BUILD_MINIMAL != "yes" || -z "${BUILD_MINIMAL}" ]]; then
BUILD_MINIMAL=no # Just in case BUILD_MINIMAL is not defined
BUILD_DESKTOP=no
SELECTED_CONFIGURATION="cli_standard"
elif [[ $BUILD_MINIMAL == "yes" ]]; then
BUILD_DESKTOP=no
SELECTED_CONFIGURATION="cli_minimal"
fi
#shellcheck source=configuration.sh
source "${SRC}"/scripts/configuration.sh
# optimize build time with 100% CPU usage 定系统中的CPU核心数,并根据USEALLCORES的设置动态调整并行编译线程数
CPUS=$(grep -c 'processor' /proc/cpuinfo)
if [[ $USEALLCORES != no ]]; then
CTHREADS="-j$((CPUS + CPUS/2))"
else
CTHREADS="-j1"
fi
call_extension_method "post_determine_cthreads" "config_post_determine_cthreads" << 'POST_DETERMINE_CTHREADS'
*give config a chance modify CTHREADS programatically. A build server may work better with hyperthreads-1 for example.*
Called early, before any compilation work starts.
POST_DETERMINE_CTHREADS
if [[ $BETA == yes ]]; then
IMAGE_TYPE=nightly
elif [[ $BETA != "yes" && $BUILD_ALL == yes && -n $GPG_PASS ]]; then
IMAGE_TYPE=stable
else
IMAGE_TYPE=user-built # 走这里
fi
branch2dir() {
[[ "${1}" == "head" ]] && echo "HEAD" || echo "${1##*:}"
}
BOOTSOURCEDIR="${BOOTDIR}/$(branch2dir "${BOOTBRANCH}")"
LINUXSOURCEDIR="${KERNELDIR}/$(branch2dir "${KERNELBRANCH}")"
[[ -n $ATFSOURCE ]] && ATFSOURCEDIR="${ATFDIR}/$(branch2dir "${ATFBRANCH}")"
BSP_CLI_PACKAGE_NAME="orangepi-bsp-cli-${BOARD}"
BSP_CLI_PACKAGE_FULLNAME="${BSP_CLI_PACKAGE_NAME}_${REVISION}_${ARCH}"
BSP_DESKTOP_PACKAGE_NAME="orangepi-bsp-desktop-${BOARD}"
BSP_DESKTOP_PACKAGE_FULLNAME="${BSP_DESKTOP_PACKAGE_NAME}_${REVISION}_${ARCH}"
CHOSEN_UBOOT=linux-u-boot-${BRANCH}-${BOARD}
CHOSEN_KERNEL=linux-image-${BRANCH}-${LINUXFAMILY}
CHOSEN_ROOTFS=${BSP_CLI_PACKAGE_NAME}
CHOSEN_DESKTOP=orangepi-${RELEASE}-desktop-${DESKTOP_ENVIRONMENT}
CHOSEN_KSRC=linux-source-${BRANCH}-${LINUXFAMILY}
do_default() {
start=$(date +%s)
# Check and install dependencies, directory structure and settings
# The OFFLINE_WORK variable inside the function
prepare_host
[[ "${JUST_INIT}" == "yes" ]] && exit 0
[[ $CLEAN_LEVEL == *sources* ]] && cleaning "sources"
# fetch_from_repo <url> <dir> <ref> <subdir_flag>
# ignore updates help on building all images - for internal purposes
if [[ ${IGNORE_UPDATES} != yes ]]; then
display_alert "Downloading sources" "" "info"
[[ $BUILD_OPT =~ u-boot|image ]] && fetch_from_repo "$BOOTSOURCE" "$BOOTDIR" "$BOOTBRANCH" "yes"
[[ $BUILD_OPT =~ kernel|image ]] && fetch_from_repo "$KERNELSOURCE" "$KERNELDIR" "$KERNELBRANCH" "yes"
if [[ -n ${ATFSOURCE} ]]; then
[[ ${BUILD_OPT} =~ u-boot|image ]] && fetch_from_repo "$ATFSOURCE" "${EXTER}/cache/sources/$ATFDIR" "$ATFBRANCH" "yes"
fi
if [[ ${BOARDFAMILY} == "rockchip-rk356x" && $RELEASE =~ bullseye|focal|jammy|raspi ]]; then
[[ ${BUILD_OPT} == image ]] && fetch_from_repo "https://github.com/orangepi-xunlong/rk-rootfs-build.git" "${EXTER}/cache/sources/rk35xx_packages" "branch:rk35xx_packages"
fi
if [[ ${BOARD} =~ orangepi3|orangepi3-lts && $RELEASE =~ bullseye && $BRANCH == current ]]; then
[[ ${BUILD_OPT} == image ]] && fetch_from_repo "https://github.com/orangepi-xunlong/rk-rootfs-build.git" "${EXTER}/cache/sources/ffmpeg_kodi_${RELEASE}" "branch:ffmpeg_kodi_${RELEASE}"
fi
call_extension_method "fetch_sources_tools" <<- 'FETCH_SOURCES_TOOLS'
*fetch host-side sources needed for tools and build*
Run early to fetch_from_repo or otherwise obtain sources for needed tools.
FETCH_SOURCES_TOOLS
call_extension_method "build_host_tools" <<- 'BUILD_HOST_TOOLS'
*build needed tools for the build, host-side*
After sources are fetched, build host-side tools needed for the build.
BUILD_HOST_TOOLS
if [[ ${BOARDFAMILY} == "rockchip-rk3588" ]]; then
local rkbin_url="https://github.com/orangepi-xunlong/rk-rootfs-build/raw/rkbin/rk35"
wget -nc -P ${EXTER}/cache/sources/rkbin-tools/rk35/ ${rkbin_url}/rk3588_bl31_v1.45_20240422.elf
fi
fi
for option in $(tr ',' ' ' <<< "$CLEAN_LEVEL"); do
[[ $option != sources ]] && cleaning "$option"
done
# Compile u-boot if packed .deb does not exist or use the one from Orange Pi
if [[ $BUILD_OPT == u-boot || $BUILD_OPT == image ]]; then
if [[ ! -f "${DEB_STORAGE}"/u-boot/${CHOSEN_UBOOT}_${REVISION}_${ARCH}.deb ]]; then
[[ -n "${ATFSOURCE}" && "${REPOSITORY_INSTALL}" != *u-boot* ]] && compile_atf
[[ ${REPOSITORY_INSTALL} != *u-boot* ]] && compile_uboot
fi
if [[ $BUILD_OPT == "u-boot" ]]; then
unset BUILD_MINIMAL BUILD_DESKTOP COMPRESS_OUTPUTIMAGE
display_alert "U-boot build done" "@host" "info"
display_alert "Target directory" "${DEB_STORAGE}/u-boot" "info"
display_alert "File name" "${CHOSEN_UBOOT}_${REVISION}_${ARCH}.deb" "info"
fi
fi
# Compile kernel if packed .deb does not exist or use the one from Orange Pi
if [[ $BUILD_OPT == kernel || $BUILD_OPT == image ]]; then
if [[ ! -f ${DEB_STORAGE}/${CHOSEN_KERNEL}_${REVISION}_${ARCH}.deb ]]; then
KDEB_CHANGELOG_DIST=$RELEASE
[[ "${REPOSITORY_INSTALL}" != *kernel* ]] && compile_kernel
fi
if [[ $BUILD_OPT == "kernel" ]]; then
unset BUILD_MINIMAL BUILD_DESKTOP COMPRESS_OUTPUTIMAGE
display_alert "Kernel build done" "@host" "info"
display_alert "Target directory" "${DEB_STORAGE}/" "info"
display_alert "File name" "${CHOSEN_KERNEL}_${REVISION}_${ARCH}.deb" "info"
fi
fi
if [[ $BUILD_OPT == rootfs || $BUILD_OPT == image ]]; then
# Compile orangepi-config if packed .deb does not exist or use the one from Orange Pi
if [[ ! -f ${DEB_STORAGE}/orangepi-config_${REVISION}_all.deb ]]; then
[[ "${REPOSITORY_INSTALL}" != *orangepi-config* ]] && compile_orangepi-config
fi
# Compile orangepi-zsh if packed .deb does not exist or use the one from repository
if [[ ! -f ${DEB_STORAGE}/orangepi-zsh_${REVISION}_all.deb ]]; then
[[ "${REPOSITORY_INSTALL}" != *orangepi-zsh* ]] && compile_orangepi-zsh
fi
# Compile plymouth-theme-orangepi if packed .deb does not exist or use the one from repository
if [[ ! -f ${DEB_STORAGE}/plymouth-theme-orangepi_${REVISION}_all.deb ]]; then
[[ "${REPOSITORY_INSTALL}" != *plymouth-theme-orangepi* ]] && compile_plymouth-theme-orangepi
fi
# Compile orangepi-firmware if packed .deb does not exist or use the one from repository
if [[ "${REPOSITORY_INSTALL}" != *orangepi-firmware* ]]; then
if ! ls "${DEB_STORAGE}/orangepi-firmware_${REVISION}_all.deb" 1> /dev/null 2>&1; then
FULL=""
REPLACE="-full"
compile_firmware
fi
fi
overlayfs_wrapper "cleanup"
# create board support package
[[ -n $RELEASE && ! -f ${DEB_STORAGE}/$RELEASE/${BSP_CLI_PACKAGE_FULLNAME}.deb ]] && create_board_package
# create desktop package
[[ -n $RELEASE && $DESKTOP_ENVIRONMENT ]] && create_desktop_package
[[ -n $RELEASE && $DESKTOP_ENVIRONMENT ]] && create_bsp_desktop_package
# build additional packages
[[ $EXTERNAL_NEW == compile ]] && chroot_build_packages
[[ $BSP_BUILD != yes ]] && debootstrap_ng
fi
# hook for function to run after build, i.e. to change owner of $SRC
# NOTE: this will run only if there were no errors during build process
[[ $(type -t run_after_build) == function ]] && run_after_build || true
end=$(date +%s)
runtime=$(((end-start)/60))
display_alert "Runtime" "$runtime min" "info"
# Make it easy to repeat build by displaying build options used
[ "$(systemd-detect-virt)" == 'docker' ] && BUILD_CONFIG='docker'
display_alert "Repeat Build Options" "sudo ./build.sh ${BUILD_CONFIG} BOARD=${BOARD} BRANCH=${BRANCH} \
$([[ -n $BUILD_OPT ]] && echo "BUILD_OPT=${BUILD_OPT} ")\
$([[ -n $RELEASE ]] && echo "RELEASE=${RELEASE} ")\
$([[ -n $BUILD_MINIMAL ]] && echo "BUILD_MINIMAL=${BUILD_MINIMAL} ")\
$([[ -n $BUILD_DESKTOP ]] && echo "BUILD_DESKTOP=${BUILD_DESKTOP} ")\
$([[ -n $KERNEL_CONFIGURE ]] && echo "KERNEL_CONFIGURE=${KERNEL_CONFIGURE} ")\
$([[ -n $DESKTOP_ENVIRONMENT ]] && echo "DESKTOP_ENVIRONMENT=${DESKTOP_ENVIRONMENT} ")\
$([[ -n $DESKTOP_ENVIRONMENT_CONFIG_NAME ]] && echo "DESKTOP_ENVIRONMENT_CONFIG_NAME=${DESKTOP_ENVIRONMENT_CONFIG_NAME} ")\
$([[ -n $DESKTOP_APPGROUPS_SELECTED ]] && echo "DESKTOP_APPGROUPS_SELECTED=\"${DESKTOP_APPGROUPS_SELECTED}\" ")\
$([[ -n $DESKTOP_APT_FLAGS_SELECTED ]] && echo "DESKTOP_APT_FLAGS_SELECTED=\"${DESKTOP_APT_FLAGS_SELECTED}\" ")\
$([[ -n $COMPRESS_OUTPUTIMAGE ]] && echo "COMPRESS_OUTPUTIMAGE=${COMPRESS_OUTPUTIMAGE} ")\
" "ext"
} # end of do_default()
if [[ -z $1 ]]; then
do_default
else
eval "$@"
f
接下来我们针对该脚本内容从上往下依次分析。
2.1 准备工作
main.sh
脚本开始是一系列的准备工作,具体如下。
2.1.1 确定目标路径
确定编译输出目标路径,设置为<SDK>/output
;
# destination 确定目标路径
if [ -d "$CONFIG_PATH/output" ]; then
DEST="${CONFIG_PATH}"/output
else
DEST="${SRC}"/output # 走这里
fi
2.1.2 加载若干脚本函数
接着是使用source
命令执行若干*.sh
脚本,脚本均位于<SDK>/scripts
目录下;
# shellcheck source=debootstrap.sh
source "${SRC}"/scripts/debootstrap.sh # system specific install
# shellcheck source=image-helpers.sh
source "${SRC}"/scripts/image-helpers.sh # helpers for OS image building
# shellcheck source=distributions.sh
source "${SRC}"/scripts/distributions.sh # system specific install
# shellcheck source=desktop.sh
source "${SRC}"/scripts/desktop.sh # desktop specific install
# shellcheck source=compilation.sh
source "${SRC}"/scripts/compilation.sh # patching and compilation of kernel, uboot, ATF
# shellcheck source=compilation-prepare.sh
#source "${SRC}"/scripts/compilation-prepare.sh # drivers that are not upstreamed
# shellcheck source=makeboarddeb.sh
source "${SRC}"/scripts/makeboarddeb.sh # board support package
# shellcheck source=general.sh
source "${SRC}"/scripts/general.sh # general functions
# shellcheck source=chroot-buildpackages.sh
source "${SRC}"/scripts/chroot-buildpackages.sh # chroot packages building
# shellcheck source=pack.sh
source "${SRC}"/scripts/pack-uboot.sh
这些脚本都是定义了若干个函数,这些脚本中定义的函数将会被加载到当前shell
中。
2.1.3 设置日志路径
接着设置日志输出路径:
# set log path
LOG_SUBPATH=${LOG_SUBPATH:=debug}
# compress and remove old logs 创建目录
mkdir -p "${DEST}"/${LOG_SUBPATH}
# 压缩并删除旧的日志文件,并将其压缩后的文件存档
(cd "${DEST}"/${LOG_SUBPATH} && tar -czf logs-"$(<timestamp)".tgz ./*.log) > /dev/null 2>&1
rm -f "${DEST}"/${LOG_SUBPATH}/*.log > /dev/null 2>&1
date +"%d_%m_%Y-%H_%M_%S" > "${DEST}"/${LOG_SUBPATH}/timestamp
# delete compressed logs older than 7 days 删除超过一周的旧日志压缩文件
(cd "${DEST}"/${LOG_SUBPATH} && find . -name '*.tgz' -mtime +7 -delete) > /dev/null
日志输出路径被设置为debug
,位于<SDK>/output
目录下;
root@ubuntu:/work/sambashare/rk3566/orangepi-build$ ll output/debug/
-rw-rw-r-- 1 root sudo 6100 7月 10 15:24 logs-10_07_2024-14_20_17.tgz
-rw-rw-r-- 1 root sudo 246 7月 10 15:26 logs-10_07_2024-15_24_55.tgz
-rw-rw-r-- 1 root sudo 254 7月 10 15:30 logs-10_07_2024-15_26_21.tgz
-rw-rw-r-- 1 root sudo 2253 7月 10 15:42 logs-10_07_2024-15_30_06.tgz
-rw-rw-r-- 1 root sudo 6296 7月 10 16:53 logs-10_07_2024-15_42_43.tgz
-rw-rw-r-- 1 root sudo 246 7月 10 16:55 logs-10_07_2024-16_53_05.tgz
-rw-rw-r-- 1 root sudo 4630 7月 10 17:40 logs-10_07_2024-16_55_36.tgz
-rw-rw-r-- 1 root sudo 3659 7月 10 17:45 logs-10_07_2024-17_40_27.tgz
-rw-rw-r-- 1 root sudo 3714 7月 10 17:57 logs-10_07_2024-17_45_03.tgz
-rw-rw-r-- 1 root sudo 30427 7月 10 20:20 logs-10_07_2024-17_57_14.tgz
-rw-rw-r-- 1 root root 45 7月 10 14:20 logs-.tgz
-rw-rw-r-- 1 root sudo 198 7月 10 20:20 output.log
-rw-rw-r-- 1 root root 20 7月 10 20:20 timestamp
在该路径下存放在一周内的编译日志。
2.1.4 设置缓存路径
这段脚本片段的作用是根据条件设置ccache
的相关环境变量和路径:
SHOW_WARNING=yes
if [[ $USE_CCACHE != no ]]; then
CCACHE=ccache
export PATH="/usr/lib/ccache:$PATH"
# private ccache directory to avoid permission issues when using build script with "sudo"
# see https://ccache.samba.org/manual.html#_sharing_a_cache for alternative solution
[[ $PRIVATE_CCACHE == yes ]] && export CCACHE_DIR=$EXTER/cache/ccache
else
CCACHE=""
fi
由于未设置USE_CCACHE
,因此CCACHE=""
。
2.2 支持用户选择
接下来就是可视化交互页面,允许用户选择编译u-boot
、kernel
、rootfs
、image
以及版本等信息。
2.2.1 编译选项
接着创建了一个用户界面,用户可以从菜单中选择构建选项(u-boot
、kernel
、rootfs
、image
);
# if BUILD_OPT, KERNEL_CONFIGURE, BOARD, BRANCH or RELEASE are not set, display selection menu
if [[ -z $BUILD_OPT ]]; then
options+=("u-boot" "U-boot package")
options+=("kernel" "Kernel package")
options+=("rootfs" "Rootfs and all deb packages")
options+=("image" "Full OS image for flashing")
menustr="Compile image | rootfs | kernel | u-boot"
BUILD_OPT=$(whiptail --title "${titlestr}" --backtitle "${backtitle}" --notags \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
# 未选择,则退出
[[ -z $BUILD_OPT ]] && exit_with_error "No option selected"
[[ $BUILD_OPT == rootfs ]] && ROOT_FS_CREATE_ONLY="yes"
fi
假如我们选择了Full OS image for flashing
,则会设置BUILD_OPT=image
;

2.2.2 选择内核配置
假如上一步我们选择了Linux
镜像,接下来会让我们选择内核配置;
if [[ ${BUILD_OPT} =~ kernel|image ]]; then
if [[ -z $KERNEL_CONFIGURE ]]; then
options+=("no" "Do not change the kernel configuration")
options+=("yes" "Show a kernel configuration menu before compilation")
menustr="Select the kernel configuration."
KERNEL_CONFIGURE=$(whiptail --title "${titlestr}" --backtitle "$backtitle" --notags \
--menu "${menustr}" $TTY_Y $TTY_X $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $KERNEL_CONFIGURE ]] && exit_with_error "No option selected"
fi
fi
如果不需要修改内核配置,则选择第一个即可,如果需要修改内核配置,则选择第二个;

假如我们选择了第一个,那么KERNEL_CONFIGURE=no
。
2.2.3 选择开发板型号
接着是选择开发板的型号;
if [[ -z $BOARD ]]; then
#options+=("orangepir1" "Allwinner H2+ quad core 256MB RAM WiFi SPI 2xETH")
#options+=("orangepizero" "Allwinner H2+ quad core 256MB/512MB RAM WiFi SPI")
#options+=("orangepipc" "Allwinner H3 quad core 1GB RAM")
#options+=("orangepipcplus" "Allwinner H3 quad core 1GB RAM WiFi eMMC")
#options+=("orangepione" "Allwinner H3 quad core 512MB RAM")
#options+=("orangepilite" "Allwinner H3 quad core 512MB RAM WiFi")
......
options+=("orangepi3b" "Rockchip RK3566 quad core 2-8GB RAM GBE eMMC USB3 NvMe WiFi/BT")
#options+=("orangepir1plus" "Rockchip RK3328 quad core 1GB RAM 2xGBE USB2 SPI")
#options+=("orangepi3plus" "Amlogic S905D3 quad core 2/4GB RAM SoC eMMC GBE USB3 SPI WiFi/BT")
menustr="Please choose a Board."
BOARD=$(whiptail --title "${titlestr}" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $BOARD ]] && exit_with_error "No option selected"
fi
假如我们选择了orangepi3b
,那么将会设置BOARD=orangepi3b
。
2.2.4 加载板载配置
假如我们选择的开发板型号为orangepi3b
,那么将会加载板载配置文件external/config/boards/orangepi3b.conf
;
BOARD_TYPE="conf"
# shellcheck source=/dev/null
source "${EXTER}/config/boards/${BOARD}.${BOARD_TYPE}"
# 设置为rockchip-rk356x
LINUXFAMILY="${BOARDFAMILY}"
# 不会进入
[[ -z $KERNEL_TARGET ]] && exit_with_error "Board configuration does not define valid kernel config"
orangepi3b.conf
内容如下:
# Rockchip RK3566 hexa core 4GB RAM SoC GBE eMMC USB3 USB-C WiFi/BT
BOARD_NAME="OPI 3B"
BOARDFAMILY="rockchip-rk356x"
BOOTCONFIG="orangepi-3b-rk3566_defconfig"
KERNEL_TARGET="legacy,current"
BOOT_LOGO="desktop"
BOOT_SUPPORT_SPI="yes"
DISTRIB_TYPE_LEGACY="focal jammy bullseye bookworm raspi"
BOOTFS_TYPE="fat"
IMAGE_PARTITION_TABLE="gpt"
REVISION="1.0.6"
2.2.5 选择内核版本
接着是选择内核版本;
# 进入,选择源码分支
if [[ -z $BRANCH ]]; then
# 定义数组
options=()
# 根据支持项定义菜单选项
[[ $KERNEL_TARGET == *current* ]] && options+=("current" "Recommended. Come with best support")
[[ $KERNEL_TARGET == *legacy* ]] && options+=("legacy" "Old stable / Legacy")
[[ $KERNEL_TARGET == *next* ]] && options+=("next" "Use the latest kernel")
menustr="Select the target kernel branch\nExact kernel versions depend on selected board"
# do not display selection dialog if only one kernel branch is available
if [[ "${#options[@]}" == 2 ]]; then
BRANCH="${options[0]}"
else
BRANCH=$(whiptail --title "${titlestr}" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
fi
unset options
[[ -z $BRANCH ]] && exit_with_error "No kernel branch selected"
[[ $BRANCH == dev && $SHOW_WARNING == yes ]] && show_developer_warning
fi
由于KERNEL_TARGET="legacy,current"
,因此支持的选项如下;

假如我们选择了current
,那么BRANCH=current
。
2.2.6 选择Linux
发行版的类型
2.2.6.1 Linux
发行版
首先是选择Linux
发行版的类型;
if [[ $BUILD_OPT =~ rootfs|image && -z $RELEASE ]]; then
options=()
distros_options
menustr="Select the target OS release package base"
RELEASE=$(whiptail --title "Choose a release package base" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
#echo "options : ${options}"
[[ -z $RELEASE ]] && exit_with_error "No release selected"
unset options
fi
distros_options
定义在general.sh
中,用于获取Linux
发行版的类型;

假如我们选择了bullseye Debian 11 Bullseye
,那么RELEASE=bullseye
。
2.2.6.2 镜像类型
接着是选择镜像的类型;
if [[ $BUILD_OPT =~ rootfs|image && -z $BUILD_DESKTOP ]]; then
# read distribution support status which is written to the orangepi-release file
set_distribution_status
options=()
options+=("no" "Image with console interface (server)")
options+=("yes" "Image with desktop environment")
menustr="Select the target image type"
BUILD_DESKTOP=$(whiptail --title "Choose image type" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $BUILD_DESKTOP ]] && exit_with_error "No option selected"
if [[ ${BUILD_DESKTOP} == "yes" ]]; then
BUILD_MINIMAL=no
SELECTED_CONFIGURATION="desktop"
fi
其中:
-
Image with console interface (server)
表示服务器版的镜像,体积比较小; -
Image with desktop environmen
表示带桌面的镜像,体积比较大。
如果我们选择Image with console interface (server)
,BUILD_DESKTOP=no
;

2.2.6.3 Standard/Minimal
如果是编译服务器版的镜像,还可以选择编译Standard
版本或者Minimal
版本,Minimal
版本预装的软件会比Standard
版本少很多(没特殊需求请不要选择Minimal
版本,因为很多东西默认没有预装,部分功能可能用不了);
if [[ $BUILD_OPT =~ rootfs|image && $BUILD_DESKTOP == no && -z $BUILD_MINIMAL ]]; then
options=()
options+=("no" "Standard image with console interface")
options+=("yes" "Minimal image with console interface")
menustr="Select the target image type"
BUILD_MINIMAL=$(whiptail --title "Choose image type" --backtitle "${backtitle}" \
--menu "${menustr}" "${TTY_Y}" "${TTY_X}" $((TTY_Y - 8)) \
--cancel-button Exit --ok-button Select "${options[@]}" \
3>&1 1>&2 2>&3)
unset options
[[ -z $BUILD_MINIMAL ]] && exit_with_error "No option selected"
if [[ $BUILD_MINIMAL == "yes" ]]; then
SELECTED_CONFIGURATION="cli_minimal"
else
SELECTED_CONFIGURATION="cli_standard"
fi
fi
如果我们选择了Standard image with console interface
,BUILD_MINIMAL=no
、SELECTED_CONFIGURATION=cli_standard
;

2.3 加载configuration.sh
接着是使用source
命令执行configuration.sh
脚本,脚本位于<SDK>/scripts
目录下,该脚本内容也比较多,后面我们单独介绍。
#shellcheck source=configuration.sh
source "${SRC}"/scripts/configuration.sh
2.4 变量定义
接着是一些变量定义,比如定义了BSP_CLI
包名、BSP_DESKTOP
包名;
branch2dir() {
[[ "${1}" == "head" ]] && echo "HEAD" || echo "${1##*:}"
}
# <SDK>/u-boot/v2017.09-rk3588
BOOTSOURCEDIR="${BOOTDIR}/$(branch2dir "${BOOTBRANCH}")"
# <SDK>/u-boot/orange-pi-6.6-rk35xx
LINUXSOURCEDIR="${KERNELDIR}/$(branch2dir "${KERNELBRANCH}")"
[[ -n $ATFSOURCE ]] && ATFSOURCEDIR="${ATFDIR}/$(branch2dir "${ATFBRANCH}")"
# orangepi-bsp-cli-orangepi3b
BSP_CLI_PACKAGE_NAME="orangepi-bsp-cli-${BOARD}"
# orangepi-bsp-cli-orangepi3b_1.0.6_arm64
BSP_CLI_PACKAGE_FULLNAME="${BSP_CLI_PACKAGE_NAME}_${REVISION}_${ARCH}"
# orangepi-bsp-desktop--orangepi3b
BSP_DESKTOP_PACKAGE_NAME="orangepi-bsp-desktop-${BOARD}"
# orangepi-bsp-desktop--orangepi3b_1.0.6_arm64
BSP_DESKTOP_PACKAGE_FULLNAME="${BSP_DESKTOP_PACKAGE_NAME}_${REVISION}_${ARCH}"
# linux-u-boot-current-orangepi3b
CHOSEN_UBOOT=linux-u-boot-${BRANCH}-${BOARD}
# linux-image-current-rockchip-rk356x
CHOSEN_KERNEL=linux-image-${BRANCH}-${LINUXFAMILY}
# orangepi-bsp-cli-orangepi3b
CHOSEN_ROOTFS=${BSP_CLI_PACKAGE_NAME}
CHOSEN_DESKTOP=orangepi-${RELEASE}-desktop-${DESKTOP_ENVIRONMENT}
# linux-source-current-rockchip-rk356x
CHOSEN_KSRC=linux-source-${BRANCH}-${LINUXFAMILY}
2.5 do_default
文件最后调用了do_default
函数,我们将该函数分为以下几段莱介绍。
2.5.1 源码下载
如果没有设置IGNORE_UPDATES="yes"
,将会通过调用fetch_from_repo
依次下载:
u-boot
:从https://github.com/orangepi-xunlong/u-boot-orangepi.git
下载u-boot
源码;kernel
;从https://github.com/orangepi-xunlong/linux-orangepi.git
下载内核源码;rootfs
:从https://github.com/orangepi-xunlong/rk-rootfs-build.git
下载根文件系统;
脚本如下:
# fetch_from_repo <url> <dir> <ref> <subdir_flag>
# ignore updates help on building all images - for internal purposes
if [[ ${IGNORE_UPDATES} != yes ]]; then
display_alert "Downloading sources" "" "info"
# 下载u-boot源码
[[ $BUILD_OPT =~ u-boot|image ]] && fetch_from_repo "$BOOTSOURCE" "$BOOTDIR" "$BOOTBRANCH" "yes"
# 下载kernel源码
[[ $BUILD_OPT =~ kernel|image ]] && fetch_from_repo "$KERNELSOURCE" "$KERNELDIR" "$KERNELBRANCH" "yes"
# ATFSOURCE并没有定义 不会执行
if [[ -n ${ATFSOURCE} ]]; then
[[ ${BUILD_OPT} =~ u-boot|image ]] && fetch_from_repo "$ATFSOURCE" "${EXTER}/cache/sources/$ATFDIR" "$ATFBRANCH" "yes"
fi
# rk356x系列 下载Linux发行版
if [[ ${BOARDFAMILY} == "rockchip-rk356x" && $RELEASE =~ bullseye|focal|jammy|raspi ]]; then
[[ ${BUILD_OPT} == image ]] && fetch_from_repo "https://github.com/orangepi-xunlong/rk-rootfs-build.git" "${EXTER}/cache/sources/rk35xx_packages" "branch:rk35xx_packages"
fi
if [[ ${BOARD} =~ orangepi3|orangepi3-lts && $RELEASE =~ bullseye && $BRANCH == current ]]; then
[[ ${BUILD_OPT} == image ]] && fetch_from_repo "https://github.com/orangepi-xunlong/rk-rootfs-build.git" "${EXTER}/cache/sources/ffmpeg_kodi_${RELEASE}" "branch:ffmpeg_kodi_${RELEASE}"
fi
call_extension_method "fetch_sources_tools" <<- 'FETCH_SOURCES_TOOLS'
*fetch host-side sources needed for tools and build*
Run early to fetch_from_repo or otherwise obtain sources for needed tools.
FETCH_SOURCES_TOOLS
call_extension_method "build_host_tools" <<- 'BUILD_HOST_TOOLS'
*build needed tools for the build, host-side*
After sources are fetched, build host-side tools needed for the build.
BUILD_HOST_TOOLS
fi
2.5.1.1 u-boot
源码
下载命令:
fetch_from_repo "$BOOTSOURCE" "$BOOTDIR" "$BOOTBRANCH" "yes"
BOOTSOURCE
、BOOTDIR
、BOOTBRANCH
定义在<SDK>/external/config/sources/arm64.conf
;
GIT_SERVER="https://github.com/orangepi-xunlong"
# 源码下载地址https://github.com/orangepi-xunlong/u-boot-orangepi.git
[[ -z $BOOTSOURCE ]] && BOOTSOURCE="${GIT_SERVER}/u-boot-orangepi.git"
# 下载保存目录<SDK>/u-boot
[[ -z $BOOTDIR ]] && BOOTDIR="${SRC}/u-boot"
# 下载分支branch:v2020.04,这个值会被<SDK>/external/config/sources/families/rockchip-rk356x.conf覆盖为branch:v2017.09-rk3588
[[ -z $BOOTBRANCH ]] && BOOTBRANCH='branch:v2020.04'
因此会从https://github.com/orangepi-xunlong/u-boot-orangepi.git
下载v2017.09-rk3588
分支源码并保存到<SDK>/u-boot
目录下;
root@ubuntu:/work/sambashare/rk3566/orangepi-build# ll u-boot
drwxrwxr-x 27 root root 4096 7月 27 23:26 v2017.09-rk3588/
2.5.1.2 kernel
源码
下载命令:
fetch_from_repo "$KERNELSOURCE" "$KERNELDIR" "$KERNELBRANCH" "yes"
KERNELSOURCE
、KERNELDIR
、KERNELBRANCH
定义在<SDK>/external/config/sources/arm64.conf
;
GIT_SERVER="https://github.com/orangepi-xunlong"
# 源码下载地址https://github.com/orangepi-xunlong/linux-orangepi.git
[[ -z $KERNELSOURCE ]] && KERNELSOURCE="${GIT_SERVER}/linux-orangepi.git"
# 下载保存目录<SDK>/kernel
[[ -z $KERNELDIR ]] && KERNELDIR="${SRC}/kernel"
# 下载分支branch:orange-pi-5.4,这个值会被<SDK>/external/config/sources/families/rockchip-rk356x.conf覆盖为branch:orange-pi-6.6-rk35xx
[[ -z $KERNELBRANCH ]] && KERNELBRANCH='branch:orange-pi-5.4'
因此会从https://github.com/orangepi-xunlong/linux-orangepi.git
下载orange-pi-6.6-rk35xx
分支源码并保存到<SDK>/kernel
目录下;
root@ubuntu:/work/sambashare/rk3566/orangepi-build# ll kernel/
-rw-rw-r-- 1 root root 7034 7月 27 23:29 linux-6.6.0-rc5-rockchip-rk356x_1.0.6_arm64.buildinfo
-rw-rw-r-- 1 root root 2574 7月 27 23:29 linux-6.6.0-rc5-rockchip-rk356x_1.0.6_arm64.changes
drwxrwxr-x 28 root root 4096 7月 27 23:29 orange-pi-6.6-rk35xx/
2.5.1.3 rootfs
源码
下载命令:
fetch_from_repo "https://github.com/orangepi-xunlong/rk-rootfs-build.git" "${EXTER}/cache/sources/rk35xx_packages" "branch:rk35xx_packages"
fetch_from_repo "https://github.com/orangepi-xunlong/rk-rootfs-build.git" "${EXTER}/cache/sources/ffmpeg_kodi_${RELEASE}" "branch:ffmpeg_kodi_${RELEASE}"
首先会从https://github.com/orangepi-xunlong/rk-rootfs-build.git
下载rk35xx_packages
分支源码并保存到<SDK>/cache/sources/rk35xx_packages
目录下;

接着会从https://github.com/orangepi-xunlong/rk-rootfs-build.git
下载ffmpeg_kodi_bullseye
分支源码并保存到<SDK>/cache/sources/ffmpeg_kodi_bullseye
目录下;

不过我们发现<SDK>/external/cache/sources/rk35xx_packages
竟然是空的,并且没有创建ffmpeg_kodi_bullseye
目录。
root@ubuntu:/work/sambashare/rk3566/orangepi-build# ll external/cache/sources/rk35xx_packages
drwxrwxr-x 7 root root 4096 7月 10 17:55 .git/
root@ubuntu:/work/sambashare/rk3566/orangepi-build# ll external/cache/sources/ffmpeg_kodi_bullseye
ls: 无法访问 'external/cache/sources/ffmpeg_kodi_bullseye': 没有那个文件或目录
2.5.2 清理工作
下载完源码之后,是进行上一次编译的清理工作;
for option in $(tr ',' ' ' <<< "$CLEAN_LEVEL"); do
[[ $option != sources ]] && cleaning "$option"
done
CLEAN_LEVEL
默认被配置为debs,oldcache
,定义在<SDK>/userpatches/config-default.conf
;
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
这里使用tr
命令将CLEAN_LEVEL
中的逗号替换为空格,这样可以将逗号分隔的选项转换成空格分隔的选项列表。
然后执行cleaning
函数,入参依次外debs
、oldcache
,该函数定义在scripts/general.sh
。
如果我们没有对u-boot
、kernel
进行修改,我们就可以不清理u-boot
、kernel
编译生成的deb
包,即修改:
CLEAN_LEVEL="oldcache"
这样就不会重新编译u-boot
、kernel
。
2.5.3 编译u-boot
接着是进行u-boot
的编译,首先判断u-boot deb
包是否存在,如果不存在无非是进入u-boot
源码执行配置、编译;
# Compile u-boot if packed .deb does not exist or use the one from Orange Pi
if [[ $BUILD_OPT == u-boot || $BUILD_OPT == image ]]; then
# 判断 <SDK>/output/debs/u-boot/linux-u-boot-current-orangepi3b_1.0.6_arm64.deb文件是否存在,如果不存在
if [[ ! -f "${DEB_STORAGE}"/u-boot/${CHOSEN_UBOOT}_${REVISION}_${ARCH}.deb ]]; then
# ATFSOURCE未定义
[[ -n "${ATFSOURCE}" && "${REPOSITORY_INSTALL}" != *u-boot* ]] && compile_atf
# REPOSITORY_INSTALL未定义,因此执行compile_uboot
[[ ${REPOSITORY_INSTALL} != *u-boot* ]] && compile_uboot
fi
if [[ $BUILD_OPT == "u-boot" ]]; then
unset BUILD_MINIMAL BUILD_DESKTOP COMPRESS_OUTPUTIMAGE
display_alert "U-boot build done" "@host" "info"
display_alert "Target directory" "${DEB_STORAGE}/u-boot" "info"
display_alert "File name" "${CHOSEN_UBOOT}_${REVISION}_${ARCH}.deb" "info"
fi
fi
我们查看编译生成的u-boot deb
包:
root@ubuntu:/work/sambashare/rk3566/orangepi-build# ll output/debs/u-boot/linux-u-boot-current-orangepi3b_1.0.6_arm64.deb
-rw-r--r-- 1 root sudo 553488 7月 27 23:26 output/debs/u-boot/linux-u-boot-current-orangepi3b_1.0.6_arm64.deb
2.5.4 编译kernel
接着是进行kernel
的编译,首先判断kernel deb
包是否存在,如果不存在无非是进入kernel
源码执行配置、编译;
# Compile kernel if packed .deb does not exist or use the one from Orange Pi
if [[ $BUILD_OPT == kernel || $BUILD_OPT == image ]]; then
# 判断 <SDK>/output/debs/linux-image-current-rockchip-rk356x_1.0.6_arm64.deb文件是否存在,如果不存在
if [[ ! -f ${DEB_STORAGE}/${CHOSEN_KERNEL}_${REVISION}_${ARCH}.deb ]]; then
# KDEB_CHANGELOG_DIST=bullseye
KDEB_CHANGELOG_DIST=$RELEASE
# REPOSITORY_INSTALL未定义,因此执行compile_kernel
[[ "${REPOSITORY_INSTALL}" != *kernel* ]] && compile_kernel
fi
if [[ $BUILD_OPT == "kernel" ]]; then
unset BUILD_MINIMAL BUILD_DESKTOP COMPRESS_OUTPUTIMAGE
display_alert "Kernel build done" "@host" "info"
display_alert "Target directory" "${DEB_STORAGE}/" "info"
display_alert "File name" "${CHOSEN_KERNEL}_${REVISION}_${ARCH}.deb" "info"
fi
fi
我们查看编译生成的kernel deb
包:
root@ubuntu:/work/sambashare/rk3566/orangepi-build# ll output/debs/linux-image-current-rockchip-rk356x_1.0.6_arm64.deb
-rw-r--r-- 1 root sudo 40466004 7月 27 23:29 output/debs/linux-image-current-rockchip-rk356x_1.0.6_arm64.deb
2.5.5 构建rootfs
和Linux
镜像
接着是进行Linux
镜像的构建,这里会判断如下包是否存在,不存在则会编译生成;
-
<SDK>/output/debs/orangepi-config_1.0.6_all.deb
:compile_orangepi
编译生成; -
<SDK>/output/debs/orangepi-zsh_1.0.6_all.deb
:compile_orangepi
编译生成; -
<SDK>/output/debs/orangepi-plymouth-theme_1.0.6_all.deb
:compile_plymouth-theme-orangepi
编译生成; -
<SDK>/output/debs/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb
:create_board_package
编译生成;
最后调用debootstrap_ng
开始构建rootfs
文件系统以及Linux
镜像文件(统一固件)。
脚本如下:
if [[ $BUILD_OPT == rootfs || $BUILD_OPT == image ]]; then
# Compile orangepi-config if packed .deb does not exist or use the one from Orange Pi
# <SDK>/output/debs/orangepi-config_1.0.6_all.deb
if [[ ! -f ${DEB_STORAGE}/orangepi-config_${REVISION}_all.deb ]]; then
[[ "${REPOSITORY_INSTALL}" != *orangepi-config* ]] && compile_orangepi-config
fi
# Compile orangepi-zsh if packed .deb does not exist or use the one from repository
# <SDK>/output/debs/orangepi-zsh_1.0.6_all.deb
if [[ ! -f ${DEB_STORAGE}/orangepi-zsh_${REVISION}_all.deb ]]; then
[[ "${REPOSITORY_INSTALL}" != *orangepi-zsh* ]] && compile_orangepi-zsh
fi
# Compile plymouth-theme-orangepi if packed .deb does not exist or use the one from repository
# <SDK>/output/debs/orangepi-plymouth-theme_1.0.6_all.deb
if [[ ! -f ${DEB_STORAGE}/plymouth-theme-orangepi_${REVISION}_all.deb ]]; then
[[ "${REPOSITORY_INSTALL}" != *plymouth-theme-orangepi* ]] && compile_plymouth-theme-orangepi
fi
# Compile orangepi-firmware if packed .deb does not exist or use the one from repository
# <SDK>/output/debs/orangepi-firmware_1.0.6_all.deb
if [[ "${REPOSITORY_INSTALL}" != *orangepi-firmware* ]]; then
if ! ls "${DEB_STORAGE}/orangepi-firmware_${REVISION}_all.deb" 1> /dev/null 2>&1; then
FULL=""
REPLACE="-full"
compile_firmware
fi
fi
overlayfs_wrapper "cleanup"
# create board support package, <SDK>/output/debs/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb
[[ -n $RELEASE && ! -f ${DEB_STORAGE}/$RELEASE/${BSP_CLI_PACKAGE_FULLNAME}.deb ]] && create_board_package
# create desktop package,我们未配置桌面环境,因此不会进入
[[ -n $RELEASE && $DESKTOP_ENVIRONMENT ]] && create_desktop_package
[[ -n $RELEASE && $DESKTOP_ENVIRONMENT ]] && create_bsp_desktop_package
# build additional packages,EXTERNAL_NEW="prebuilt"因此也不会进入
[[ $EXTERNAL_NEW == compile ]] && chroot_build_packages
[[ $BSP_BUILD != yes ]] && debootstrap_ng
fi
2.5.5 其它
最后执行用户自定义的hook
函数run_after_build
,并输出构建完成的日志信息;
# hook for function to run after build, i.e. to change owner of $SRC
# NOTE: this will run only if there were no errors during build process
[[ $(type -t run_after_build) == function ]] && run_after_build || true
end=$(date +%s)
runtime=$(((end-start)/60))
display_alert "Runtime" "$runtime min" "info"
# Make it easy to repeat build by displaying build options used
[ "$(systemd-detect-virt)" == 'docker' ] && BUILD_CONFIG='docker'
display_alert "Repeat Build Options" "sudo ./build.sh ${BUILD_CONFIG} BOARD=${BOARD} BRANCH=${BRANCH} \
$([[ -n $BUILD_OPT ]] && echo "BUILD_OPT=${BUILD_OPT} ")\
$([[ -n $RELEASE ]] && echo "RELEASE=${RELEASE} ")\
$([[ -n $BUILD_MINIMAL ]] && echo "BUILD_MINIMAL=${BUILD_MINIMAL} ")\
$([[ -n $BUILD_DESKTOP ]] && echo "BUILD_DESKTOP=${BUILD_DESKTOP} ")\
$([[ -n $KERNEL_CONFIGURE ]] && echo "KERNEL_CONFIGURE=${KERNEL_CONFIGURE} ")\
$([[ -n $DESKTOP_ENVIRONMENT ]] && echo "DESKTOP_ENVIRONMENT=${DESKTOP_ENVIRONMENT} ")\
$([[ -n $DESKTOP_ENVIRONMENT_CONFIG_NAME ]] && echo "DESKTOP_ENVIRONMENT_CONFIG_NAME=${DESKTOP_ENVIRONMENT_CONFIG_NAME} ")\
$([[ -n $DESKTOP_APPGROUPS_SELECTED ]] && echo "DESKTOP_APPGROUPS_SELECTED=\"${DESKTOP_APPGROUPS_SELECTED}\" ")\
$([[ -n $DESKTOP_APT_FLAGS_SELECTED ]] && echo "DESKTOP_APT_FLAGS_SELECTED=\"${DESKTOP_APT_FLAGS_SELECTED}\" ")\
$([[ -n $COMPRESS_OUTPUTIMAGE ]] && echo "COMPRESS_OUTPUTIMAGE=${COMPRESS_OUTPUTIMAGE} ")\
" "ext"
三、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
。
3.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
}
3.2 prepare_host_basic
prepare_host_basic
为宿主机ubuntu 22.04
系统安装基础包,比如dialog
、uuid
、uuid-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=(
"whiptail:whiptail"
"dialog:dialog"
"fuser:psmisc"
"getfacl:acl"
"uuid:uuid uuid-runtime"
"curl:curl"
"gpg:gnupg"
"gawk:gawk"
"git:git"
)
for check_pack in "${checklist[@]}"; do
# 使用which命令检查 ${check_pack%:*}是否存在,如果不存在(即返回非零退出码),则将${check_pack#*:}添加到install_pack变量中。
# ${check_pack%:*}:删除最后一个冒号:及其右侧的部分,保留左侧的命令名称部分
# ${check_pack#*:}:删除第一个冒号:及其左侧的部分,保留右侧的软件包名称部分
if ! which ${check_pack%:*} >/dev/null; then local install_pack+=${check_pack#*:}" "; fi
done
# 不为空,则显示安装基本软件包
if [[ -n $install_pack ]]; then
display_alert "Installing basic packages" "$install_pack"
sudo bash -c "apt-get -qq update && apt-get install -qq -y --no-install-recommends $install_pack"
fi
}
3.3 distros_options
distros_options
函数用于获取Linux
发行版的类型;
DISTRIBUTIONS_DESC_DIR="external/config/distributions"
function distro_menu ()
{
# create a select menu for choosing a distribution based EXPERT status
local distrib_dir="${1}"
# 查目录 ${distrib_dir}是否存在且包含文件${distrib_dir}/support
if [[ -d "${distrib_dir}" && -f "${distrib_dir}/support" ]]; then
# 读取 ${distrib_dir}/support文件中的支持级别
local support_level="$(cat "${distrib_dir}/support")"
# 如果分发的支持级别不是"supported"并且EXPERT不等于"yes",则跳过该分发
if [[ "${support_level}" != "supported" && $EXPERT != "yes" ]]; then
:
else
# 读取分发的名称和全名
local distro_codename="$(basename "${distrib_dir}")"
local distro_fullname="$(cat "${distrib_dir}/name")"
local expert_infos=""
# 不会进入
[[ $EXPERT == "yes" ]] && expert_infos="(${support_level})"
# 根据BRANCH的值设置DISTRIB_TYPE变量
if [[ "${BRANCH}" == "legacy" ]]; then
DISTRIB_TYPE="${DISTRIB_TYPE_LEGACY}"
[[ -z "${DISTRIB_TYPE_LEGACY}" ]] && DISTRIB_TYPE="buster bionic focal"
elif [[ "${BRANCH}" == "current" ]]; then
DISTRIB_TYPE="${DISTRIB_TYPE_CURRENT}"
[[ -z "${DISTRIB_TYPE_CURRENT}" ]] && DISTRIB_TYPE="bullseye bookworm focal jammy"
elif [[ "${BRANCH}" == "next" ]]; then
if [[ -n "${DISTRIB_TYPE_NEXT}" ]]; then
DISTRIB_TYPE="${DISTRIB_TYPE_NEXT}"
else
DISTRIB_TYPE="${DISTRIB_TYPE_CURRENT}"
[[ -z "${DISTRIB_TYPE_CURRENT}" ]] && DISTRIB_TYPE="bullseye bookworm focal jammy"
fi
fi
if [[ "${DISTRIB_TYPE}" =~ "${distro_codename}" ]]; then
options+=("${distro_codename}" "${distro_fullname} ${expert_infos}")
fi
fi
fi
}
function distros_options() {
for distrib_dir in "${DISTRIBUTIONS_DESC_DIR}/"*; do
distro_menu "${distrib_dir}"
done
}
我们查看external/config/distributions
目录;
root@ubuntu:/work/sambashare/rk3566/orangepi-build$ ll external/config/distributions
drwxr-xr-x 2 root root 4096 7月 10 13:40 bionic/
drwxr-xr-x 2 root root 4096 7月 10 13:40 bookworm/
drwxr-xr-x 2 root root 4096 7月 10 13:40 bullseye/
drwxr-xr-x 2 root root 4096 7月 10 13:40 buster/
drwxr-xr-x 2 root root 4096 7月 10 13:40 focal/
drwxr-xr-x 2 root root 4096 7月 10 13:40 jammy/
drwxr-xr-x 2 root root 4096 7月 10 13:40 raspi/
-rw-r--r-- 1 root root 297 7月 10 13:40 README.md
drwxr-xr-x 2 root root 4096 7月 10 13:40 sid/
drwxr-xr-x 2 root root 4096 7月 10 13:40 stretch/
drwxr-xr-x 2 root root 4096 7月 10 13:40 xenial/
以bullseye
目录为例;
root@ubuntu:/work/sambashare/rk3566/orangepi-build$ ll external/config/distributions/bullseye/
-rw-r--r-- 1 root root 19 7月 10 13:40 name
-rw-r--r-- 1 root root 10 7月 10 13:40 support
查看support
文件内容,这里为supported
,所以support_level=supported
;
查看name
文件内容,这里为Debian 11 Bullseye
,所以distro_codename=bullseye
、distro_fullname=Debian 11 Bullseye
;
所以当BRANCH=current
时,设置DISTRIB_TYPE=bullseye bookworm focal jammy
;
DISTRIB_TYPE="${DISTRIB_TYPE_CURRENT}"
[[ -z "${DISTRIB_TYPE_CURRENT}" ]] && DISTRIB_TYPE="bullseye bookworm focal jammy"
函数最后设置:
options+=("${distro_codename}" "${distro_fullname} ${expert_infos}")
即:
bullseye Debian 11 Bullseye
3.4 fetch_from_repo
fetch_from_repo
用于源码下载,接收三个参数:
url
:源码下载地址directory
:源码下载下来的存放目录;ref
:下载的branch/tag
名称;ref_subdir
:是否为该branch/tag
创建子目录;
由于源码较多,就不一一分析了;
View Code
# fetch_from_repo <url> <directory> <ref> <ref_subdir>
# <url>: remote repository URL
# <directory>: local directory; subdir for branch/tag will be created
# <ref>:
# branch:name
# tag:name
# head(*)
# commit:hash
#
# *: Implies ref_subdir=no
#
# <ref_subdir>: "yes" to create subdirectory for tag or branch name
#
fetch_from_repo()
{
local url=$1
local dir=$2
local ref=$3
local ref_subdir=$4
# Set GitHub mirror before anything else touches $url
url=${url//'https://github.com/'/$GITHUB_SOURCE'/'}
# The 'offline' variable must always be set to 'true' or 'false'
if [ "$OFFLINE_WORK" == "yes" ]; then
local offline=true
else
local offline=false
fi
[[ -z $ref || ( $ref != tag:* && $ref != branch:* && $ref != head && $ref != commit:* ) ]] && exit_with_error "Error in configuration"
local ref_type=${ref%%:*}
if [[ $ref_type == head ]]; then
local ref_name=HEAD
else
local ref_name=${ref##*:}
fi
display_alert "Checking git sources" "$dir $ref_name" "info"
# get default remote branch name without cloning
# local ref_name=$(git ls-remote --symref $url HEAD | grep -o 'refs/heads/\S*' | sed 's%refs/heads/%%')
# for git:// protocol comparing hashes of "git ls-remote -h $url" and "git ls-remote --symref $url HEAD" is needed
if [[ $ref_subdir == yes ]]; then
local workdir=$dir/$ref_name
else
local workdir=$dir
fi
mkdir -p "${workdir}" 2>/dev/null || \
exit_with_error "No path or no write permission" "${workdir}"
cd "${workdir}" || exit
# check if existing remote URL for the repo or branch does not match current one
# may not be supported by older git versions
# Check the folder as a git repository.
# Then the target URL matches the local URL.
if [[ "$(git rev-parse --git-dir 2>/dev/null)" == ".git" && \
"$url" != *"$(git remote get-url origin | sed 's/^.*@//' | sed 's/^.*\/\///' 2>/dev/null)" ]]; then
display_alert "Remote URL does not match, removing existing local copy"
rm -rf .git ./*
fi
if [[ "$(git rev-parse --git-dir 2>/dev/null)" != ".git" ]]; then
display_alert "Creating local copy"
git init -q .
git remote add origin "${url}"
# Here you need to upload from a new address
offline=false
fi
local changed=false
# when we work offline we simply return the sources to their original state
if ! $offline; then
local local_hash
local_hash=$(git rev-parse @ 2>/dev/null)
case $ref_type in
branch)
# TODO: grep refs/heads/$name
local remote_hash
remote_hash=$(improved_git ls-remote -h "${url}" "$ref_name" | head -1 | cut -f1)
[[ -z $local_hash || "${local_hash}" != "${remote_hash}" ]] && changed=true
;;
tag)
local remote_hash
remote_hash=$(improved_git ls-remote -t "${url}" "$ref_name" | cut -f1)
if [[ -z $local_hash || "${local_hash}" != "${remote_hash}" ]]; then
remote_hash=$(improved_git ls-remote -t "${url}" "$ref_name^{}" | cut -f1)
[[ -z $remote_hash || "${local_hash}" != "${remote_hash}" ]] && changed=true
fi
;;
head)
local remote_hash
remote_hash=$(improved_git ls-remote "${url}" HEAD | cut -f1)
[[ -z $local_hash || "${local_hash}" != "${remote_hash}" ]] && changed=true
;;
commit)
[[ -z $local_hash || $local_hash == "@" ]] && changed=true
;;
esac
fi # offline
if [[ $changed == true ]]; then
# remote was updated, fetch and check out updates
display_alert "Fetching updates"
case $ref_type in
branch) improved_git fetch --depth 200 origin "${ref_name}" ;;
tag) improved_git fetch --depth 200 origin tags/"${ref_name}" ;;
head) improved_git fetch --depth 200 origin HEAD ;;
esac
# commit type needs support for older git servers that doesn't support fetching id directly
if [[ $ref_type == commit ]]; then
improved_git fetch --depth 200 origin "${ref_name}"
# cover old type
if [[ $? -ne 0 ]]; then
display_alert "Commit checkout not supported on this repository. Doing full clone." "" "wrn"
improved_git pull
git checkout -fq "${ref_name}"
display_alert "Checkout out to" "$(git --no-pager log -2 --pretty=format:"$ad%s [%an]" | head -1)" "info"
else
display_alert "Checking out"
git checkout -f -q FETCH_HEAD
git clean -qdf
fi
else
display_alert "Checking out"
git checkout -f -q FETCH_HEAD
git clean -qdf
fi
elif [[ -n $(git status -uno --porcelain --ignore-submodules=all) ]]; then
# working directory is not clean
display_alert " Cleaning .... " "$(git status -s | wc -l) files"
# Return the files that are tracked by git to the initial state.
git checkout -f -q HEAD
# Files that are not tracked by git and were added
# when the patch was applied must be removed.
git clean -qdf
else
# working directory is clean, nothing to do
display_alert "Up to date"
fi
if [[ -f .gitmodules ]]; then
display_alert "Updating submodules" "" "ext"
# FML: http://stackoverflow.com/a/17692710
for i in $(git config -f .gitmodules --get-regexp path | awk '{ print $2 }'); do
cd "${workdir}" || exit
local surl sref
surl=$(git config -f .gitmodules --get "submodule.$i.url")
sref=$(git config -f .gitmodules --get "submodule.$i.branch")
if [[ -n $sref ]]; then
sref="branch:$sref"
else
sref="head"
fi
fetch_from_repo "$surl" "$workdir/$i" "$sref"
done
fi
} #############################################################################
3.5 cleaning
cleaning
执行一些清理工作,支持的选项有:
-
debs
:删除u-boot
、kernel
、bsp
等deb
包,这些包均位于<SDK>/output/debs
目录; -
ubootdebs
:删除u-boot deb
包,比如我们编译生成的<SDK>/output/debs/linux-image-current-rockchip-rk356x_1.0.6_arm64.deb
; -
extras
:删除额外的deb
包,这些包位于<SDK>/output/debs/extra/bullseye
目录; -
alldebs
:删除所有的deb
包,即直接清理<SDK>/output/debs/
目录; -
cache
:删除缓存的rootfs
,即直接清理<SDK>/external/cache/rootfs
目录下的文件; -
images
:删除<SDK>/output/images
目录下的文件,比如我们编译生成的Orangepi3b_1.0.6_debian_bullseye_server_linux6.6.0-rc5/
目录; -
sources
:删除缓存的源码,即直接清理<SDK>/external/cache/sources
目录下的文件; -
oldcache
:删除缓存早期的rootfs
,即清理<SDK>/external/cache/rootfs
目录下除了最新的${ROOTFS_CACHE_MAX}
个.lz4
文件之外的.lz4
文件;
脚本如下:
# cleaning <target>
#
# target: what to clean
# "make" - "make clean" for selected kernel and u-boot
# "debs" - delete output/debs for board&branch
# "ubootdebs" - delete output/debs for uboot&board&branch
# "alldebs" - delete output/debs
# "cache" - delete output/cache
# "oldcache" - remove old output/cache
# "images" - delete output/images
# "sources" - delete output/sources
#
cleaning()
{
case $1 in
# delete output/debs for board&branch
debs) # delete ${DEB_STORAGE} for current branch and family,DEB_STORAGE=<SDK>/output/debs
if [[ -d "${DEB_STORAGE}" ]]; then
display_alert "Cleaning ${DEB_STORAGE} for" "$BOARD $BRANCH" "info"
# easier than dealing with variable expansion and escaping dashes in file names
# 删除u-boot deb包,linux-u-boot-current-orangepi3b_1.0.6_arm64.deb
find "${DEB_STORAGE}" -name "${CHOSEN_UBOOT}_*.deb" -delete
# 删除kernel deb包,linux-image-current-rockchip-rk356x_1.0.6_arm64.deb
find "${DEB_STORAGE}" \( -name "${CHOSEN_KERNEL}_*.deb" -o \
-name "orangepi-*.deb" -o \
-name "plymouth-theme-orangepi_*.deb" -o \
-name "${CHOSEN_KERNEL/image/dtb}_*.deb" -o \
-name "${CHOSEN_KERNEL/image/headers}_*.deb" -o \
-name "${CHOSEN_KERNEL/image/source}_*.deb" -o \
-name "${CHOSEN_KERNEL/image/firmware-image}_*.deb" \) -delete
# 删除BSP包,<SDK>/output/debs/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb
[[ -n $RELEASE ]] && rm -f "${DEB_STORAGE}/${RELEASE}/${CHOSEN_ROOTFS}"_*.deb
[[ -n $RELEASE ]] && rm -f "${DEB_STORAGE}/${RELEASE}/orangepi-desktop-${RELEASE}"_*.deb
fi
;;
ubootdebs) # delete ${DEB_STORAGE} for uboot, current branch and family
if [[ -d "${DEB_STORAGE}" ]]; then
display_alert "Cleaning ${DEB_STORAGE} for u-boot" "$BOARD $BRANCH" "info"
# easier than dealing with variable expansion and escaping dashes in file names
find "${DEB_STORAGE}" -name "${CHOSEN_UBOOT}_*.deb" -delete
fi
;;
extras) # delete ${DEB_STORAGE}/extra/$RELEASE for all architectures
if [[ -n $RELEASE && -d ${DEB_STORAGE}/extra/$RELEASE ]]; then
display_alert "Cleaning ${DEB_STORAGE}/extra for" "$RELEASE" "info"
rm -rf "${DEB_STORAGE}/extra/${RELEASE}"
fi
;;
alldebs) # delete output/debs
[[ -d "${DEB_STORAGE}" ]] && display_alert "Cleaning" "${DEB_STORAGE}" "info" && rm -rf "${DEB_STORAGE}"/*
;;
cache) # delete output/cache
[[ -d $EXTER/cache/rootfs ]] && display_alert "Cleaning" "rootfs cache (all)" "info" && find $EXTER/cache/rootfs -type f -delete
;;
images) # delete output/images
[[ -d "${DEST}"/images ]] && display_alert "Cleaning" "output/images" "info" && rm -rf "${DEST}"/images/*
;;
sources) # delete output/sources and output/buildpkg
[[ -d $EXTER/cache/sources ]] && display_alert "Cleaning" "sources" "info" && rm -rf $EXTER/cache/sources/* "${DEST}"/buildpkg/*
;;
oldcache) # remove old `cache/rootfs` except for the newest 8 files
if [[ -d $EXTER/cache/rootfs && $(ls -1 $EXTER/cache/rootfs/*.lz4 2> /dev/null | wc -l) -gt "${ROOTFS_CACHE_MAX}" ]]; then
display_alert "Cleaning" "rootfs cache (old)" "info"
(cd $EXTER/cache/rootfs; ls -t *.lz4 | sed -e "1,${ROOTFS_CACHE_MAX}d" | xargs -d '\n' rm -f)
# Remove signatures if they are present. We use them for internal purpose
(cd $EXTER/cache/rootfs; ls -t *.asc | sed -e "1,${ROOTFS_CACHE_MAX}d" | xargs -d '\n' rm -f)
fi
;;
esac
}
四、compilation.sh
分析
compilation.sh
脚本位于<SDK>/scripts
目录下,实现了各个功能模块源码的编译,如compile_atf
、compile_uboot
、compile_kernel
、compile_firmware
、compile_orangepi-config
、compile_sunxi_tools
、install_rkbin_tools
、grab_version
、find_toolchain
、advanced_patch
、process_patch_file
、userpatch_create
、overlayfs_wrapper
。
4.1 compile_uboot
compile_uboot
函数实现了u-boot
源码的编译并生成deb
软件包。由于脚本内容较多,以下脚本会提出一些不会执行的代码,具体如下:
View Code
compile_uboot()
{
if [[ ${BOARDFAMILY} == "sun50iw9" && ${BRANCH} =~ legacy|current && $(dpkg --print-architecture) == arm64 ]]; then
.......
else
# not optimal, but extra cleaning before overlayfs_wrapper should keep sources directory clean
if [[ $CLEAN_LEVEL == *make* ]]; then
display_alert "Cleaning" "$BOOTSOURCEDIR" "info"
(cd $BOOTSOURCEDIR; make clean > /dev/null 2>&1)
fi
if [[ $USE_OVERLAYFS == yes ]]; then
local ubootdir
ubootdir=$(overlayfs_wrapper "wrap" "$BOOTSOURCEDIR" "u-boot_${LINUXFAMILY}_${BRANCH}")
else
local ubootdir="$BOOTSOURCEDIR"
fi
cd "${ubootdir}" || exit
# read uboot version
local version hash
version=$(grab_version "$ubootdir")
hash=$(improved_git --git-dir="$ubootdir"/.git rev-parse HEAD)
display_alert "Compiling u-boot" "v$version" "info"
# build aarch64
if [[ $(dpkg --print-architecture) == amd64 ]]; then
local toolchain
# 查找交叉编译工具链,UBOOT_COMPILER=aarch64-none-linux-gnu- UBOOT_USE_GCC='> 8.0'
toolchain=$(find_toolchain "$UBOOT_COMPILER" "$UBOOT_USE_GCC")
[[ -z $toolchain ]] && exit_with_error "Could not find required toolchain" "${UBOOT_COMPILER}gcc $UBOOT_USE_GCC"
# 未定义
if [[ -n $UBOOT_TOOLCHAIN2 ]]; then
......
fi
# build aarch64
fi
display_alert "Compiler version" "${UBOOT_COMPILER}gcc $(eval env PATH="${toolchain}:${toolchain2}:${PATH}" "${UBOOT_COMPILER}gcc" -dumpversion)" "info"
# 未定义
[[ -n $toolchain2 ]] && display_alert "Additional compiler version" "${toolchain2_type}gcc $(eval env PATH="${toolchain}:${toolchain2}:${PATH}" "${toolchain2_type}gcc" -dumpversion)" "info"
# create directory structure for the .deb package 创建临时目录
uboottempdir=$(mktemp -d)
chmod 700 ${uboottempdir}
trap "ret=\$?; rm -rf \"${uboottempdir}\" ; exit \$ret" 0 1 2 3 15
# linux-u-boot-current-orangepi3b_1.0.6_arm64
local uboot_name=${CHOSEN_UBOOT}_${REVISION}_${ARCH}
rm -rf $uboottempdir/$uboot_name
# 创建/tmp/xxxx/linux-u-boot-current-orangepi3b_1.0.6_arm64/usr/lib/u-boot、tmp/xxxx/linux-u-boot-current-orangepi3b_1.0.6_arm64/usr/lib/linux-u-boot-current-orangepi3b_1.0.6_arm64等目录
mkdir -p $uboottempdir/$uboot_name/usr/lib/{u-boot,$uboot_name} $uboottempdir/$uboot_name/DEBIAN
# process compilation for one or multiple targets,读取UBOOT_TARGET_MAP变量值,一次读取一行
while read -r target; do
local target_make target_patchdir target_files
# BL31=external/cache/sources/rkbin-tools/rk35/rk3568_bl31_v1.28.elf spl/u-boot-spl.bin u-boot.dtb u-boot.itb
target_make=$(cut -d';' -f1 <<< "${target}")
# target_patchdir=
target_patchdir=$(cut -d';' -f2 <<< "${target}")
# idbloader.img u-boot.itb
target_files=$(cut -d';' -f3 <<< "${target}")
# needed for multiple targets and for calling compile_uboot directly
#display_alert "Checking out to clean sources"
#improved_git checkout -f -q HEAD
if [[ $CLEAN_LEVEL == *make* ]]; then
display_alert "Cleaning" "$BOOTSOURCEDIR" "info"
(cd "${BOOTSOURCEDIR}"; make clean > /dev/null 2>&1)
fi
advanced_patch "u-boot" "$BOOTPATCHDIR" "$BOARD" "$target_patchdir" "$BRANCH" "${LINUXFAMILY}-${BOARD}-${BRANCH}"
# create patch for manual source changes
[[ $CREATE_PATCHES == yes ]] && userpatch_create "u-boot"
if [[ -n $ATFSOURCE ]]; then
cp -Rv "${atftempdir}"/*.bin .
rm -rf "${atftempdir}"
fi
# == u-boot make orangepi-3b-rk3566_defconfig ==
echo -e "\n\t== u-boot make $BOOTCONFIG ==\n" >> "${DEST}"/${LOG_SUBPATH}/compilation.log
## 先将交叉编译工具添加到环境变量PATH,然后执行make -j4 orangepi-3b-rk3566_defconfig CROSS_COMPILE=aarch64-none-linux-gnu-
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${toolchain2}:${PATH}" \
'make $CTHREADS $BOOTCONFIG \
CROSS_COMPILE="$CCACHE $UBOOT_COMPILER"' 2>> "${DEST}"/${LOG_SUBPATH}/compilation.log \
${PROGRESS_LOG_TO_FILE:+' | tee -a $DEST/${LOG_SUBPATH}/compilation.log'} \
${OUTPUT_VERYSILENT:+' >/dev/null 2>/dev/null'}
# 修改.config配置文件,比如配置BOOTDELAY
if [[ "${version}" != 2014.07 ]]; then
# orangepi specifics u-boot settings
[[ -f .config ]] && sed -i 's/CONFIG_LOCALVERSION=""/CONFIG_LOCALVERSION="-orangepi"/g' .config
[[ -f .config ]] && sed -i 's/CONFIG_LOCALVERSION_AUTO=.*/# CONFIG_LOCALVERSION_AUTO is not set/g' .config
# for modern kernel and non spi targets
if [[ ${BOOTBRANCH} =~ ^tag:v201[8-9](.*) && ${target} != "spi" && -f .config ]]; then
......
fi
if [[ ${BOARDFAMILY} == "sun50iw9" && ${BRANCH} == "next" ]]; then
......
fi
[[ -f tools/logos/udoo.bmp ]] && cp "${EXTER}"/packages/blobs/splash/udoo.bmp tools/logos/udoo.bmp
touch .scmversion
# $BOOTDELAY can be set in board family config, ensure autoboot can be stopped even if set to 0
[[ $BOOTDELAY == 0 ]] && echo -e "CONFIG_ZERO_BOOTDELAY_CHECK=y" >> .config
[[ -n $BOOTDELAY ]] && sed -i "s/^CONFIG_BOOTDELAY=.*/CONFIG_BOOTDELAY=${BOOTDELAY}/" .config || [[ -f .config ]] && echo "CONFIG_BOOTDELAY=${BOOTDELAY}" >> .config
fi
# workaround when two compilers are needed
cross_compile="CROSS_COMPILE=$CCACHE $UBOOT_COMPILER";
[[ -n $UBOOT_TOOLCHAIN2 ]] && cross_compile="ORANGEPI=foe"; # empty parameter is not allowed
# == u-boot make BL31=/work/sambashare/rk3566/orangepi-build/external/cache/sources/rkbin-tools/rk35/rk3568_bl31_v1.28.elf spl/u-boot-spl.bin u-boot.dtb u-boot.itb ==
echo -e "\n\t== u-boot make $target_make ==\n" >> "${DEST}"/${LOG_SUBPATH}/compilation.log
## 先将交叉编译工具添加到环境变量PATH,然后执行make BL31=/work/sambashare/rk3566/orangepi-build/external/cache/sources/rkbin-tools/rk35/rk3568_bl31_v1.28.elf spl/u-boot-spl.bin u-boot.dtb u-boot.itb -j4 CROSS_COMPILE=aarch64-none-linux-gnu-
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${toolchain2}:${PATH}" \
'make $target_make $CTHREADS \
"${cross_compile}"' 2>>"${DEST}"/${LOG_SUBPATH}/compilation.log \
${PROGRESS_LOG_TO_FILE:+' | tee -a "${DEST}"/${LOG_SUBPATH}/compilation.log'} \
${OUTPUT_DIALOG:+' | dialog --backtitle "$backtitle" --progressbox "Compiling u-boot..." $TTY_Y $TTY_X'} \
${OUTPUT_VERYSILENT:+' >/dev/null 2>/dev/null'} ';EVALPIPE=(${PIPESTATUS[@]})'
[[ ${EVALPIPE[0]} -ne 0 ]] && exit_with_error "U-boot compilation failed"
# 执行uboot_custom_postprocess函数
[[ $(type -t uboot_custom_postprocess) == function ]] && uboot_custom_postprocess
# copy files to build directory,拷贝编译出来的文件到构建目录
for f in $target_files; do
local f_src
f_src=$(cut -d':' -f1 <<< "${f}")
if [[ $f == *:* ]]; then
local f_dst
f_dst=$(cut -d':' -f2 <<< "${f}")
else
local f_dst
f_dst=$(basename "${f_src}")
fi
[[ ! -f $f_src ]] && exit_with_error "U-boot file not found" "$(basename "${f_src}")"
if [[ "${version}" =~ 2014.07|2011.09 ]]; then
cp "${f_src}" "$uboottempdir/packout/${f_dst}"
else
cp "${f_src}" "$uboottempdir/${uboot_name}/usr/lib/${uboot_name}/${f_dst}"
fi
done
done <<< "$UBOOT_TARGET_MAP"
# 未定义
if [[ $PACK_UBOOT == "yes" ]];then
if [[ $BOARDFAMILY =~ sun50iw1 ]]; then
......
else
pack_uboot
cp $uboottempdir/packout/{boot0_sdcard.fex,boot_package.fex} "${SRC}/.tmp/${uboot_name}/usr/lib/${uboot_name}/"
cp $uboottempdir/packout/dts/${BOARD}-u-boot.dts "${SRC}/.tmp/${uboot_name}/usr/lib/u-boot/"
fi
cd "${ubootdir}" || exit
fi
# declare -f on non-defined function does not do anything
cat <<-EOF > "$uboottempdir/${uboot_name}/usr/lib/u-boot/platform_install.sh"
DIR=/usr/lib/$uboot_name
$(declare -f write_uboot_platform)
$(declare -f write_uboot_platform_mtd)
$(declare -f setup_write_uboot_platform)
EOF
# set up control file
cat <<-EOF > "$uboottempdir/${uboot_name}/DEBIAN/control"
Package: linux-u-boot-${BOARD}-${BRANCH}
Version: $REVISION
Architecture: $ARCH
Maintainer: $MAINTAINER <$MAINTAINERMAIL>
Installed-Size: 1
Section: kernel
Priority: optional
Provides: orangepi-u-boot
Replaces: orangepi-u-boot
Conflicts: orangepi-u-boot, u-boot-sunxi
Description: Uboot loader $version
EOF
# copy config file to the package
# useful for FEL boot with overlayfs_wrapper
[[ -f .config && -n $BOOTCONFIG ]] && cp .config "$uboottempdir/${uboot_name}/usr/lib/u-boot/${BOOTCONFIG}"
# copy license files from typical locations
[[ -f COPYING ]] && cp COPYING "$uboottempdir/${uboot_name}/usr/lib/u-boot/LICENSE"
[[ -f Licenses/README ]] && cp Licenses/README "$uboottempdir/${uboot_name}/usr/lib/u-boot/LICENSE"
[[ -n $atftempdir && -f $atftempdir/license.md ]] && cp "${atftempdir}/license.md" "$uboottempdir/${uboot_name}/usr/lib/u-boot/LICENSE.atf"
display_alert "Building deb" "${uboot_name}.deb" "info"
fakeroot dpkg-deb -b -Z${DEB_COMPRESS} "$uboottempdir/${uboot_name}" "$uboottempdir/${uboot_name}.deb" >> "${DEST}"/${LOG_SUBPATH}/output.log 2>&1
rm -rf "$uboottempdir/${uboot_name}"
[[ -n $atftempdir ]] && rm -rf "${atftempdir}"
[[ ! -f $uboottempdir/${uboot_name}.deb ]] && exit_with_error "Building u-boot package failed"
rsync --remove-source-files -rq "$uboottempdir/${uboot_name}.deb" "${DEB_STORAGE}/u-boot/"
rm -rf "$uboottempdir"
fi
}
u-boot
编译包含两部分:配置和编译。
4.1.1 配置
先将交叉编译工具添加到环境变量PATH
,然后执行make -j4 orangepi-3b-rk3566_defconfig CROSS_COMPILE=aarch64-none-linux-gnu-
;
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${toolchain2}:${PATH}" \
'make $CTHREADS $BOOTCONFIG \
CROSS_COMPILE="$CCACHE $UBOOT_COMPILER"' 2>> "${DEST}"/${LOG_SUBPATH}/compilation.log \
${PROGRESS_LOG_TO_FILE:+' | tee -a $DEST/${LOG_SUBPATH}/compilation.log'} \
${OUTPUT_VERYSILENT:+' >/dev/null 2>/dev/null'}
eval
命令在shell
中用于执行参数中的命令,并将结果作为一个命令来执行。主要功能包括:
- 执行字符串:
eval
命令会将其参数作为shell
命令执行,这在需要动态生成命令或者执行复杂的命令字符串时非常有用; - 变量展开:如果参数中包含变量,
eval
命令会先展开这些变量再执行命令。这使得可以在运行时动态地构造命令; - 处理引号:
eval
可以处理包括引号在内的特殊字符,使得shell
可以正确解析参数中的命令和变量。
env
命令主要用于设置和显示环境变量。它的主要功能包括:
- 设置环境变量:可以在命令执行前设置一个或多个环境变量;
- 显示当前环境变量:如果不带参数,
env
命令会显示当前shell
的所有环境变量及其值; - 运行命令时设置环境变量:可以在命令执行时暂时设置环境变量,而不是永久更改
shell
环境。
4.1.2 编译
先将交叉编译工具添加到环境变量PATH
,然后执行make BL31=/work/sambashare/rk3566/orangepi-build/external/cache/sources/rkbin-tools/rk35/rk3568_bl31_v1.28.elf spl/u-boot-spl.bin u-boot.dtb u-boot.itb -j4 CROSS_COMPILE=aarch64-none-linux-gnu-
;
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${toolchain2}:${PATH}" \
'make $target_make $CTHREADS \
"${cross_compile}"' 2>>"${DEST}"/${LOG_SUBPATH}/compilation.log \
${PROGRESS_LOG_TO_FILE:+' | tee -a "${DEST}"/${LOG_SUBPATH}/compilation.log'} \
${OUTPUT_DIALOG:+' | dialog --backtitle "$backtitle" --progressbox "Compiling u-boot..." $TTY_Y $TTY_X'} \
${OUTPUT_VERYSILENT:+' >/dev/null 2>/dev/null'} ';EVALPIPE=(${PIPESTATUS[@]})'
4.1.3 uboot_custom_postprocess
首先执行uboot_custom_postprocess
,该函数会在u-boot
编译完成后执行,主要做一些后置处理;
[[ $(type -t uboot_custom_postprocess) == function ]] && uboot_custom_postprocess
# copy files to build directory
# target_files=idbloader.img u-boot.itb
for f in $target_files; do
local f_src
f_src=$(cut -d':' -f1 <<< "${f}")
if [[ $f == *:* ]]; then
local f_dst
f_dst=$(cut -d':' -f2 <<< "${f}")
else
local f_dst
f_dst=$(basename "${f_src}")
fi
[[ ! -f $f_src ]] && exit_with_error "U-boot file not found" "$(basename "${f_src}")"
if [[ "${version}" =~ 2014.07|2011.09 ]]; then
cp "${f_src}" "$uboottempdir/packout/${f_dst}"
else
cp "${f_src}" "$uboottempdir/${uboot_name}/usr/lib/${uboot_name}/${f_dst}"
fi
done
接着从<SDK>/u-boot/v2017.09-rk3588
拷贝idbloader.img
、 u-boot.itb
到$uboottempdir/linux-u-boot-current-orangepi3b_1.0.6_arm64/usr/lib/u-boot/linux-u-boot-current-orangepi3b_1.0.6_arm64
目录。
uboot_custom_postprocess
定义在<SDK>/external/config/sources/families/include/rockchip64_common.inc
。
u-boot
源码编译后会生成tpl/u-boot-tpl.bin
和spl/u-boot-spl.bin
文件,如果配置了BOOT_SUPPORT_SPI
:
-
那么
uboot_custom_postprocess
调用mkimage
根据external/cache/sources/rkbin-tools/rk35/rk3566_ddr_1056MHz_v1.10.bin
和spl/u-boot-spl.bin
这两个文件生成idbloader.img
; -
此外还创建了
rkspi_loader.img
镜像文件,该文件包含两个分区:-
idbloader
分区:位于0x40~0x3FF
扇区,写入idbloader.img
镜像文件; -
uboot
分区:位于0x400~0x1BFF
扇区,写入u-boot.itb
镜像文件;
-
脚本如下:
uboot_custom_postprocess()
{
# BOOT_SUPPORT_SPI="yes",进入用于生成idbloader.img、rkspi_loader.img
if [[ $BOOT_SUPPORT_SPI == yes ]]; then
if [[ $BOARDFAMILY == "rockchip-rk3588" ]]; then
......
# BOARDFAMILY="rockchip-rk356x",进入
elif [[ $BOARDFAMILY == "rockchip-rk356x" ]]; then
# external/cache/sources/rkbin-tools/rk35/rk3566_ddr_1056MHz_v1.10.bin:spl/u-boot-spl.bin -> idbloader.img
tools/mkimage -n rk3568 -T rksd -d $RKBIN_DIR/$DDR_BLOB:spl/u-boot-spl.bin idbloader.img
# 生成空白的 rkspi_loader.img 文件,大小4M
dd if=/dev/zero of=rkspi_loader.img bs=1M count=0 seek=4
# 使用parted创建GPT分区表
/sbin/parted -s rkspi_loader.img mklabel gpt
# 使用parted工具在rkspi_loader.img文件上创建一个名为idbloader的分区,起始扇区从0x40开始,终止扇区为0x3FF
/sbin/parted -s rkspi_loader.img unit s mkpart idbloader 64 1023
# 使用parted工具在rkspi_loader.img文件上创建一个名为uboot的分区,起始扇区从0x400开始,终止扇区为0x1BFF
/sbin/parted -s rkspi_loader.img unit s mkpart uboot 1024 7167
# 使用dd命令将idbloader.img文件的内容写入到rkspi_loader.img文件中idbloader分区
dd if=idbloader.img of=rkspi_loader.img seek=64 conv=notrunc
# 使用dd命令将u-boot.itb文件的内容写入到rkspi_loader.img文件中uboot分区
dd if=u-boot.itb of=rkspi_loader.img seek=1024 conv=notrunc
fi
fi
if [[ $BOOT_USE_MAINLINE_ATF == yes || $BOOT_USE_TPL_SPL_BLOB == yes ]]; then
......
elif [[ $BOOT_USE_BLOBS == yes ]]; then
......
# BOOT_SCENARIO="spl-blobs",进入
elif [[ $BOOT_SCENARIO == "spl-blobs" || $BOOT_SCENARIO == "tpl-blob-atf-mainline" ]]; then
# BOARD="orangepi3b",进入
if [[ $BOARD =~ orangepicm4|orangepi3b ]]; then
# external/cache/sources/rkbin-tools/rk35/rk3566_ddr_1056MHz_v1.10.bin:spl/u-boot-spl.bin -> idbloader.img
tools/mkimage -n rk3568 -T rksd -d $RKBIN_DIR/$DDR_BLOB:spl/u-boot-spl.bin idbloader.img
elif [[ $BOARD =~ orangepi4-lts|orangepi800 ]]; then
tools/mkimage -n rk3399 -T rksd -d $RKBIN_DIR/$DDR_BLOB:spl/u-boot-spl.bin idbloader.img
fi
:
else
echo "[uboot_custom_postprocess]: Unsupported u-boot processing configuration!"
exit 1
fi
# MERGE_UBOOT未定义不会进入
if [[ ${MERGE_UBOOT} ]]; then
......
fi
}
4.1.4 platform_install.sh
接着会在uboottempdir
目录下创建linux-u-boot-current-orangepi3b_1.0.6_arm64/usr/lib/u-boot/platform_install.sh
文件;
# declare -f on non-defined function does not do anything
cat <<-EOF > "$uboottempdir/${uboot_name}/usr/lib/u-boot/platform_install.sh"
DIR=/usr/lib/$uboot_name
$(declare -f write_uboot_platform)
$(declare -f write_uboot_platform_mtd)
$(declare -f setup_write_uboot_platform)
EOF
这里会将DIR
变量以及write_uboot_platform
、write_uboot_platform_mtd
、setup_write_uboot_platform
函数写入。
这些函数定义在<SDK>/external/config/sources/families/include/rockchip64_common.inc
。
4.1.5 control
接着会在uboottempdir
目录下创建linux-u-boot-current-orangepi3b_1.0.6_arm64/DEBIAN/control
文件;
# set up control file
cat <<-EOF > "$uboottempdir/${uboot_name}/DEBIAN/control"
Package: linux-u-boot-${BOARD}-${BRANCH}
Version: $REVISION
Architecture: $ARCH
Maintainer: $MAINTAINER <$MAINTAINERMAIL>
Installed-Size: 1
Section: kernel
Priority: optional
Provides: orangepi-u-boot
Replaces: orangepi-u-boot
Conflicts: orangepi-u-boot, u-boot-sunxi
Description: Uboot loader $version
EOF
control
文件描述软件包的名称(Package
),版本(Version
),描述(Description
)等,是deb
包必须剧本的描述性文件,以便于软件的安装管理和索引。
4.1.6 生成deb
包
最后就是构建一个名为linux-u-boot-current-orangepi3b_1.0.6_arm64
的Debian
软件包,并将其复制到指定的目标存储位置 <SDK>/output/debs/u-boot/
。
# copy config file to the package
# useful for FEL boot with overlayfs_wrapper, 将.config 复制到 ${uboottempdir}/${uboot_name}/usr/lib/u-boot/orangepi-3b-rk3566_defconfig
[[ -f .config && -n $BOOTCONFIG ]] && cp .config "$uboottempdir/${uboot_name}/usr/lib/u-boot/${BOOTCONFIG}"
# copy license files from typical locations,将COPYING复制${uboot_name}/usr/lib/u-boot/LICENSE
[[ -f COPYING ]] && cp COPYING "$uboottempdir/${uboot_name}/usr/lib/u-boot/LICENSE"
# 无
[[ -f Licenses/README ]] && cp Licenses/README "$uboottempdir/${uboot_name}/usr/lib/u-boot/LICENSE"
# 无
[[ -n $atftempdir && -f $atftempdir/license.md ]] && cp "${atftempdir}/license.md" "$uboottempdir/${uboot_name}/usr/lib/u-boot/LICENSE.atf"
# 使用fakeroot命令打包${uboottempdir}/${uboot_name}目录为${uboottempdir}/${uboot_name}.deb 文件
display_alert "Building deb" "${uboot_name}.deb" "info"
fakeroot dpkg-deb -b -Z${DEB_COMPRESS} "$uboottempdir/${uboot_name}" "$uboottempdir/${uboot_name}.deb" >> "${DEST}"/${LOG_SUBPATH}/output.log 2>&1
# 清理临时目录
rm -rf "$uboottempdir/${uboot_name}"
[[ -n $atftempdir ]] && rm -rf "${atftempdir}"
[[ ! -f $uboottempdir/${uboot_name}.deb ]] && exit_with_error "Building u-boot package failed"
# 将构建好的软件包复制到目标存储位置
rsync --remove-source-files -rq "$uboottempdir/${uboot_name}.deb" "${DEB_STORAGE}/u-boot/"
# 最终清理临时目录
rm -rf "$uboottempdir"
经过上面一系列的操作,会在临时目录$uboottempdir
下创建一个linux-u-boot-current-orangepi3b_1.0.6_arm64
文件夹,内部包含如下文件;
usr/
└── lib
├── linux-u-boot-current-orangepi3b_1.0.6_arm64
│ ├── idbloader.img
│ ├── rkspi_loader.img
│ └── u-boot.itb
└── u-boot
├── LICENSE
├── orangepi-3b-rk3566_defconfig
└── platform_install.sh
最终会通过fakeroot
工具将linux-u-boot-current-orangepi3b_1.0.6_arm64
目录打包成linux-u-boot-current-orangepi3b_1.0.6_arm64.deb
,并拷贝到<SDK>/output/debs/u-boot/
。
4.2 compile_kernel
compile_kernel
函数实现了kernel
源码的编译并生成deb
软件包。由于脚本内容较多,以下脚本会提出一些不会执行的代码,具体如下:
View Code
compile_kernel()
{
if [[ $CLEAN_LEVEL == *make* ]]; then
display_alert "Cleaning" "$LINUXSOURCEDIR" "info"
(cd ${LINUXSOURCEDIR}; make ARCH="${ARCHITECTURE}" clean >/dev/null 2>&1)
fi
if [[ $USE_OVERLAYFS == yes ]]; then
local kerneldir
kerneldir=$(overlayfs_wrapper "wrap" "$LINUXSOURCEDIR" "kernel_${LINUXFAMILY}_${BRANCH}")
else
local kerneldir="$LINUXSOURCEDIR"
fi
cd "${kerneldir}" || exit
rm -f localversion
# read kernel version
local version hash
version=$(grab_version "$kerneldir")
# read kernel git hash
hash=$(improved_git --git-dir="$kerneldir"/.git rev-parse HEAD)
# Apply a series of patches if a series file exists
if test -f "${EXTER}"/patch/kernel/${KERNELPATCHDIR}/series.conf; then
display_alert "series.conf file visible. Apply"
series_conf="${SRC}"/patch/kernel/${KERNELPATCHDIR}/series.conf
# apply_patch_series <target dir> <full path to series file>
apply_patch_series "${kerneldir}" "$series_conf"
fi
# build 3rd party drivers
# compilation_prepare
advanced_patch "kernel" "$KERNELPATCHDIR" "$BOARD" "" "$BRANCH" "$LINUXFAMILY-$BRANCH"
# create patch for manual source changes in debug mode
[[ $CREATE_PATCHES == yes ]] && userpatch_create "kernel"
# re-read kernel version after patching
local version
version=$(grab_version "$kerneldir")
display_alert "Compiling $BRANCH kernel" "$version" "info"
# compare with the architecture of the current Debian node
# if it matches we use the system compiler
if $(dpkg-architecture -e "${ARCH}"); then
display_alert "Native compilation"
elif [[ $(dpkg --print-architecture) == amd64 ]]; then
local toolchain
toolchain=$(find_toolchain "$KERNEL_COMPILER" "$KERNEL_USE_GCC")
[[ -z $toolchain ]] && exit_with_error "Could not find required toolchain" "${KERNEL_COMPILER}gcc $KERNEL_USE_GCC"
else
exit_with_error "Architecture [$ARCH] is not supported"
fi
display_alert "Compiler version" "${KERNEL_COMPILER}gcc $(eval env PATH="${toolchain}:${PATH}" "${KERNEL_COMPILER}gcc" -dumpversion)" "info"
# copy kernel config
if [[ $KERNEL_KEEP_CONFIG == yes && -f "${DEST}"/config/$LINUXCONFIG.config ]]; then
display_alert "Using previous kernel config" "${DEST}/config/$LINUXCONFIG.config" "info"
cp -p "${DEST}/config/${LINUXCONFIG}.config" .config
else
if [[ -f $USERPATCHES_PATH/$LINUXCONFIG.config ]]; then
display_alert "Using kernel config provided by user" "userpatches/$LINUXCONFIG.config" "info"
cp -p "${USERPATCHES_PATH}/${LINUXCONFIG}.config" .config
else
display_alert "Using kernel config file" "${EXTER}/config/kernel/$LINUXCONFIG.config" "info"
cp -p "${EXTER}/config/kernel/${LINUXCONFIG}.config" .config
fi
fi
call_extension_method "custom_kernel_config" << 'CUSTOM_KERNEL_CONFIG'
*Kernel .config is in place, still clean from git version*
Called after ${LINUXCONFIG}.config is put in place (.config).
Before any olddefconfig any Kconfig make is called.
A good place to customize the .config directly.
CUSTOM_KERNEL_CONFIG
# hack for deb builder. To pack what's missing in headers pack.
cp "$EXTER"/patch/misc/headers-debian-byteshift.patch /tmp
if [[ $KERNEL_CONFIGURE != yes ]]; then
if [[ $BRANCH == legacy && ! $BOARDFAMILY =~ "rockchip-rk3588"|"rockchip-rk356x" ]]; then
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${PATH}" \
'make ARCH=$ARCHITECTURE CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" silentoldconfig'
else
# TODO: check if required
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${PATH}" \
'make ARCH=$ARCHITECTURE CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" olddefconfig'
fi
else
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${PATH}" \
'make $CTHREADS ARCH=$ARCHITECTURE CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" oldconfig'
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${PATH}" \
'make $CTHREADS ARCH=$ARCHITECTURE CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" ${KERNEL_MENUCONFIG:-menuconfig}'
[[ ${PIPESTATUS[0]} -ne 0 ]] && exit_with_error "Error kernel menuconfig failed"
# store kernel config in easily reachable place
display_alert "Exporting new kernel config" "$DEST/config/$LINUXCONFIG.config" "info"
cp .config "${DEST}/config/${LINUXCONFIG}.config"
cp .config "${EXTER}/config/kernel/${LINUXCONFIG}.config"
# export defconfig too if requested
if [[ $KERNEL_EXPORT_DEFCONFIG == yes ]]; then
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${PATH}" \
'make ARCH=$ARCHITECTURE CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" savedefconfig'
[[ -f defconfig ]] && cp defconfig "${DEST}/config/${LINUXCONFIG}.defconfig"
fi
fi
# create linux-source package - with already patched sources
# We will build this package first and clear the memory.
if [[ $BUILD_KSRC != no ]]; then
create_linux-source_package
fi
echo -e "\n\t== kernel ==\n" >> "${DEST}"/${LOG_SUBPATH}/compilation.log
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${PATH}" \
'make $CTHREADS ARCH=$ARCHITECTURE \
CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" \
$SRC_LOADADDR \
LOCALVERSION="-$LINUXFAMILY" \
$KERNEL_IMAGE_TYPE ${KERNEL_EXTRA_TARGETS:-modules dtbs} 2>>$DEST/${LOG_SUBPATH}/compilation.log' \
${PROGRESS_LOG_TO_FILE:+' | tee -a $DEST/${LOG_SUBPATH}/compilation.log'} \
${OUTPUT_DIALOG:+' | dialog --backtitle "$backtitle" \
--progressbox "Compiling kernel..." $TTY_Y $TTY_X'} \
${OUTPUT_VERYSILENT:+' >/dev/null 2>/dev/null'}
if [[ ${PIPESTATUS[0]} -ne 0 || ! -f arch/$ARCHITECTURE/boot/$KERNEL_IMAGE_TYPE ]]; then
grep -i error $DEST/${LOG_SUBPATH}/compilation.log
exit_with_error "Kernel was not built" "@host"
fi
# different packaging for 4.3+
if linux-version compare "${version}" ge 4.3; then
local kernel_packing="bindeb-pkg"
else
local kernel_packing="deb-pkg"
fi
#if [[ $BRANCH == legacy && $LINUXFAMILY =~ sun50iw2|sun50iw6|sun50iw9 ]]; then
# make -C modules/gpu LICHEE_MOD_DIR=${SRC}/.tmp/gpu_modules_${LINUXFAMILY} LICHEE_KDIR=${kerneldir} CROSS_COMPILE=$toolchain/$KERNEL_COMPILER ARCH=$ARCHITECTURE
#fi
display_alert "Creating packages"
# produce deb packages: image, headers, firmware, dtb
echo -e "\n\t== deb packages: image, headers, firmware, dtb ==\n" >> "${DEST}"/${LOG_SUBPATH}/compilation.log
eval CCACHE_BASEDIR="$(pwd)" env PATH="${toolchain}:${PATH}" \
'make $CTHREADS $kernel_packing \
KDEB_PKGVERSION=$REVISION \
KDEB_COMPRESS=${DEB_COMPRESS} \
BRANCH=$BRANCH \
LOCALVERSION="-${LINUXFAMILY}" \
KBUILD_DEBARCH=$ARCH \
ARCH=$ARCHITECTURE \
DEBFULLNAME="$MAINTAINER" \
DEBEMAIL="$MAINTAINERMAIL" \
CROSS_COMPILE="$CCACHE $KERNEL_COMPILER" 2>>$DEST/${LOG_SUBPATH}/compilation.log' \
${PROGRESS_LOG_TO_FILE:+' | tee -a $DEST/${LOG_SUBPATH}/compilation.log'} \
${OUTPUT_DIALOG:+' | dialog --backtitle "$backtitle" --progressbox "Creating kernel packages..." $TTY_Y $TTY_X'} \
${OUTPUT_VERYSILENT:+' >/dev/null 2>/dev/null'}
cd .. || exit
# remove firmare image packages here - easier than patching ~40 packaging scripts at once
rm -f linux-firmware-image-*.deb
rsync --remove-source-files -rq ./*.deb "${DEB_STORAGE}/" || exit_with_error "Failed moving kernel DEBs"
}
编译完成之后,会生成linux-image-current-rockchip-rk356x_1.0.6_arm64.deb
,该文件是由<SDK>/kernel/orange-pi-6.6-rk35xx/debian/tmp/
打包生成的;
root@ubuntu:/work/sambashare/rk3566/orangepi-build/kernel/orange-pi-6.6-rk35xx/$ ll debian/tmp/
drwxr-xr-x 2 root root 4096 8月 4 09:37 boot/
drwxr-xr-x 2 root root 4096 8月 4 09:37 DEBIAN/
drwxr-xr-x 3 root root 4096 8月 4 09:37 etc/
drwxr-xr-x 3 root root 4096 8月 4 09:37 lib/
drwxr-xr-x 4 root root 4096 8月 4 09:37 usr/=
可以看到这个目录和linux-image-current-rockchip-rk356x_1.0.6_arm64.deb
解压后的内容基本是一致的。有关kernel deb
更多实现细节可以查看./scripts/package/builddeb
脚本。
4.3 compile_firmware
View Code
compile_firmware()
{
display_alert "Merging and packaging linux firmware" "@host" "info"
local firmwaretempdir plugin_dir
firmwaretempdir=$(mktemp -d)
chmod 700 ${firmwaretempdir}
trap "ret=\$?; rm -rf \"${firmwaretempdir}\" ; exit \$ret" 0 1 2 3 15
plugin_dir="orangepi-firmware${FULL}"
mkdir -p "${firmwaretempdir}/${plugin_dir}/lib/firmware"
[[ $IGNORE_UPDATES != yes ]] && fetch_from_repo "https://github.com/orangepi-xunlong/firmware" "${EXTER}/cache/sources/orangepi-firmware-git" "branch:master"
if [[ -n $FULL ]]; then
[[ $IGNORE_UPDATES != yes ]] && fetch_from_repo "$MAINLINE_FIRMWARE_SOURCE" "${EXTER}/cache/sources/linux-firmware-git" "branch:master"
# cp : create hardlinks
cp -af --reflink=auto "${EXTER}"/cache/sources/linux-firmware-git/* "${firmwaretempdir}/${plugin_dir}/lib/firmware/"
fi
# overlay our firmware
# cp : create hardlinks
cp -af --reflink=auto "${EXTER}"/cache/sources/orangepi-firmware-git/* "${firmwaretempdir}/${plugin_dir}/lib/firmware/"
# cleanup what's not needed for sure
rm -rf "${firmwaretempdir}/${plugin_dir}"/lib/firmware/{amdgpu,amd-ucode,radeon,nvidia,matrox,.git}
cd "${firmwaretempdir}/${plugin_dir}" || exit
# set up control file
mkdir -p DEBIAN
cat <<-END > DEBIAN/control
Package: orangepi-firmware${FULL}
Version: $REVISION
Architecture: all
Maintainer: $MAINTAINER <$MAINTAINERMAIL>
Installed-Size: 1
Replaces: linux-firmware, firmware-brcm80211, firmware-ralink, firmware-samsung, firmware-realtek, orangepi-firmware${REPLACE}
Section: kernel
Priority: optional
Description: Linux firmware${FULL}
END
cd "${firmwaretempdir}" || exit
# pack
mv "orangepi-firmware${FULL}" "orangepi-firmware${FULL}_${REVISION}_all"
display_alert "Building firmware package" "orangepi-firmware${FULL}_${REVISION}_all" "info"
fakeroot dpkg-deb -b -Z${DEB_COMPRESS} "orangepi-firmware${FULL}_${REVISION}_all" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
mv "orangepi-firmware${FULL}_${REVISION}_all" "orangepi-firmware${FULL}"
rsync -rq "orangepi-firmware${FULL}_${REVISION}_all.deb" "${DEB_STORAGE}/"
# remove temp directory
rm -rf "${firmwaretempdir}"
}
4.4 compile_orangepi-config
compile_orangepi-config
函数是用来编译和打包Orange Pi
的配置工具 orangepi-config
到一个Debian
包 ;
compile_orangepi-config()
{
local tmpdir=${SRC}/.tmp/orangepi-config_${REVISION}_all
display_alert "Building deb" "orangepi-config" "info"
mkdir -p "${tmpdir}"/{DEBIAN,usr/bin/,usr/sbin/,usr/lib/orangepi-config/}
# set up control file
cat <<-END > "${tmpdir}"/DEBIAN/control
Package: orangepi-config
Version: $REVISION
Architecture: all
Maintainer: $MAINTAINER <$MAINTAINERMAIL>
Replaces: orangepi-bsp
Depends: bash, iperf3, psmisc, curl, bc, expect, dialog, pv, \
debconf-utils, unzip, build-essential, html2text, apt-transport-https, html2text, dirmngr, software-properties-common
Recommends: orangepi-bsp
Suggests: libpam-google-authenticator, qrencode, network-manager, sunxi-tools
Section: utils
Priority: optional
Description: Orange Pi configuration utility
END
install -m 755 $EXTER/cache/sources/orangepi-config/scripts/tv_grab_file $tmpdir/usr/bin/tv_grab_file
install -m 755 $EXTER/cache/sources/orangepi-config/debian-config $tmpdir/usr/sbin/orangepi-config
install -m 644 $EXTER/cache/sources/orangepi-config/debian-config-jobs $tmpdir/usr/lib/orangepi-config/jobs.sh
install -m 644 $EXTER/cache/sources/orangepi-config/debian-config-submenu $tmpdir/usr/lib/orangepi-config/submenu.sh
install -m 644 $EXTER/cache/sources/orangepi-config/debian-config-functions $tmpdir/usr/lib/orangepi-config/functions.sh
install -m 644 $EXTER/cache/sources/orangepi-config/debian-config-functions-network $tmpdir/usr/lib/orangepi-config/functions-network.sh
install -m 755 $EXTER/cache/sources/orangepi-config/softy $tmpdir/usr/sbin/softy
# fallback to replace orangepi-config in BSP
ln -sf /usr/sbin/orangepi-config $tmpdir/usr/bin/orangepi-config
ln -sf /usr/sbin/softy "${tmpdir}"/usr/bin/softy
fakeroot dpkg-deb -b -Z${DEB_COMPRESS} "${tmpdir}" >/dev/null
rsync --remove-source-files -rq "${tmpdir}.deb" "${DEB_STORAGE}/"
rm -rf "${tmpdir}"
}
五、makeboarddeb.sh
makeboarddeb.sh
文件只实现了 create_board_package
函数,用于构建BSP
包orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb
,需要注意的是这个包并不是rootfs
镜像文件。
View Code
#!/bin/bash
create_board_package()
{
display_alert "Creating board support package for CLI" "$CHOSEN_ROOTFS" "info"
# 创建临时目录
bsptempdir=$(mktemp -d)
# 修改权限
chmod 700 ${bsptempdir}
# 设置信号处理器,当收到信号0/1/2/3/15 删除临时目录
trap "rm -rf \"${bsptempdir}\" ; exit 0" 0 1 2 3 15
# 设置目标目录{bsptempdir}/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64
local destination=${bsptempdir}/${RELEASE}/${BSP_CLI_PACKAGE_FULLNAME}
# 创建目录{bsptempdir}/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64/DEBIAN
mkdir -p "${destination}"/DEBIAN
cd $destination
# copy general overlay from packages/bsp-cli
copy_all_packages_files_for "bsp-cli"
# install copy of boot script & environment file
if [[ "${BOOTCONFIG}" != "none" ]]; then
# @TODO: add extension method bsp_prepare_bootloader(), refactor into u-boot extension
local bootscript_src=${BOOTSCRIPT%%:*}
local bootscript_dst=${BOOTSCRIPT##*:}
mkdir -p "${destination}"/usr/share/orangepi/
# create extlinux config file
if [[ $SRC_EXTLINUX != yes ]]; then
if [ -f "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" ]; then
cp "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" "${destination}/usr/share/orangepi/${bootscript_dst}"
else
cp "${EXTER}/config/bootscripts/${bootscript_src}" "${destination}/usr/share/orangepi/${bootscript_dst}"
fi
[[ -n $BOOTENV_FILE && -f $SRC/config/bootenv/$BOOTENV_FILE ]] && \
cp "${EXTER}/config/bootenv/${BOOTENV_FILE}" "${destination}"/usr/share/orangepi/orangepiEnv.txt
fi
# add configuration for setting uboot environment from userspace with: fw_setenv fw_printenv
if [[ -n $UBOOT_FW_ENV ]]; then
UBOOT_FW_ENV=($(tr ',' ' ' <<< "$UBOOT_FW_ENV"))
mkdir -p "${destination}"/etc
echo "# Device to access offset env size" > "${destination}"/etc/fw_env.config
echo "/dev/mmcblk0 ${UBOOT_FW_ENV[0]} ${UBOOT_FW_ENV[1]}" >> "${destination}"/etc/fw_env.config
fi
fi
# Replaces: base-files is needed to replace /etc/update-motd.d/ files on Xenial
# Replaces: unattended-upgrades may be needed to replace /etc/apt/apt.conf.d/50unattended-upgrades
# (distributions provide good defaults, so this is not needed currently)
# Depends: linux-base is needed for "linux-version" command in initrd cleanup script
# Depends: fping is needed for orangepimonitor to upload orangepi-hardware-monitor.log
cat <<-EOF > "${destination}"/DEBIAN/control
Package: ${BSP_CLI_PACKAGE_NAME}
Version: $REVISION
Architecture: $ARCH
Maintainer: $MAINTAINER <$MAINTAINERMAIL>
Installed-Size: 1
Section: kernel
Priority: optional
Depends: bash, linux-base, u-boot-tools, initramfs-tools, lsb-release, fping
Provides: linux-${RELEASE}-root-legacy-$BOARD, linux-${RELEASE}-root-current-$BOARD, linux-${RELEASE}-root-next-$BOARD
Suggests: orangepi-config
Replaces: zram-config, base-files, orangepi-tools-$RELEASE, linux-${RELEASE}-root-legacy-$BOARD (<< $REVISION~), linux-${RELEASE}-root-current-$BOARD (<< $REVISION~), linux-${RELEASE}-root-next-$BOARD (<< $REVISION~)
Breaks: linux-${RELEASE}-root-legacy-$BOARD (<< $REVISION~), linux-${RELEASE}-root-current-$BOARD (<< $REVISION~), linux-${RELEASE}-root-next-$BOARD (<< $REVISION~)
Recommends: bsdutils, parted, util-linux, toilet
Description: OrangePi board support files for $BOARD
EOF
# set up pre install script
cat <<-EOF > "${destination}"/DEBIAN/preinst
#!/bin/sh
# tell people to reboot at next login
[ "\$1" = "upgrade" ] && touch /var/run/.reboot_required
# convert link to file
if [ -L "/etc/network/interfaces" ]; then
cp /etc/network/interfaces /etc/network/interfaces.tmp
rm /etc/network/interfaces
mv /etc/network/interfaces.tmp /etc/network/interfaces
fi
# fixing ramdisk corruption when using lz4 compression method
sed -i "s/^COMPRESS=.*/COMPRESS=gzip/" /etc/initramfs-tools/initramfs.conf
# swap
grep -q vm.swappiness /etc/sysctl.conf
case \$? in
0)
sed -i 's/vm\.swappiness.*/vm.swappiness=100/' /etc/sysctl.conf
;;
*)
echo vm.swappiness=100 >>/etc/sysctl.conf
;;
esac
sysctl -p >/dev/null 2>&1
# disable deprecated services
[ -f "/etc/profile.d/activate_psd_user.sh" ] && rm /etc/profile.d/activate_psd_user.sh
[ -f "/etc/profile.d/check_first_login.sh" ] && rm /etc/profile.d/check_first_login.sh
[ -f "/etc/profile.d/check_first_login_reboot.sh" ] && rm /etc/profile.d/check_first_login_reboot.sh
[ -f "/etc/profile.d/ssh-title.sh" ] && rm /etc/profile.d/ssh-title.sh
[ -f "/etc/update-motd.d/10-header" ] && rm /etc/update-motd.d/10-header
[ -f "/etc/update-motd.d/30-sysinfo" ] && rm /etc/update-motd.d/30-sysinfo
[ -f "/etc/update-motd.d/35-tips" ] && rm /etc/update-motd.d/35-tips
[ -f "/etc/update-motd.d/40-updates" ] && rm /etc/update-motd.d/40-updates
[ -f "/etc/update-motd.d/98-autoreboot-warn" ] && rm /etc/update-motd.d/98-autoreboot-warn
[ -f "/etc/update-motd.d/99-point-to-faq" ] && rm /etc/update-motd.d/99-point-to-faq
[ -f "/etc/update-motd.d/80-esm" ] && rm /etc/update-motd.d/80-esm
[ -f "/etc/update-motd.d/80-livepatch" ] && rm /etc/update-motd.d/80-livepatch
[ -f "/etc/apt/apt.conf.d/02compress-indexes" ] && rm /etc/apt/apt.conf.d/02compress-indexes
[ -f "/etc/apt/apt.conf.d/02periodic" ] && rm /etc/apt/apt.conf.d/02periodic
[ -f "/etc/apt/apt.conf.d/no-languages" ] && rm /etc/apt/apt.conf.d/no-languages
[ -f "/etc/init.d/armhwinfo" ] && rm /etc/init.d/armhwinfo
[ -f "/etc/logrotate.d/armhwinfo" ] && rm /etc/logrotate.d/armhwinfo
[ -f "/etc/init.d/firstrun" ] && rm /etc/init.d/firstrun
[ -f "/etc/init.d/resize2fs" ] && rm /etc/init.d/resize2fs
[ -f "/lib/systemd/system/firstrun-config.service" ] && rm /lib/systemd/system/firstrun-config.service
[ -f "/lib/systemd/system/firstrun.service" ] && rm /lib/systemd/system/firstrun.service
[ -f "/lib/systemd/system/resize2fs.service" ] && rm /lib/systemd/system/resize2fs.service
[ -f "/usr/lib/orangepi/apt-updates" ] && rm /usr/lib/orangepi/apt-updates
[ -f "/usr/lib/orangepi/firstrun-config.sh" ] && rm /usr/lib/orangepi/firstrun-config.sh
# fix for https://bugs.launchpad.net/ubuntu/+source/lightdm-gtk-greeter/+bug/1897491
[ -d "/var/lib/lightdm" ] && (chown -R lightdm:lightdm /var/lib/lightdm ; chmod 0750 /var/lib/lightdm)
exit 0
EOF
chmod 755 "${destination}"/DEBIAN/preinst
# postrm script
cat <<-EOF > "${destination}"/DEBIAN/postrm
#!/bin/sh
if [ remove = "\$1" ] || [ abort-install = "\$1" ]; then
systemctl disable orangepi-hardware-monitor.service orangepi-hardware-optimize.service >/dev/null 2>&1
systemctl disable orangepi-zram-config.service orangepi-ramlog.service >/dev/null 2>&1
fi
exit 0
EOF
chmod 755 "${destination}"/DEBIAN/postrm
# set up post install script
cat <<-EOF > "${destination}"/DEBIAN/postinst
#!/bin/sh
#
# ${BOARD} BSP post installation script
#
[ -f /etc/lib/systemd/system/orangepi-ramlog.service ] && systemctl --no-reload enable orangepi-ramlog.service
# check if it was disabled in config and disable in new service
if [ -n "\$(grep -w '^ENABLED=false' /etc/default/log2ram 2> /dev/null)" ]; then
sed -i "s/^ENABLED=.*/ENABLED=false/" /etc/default/orangepi-ramlog
fi
# fix boot delay "waiting for suspend/resume device"
if [ -f "/etc/initramfs-tools/initramfs.conf" ]; then
if ! grep --quiet "RESUME=none" /etc/initramfs-tools/initramfs.conf; then
echo "RESUME=none" >> /etc/initramfs-tools/initramfs.conf
fi
fi
EOF
# install bootscripts if they are not present. Fix upgrades from old images
if [[ $FORCE_BOOTSCRIPT_UPDATE == yes ]]; then
cat <<-EOF >> "${destination}"/DEBIAN/postinst
if [ true ]; then
# this package recreate boot scripts
EOF
else
cat <<-EOF >> "${destination}"/DEBIAN/postinst
if [ ! -f /boot/$bootscript_dst ]; then
# if boot script does not exits its recreated
EOF
fi
cat <<-EOF >> "${destination}"/DEBIAN/postinst
# move bootscript to /usr/share/orangepi
# create a backup
[ -f /etc/orangepi-release ] && . /etc/orangepi-release
[ -z \${VERSION} ] && VERSION=$(echo \`date +%s\`)
if [ -f /boot/$bootscript_dst ]; then
cp /boot/$bootscript_dst /usr/share/orangepi/${bootscript_dst}-\${VERSION} >/dev/null 2>&1
echo "NOTE: You can find previous bootscript versions in /usr/share/orangepi !"
fi
# cleanup old bootscript backup
ls /usr/share/orangepi/boot.cmd-* >/dev/null 2>&1 | head -n -5 | xargs rm -f --
ls /usr/share/orangepi/boot.ini-* >/dev/null 2>&1 | head -n -5 | xargs rm -f --
echo "Recreating boot script"
cp /usr/share/orangepi/$bootscript_dst /boot >/dev/null 2>&1
rootdev=\$(sed -e 's/^.*root=//' -e 's/ .*\$//' < /proc/cmdline)
rootfstype=\$(sed -e 's/^.*rootfstype=//' -e 's/ .*$//' < /proc/cmdline)
# recreate orangepiEnv.txt if it and extlinux does not exists
if [ ! -f /boot/orangepiEnv.txt ] && [ ! -f /boot/extlinux/extlinux.conf ]; then
cp /usr/share/orangepi/orangepiEnv.txt /boot >/dev/null 2>&1
echo "rootdev="\$rootdev >> /boot/orangepiEnv.txt
echo "rootfstype="\$rootfstype >> /boot/orangepiEnv.txt
fi
[ -f /boot/boot.ini ] && sed -i "s/setenv rootdev.*/setenv rootdev \\"\$rootdev\\"/" /boot/boot.ini
[ -f /boot/boot.ini ] && sed -i "s/setenv rootfstype.*/setenv rootfstype \\"\$rootfstype\\"/" /boot/boot.ini
[ -f /boot/boot.cmd ] && mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr >/dev/null 2>&1
fi
[ ! -f "/etc/network/interfaces" ] && [ -f "/etc/network/interfaces.default" ] && cp /etc/network/interfaces.default /etc/network/interfaces
ln -sf /var/run/motd /etc/motd
rm -f /etc/update-motd.d/00-header /etc/update-motd.d/10-help-text
if [ -f "/boot/bin/$BOARD.bin" ] && [ ! -f "/boot/script.bin" ]; then ln -sf bin/$BOARD.bin /boot/script.bin >/dev/null 2>&1 || cp /boot/bin/$BOARD.bin /boot/script.bin; fi
if [ ! -f "/etc/default/orangepi-motd" ]; then
mv /etc/default/orangepi-motd.dpkg-dist /etc/default/orangepi-motd
fi
if [ ! -f "/etc/default/orangepi-ramlog" ] && [ -f /etc/default/orangepi-ramlog.dpkg-dist ]; then
mv /etc/default/orangepi-ramlog.dpkg-dist /etc/default/orangepi-ramlog
fi
if [ ! -f "/etc/default/orangepi-zram-config" ] && [ -f /etc/default/orangepi-zram-config.dpkg-dist ]; then
mv /etc/default/orangepi-zram-config.dpkg-dist /etc/default/orangepi-zram-config
fi
if [ -L "/usr/lib/chromium-browser/master_preferences.dpkg-dist" ]; then
mv /usr/lib/chromium-browser/master_preferences.dpkg-dist /usr/lib/chromium-browser/master_preferences
fi
# Read release value
if [ -f /etc/lsb-release ]; then
RELEASE=\$(cat /etc/lsb-release | grep CODENAME | cut -d"=" -f2 | sed 's/.*/\u&/')
sed -i "s/^PRETTY_NAME=.*/PRETTY_NAME=\"${VENDOR} $REVISION "\${RELEASE}"\"/" /etc/os-release
echo "${VENDOR} ${REVISION} \${RELEASE} \\l \n" > /etc/issue
echo "${VENDOR} ${REVISION} \${RELEASE}" > /etc/issue.net
fi
# Reload services
systemctl --no-reload enable orangepi-hardware-monitor.service orangepi-hardware-optimize.service orangepi-zram-config.service >/dev/null 2>&1
exit 0
EOF
chmod 755 "${destination}"/DEBIAN/postinst
# won't recreate files if they were removed by user
# TODO: Add proper handling for updated conffiles
#cat <<-EOF > "${destination}"/DEBIAN/conffiles
#EOF
# copy common files from a premade directory structure
rsync -a "${EXTER}"/packages/bsp/common/* ${destination}
# trigger uInitrd creation after installation, to apply
# /etc/initramfs/post-update.d/99-uboot
cat <<-EOF > "${destination}"/DEBIAN/triggers
activate update-initramfs
EOF
# copy distribution support status
local releases=($(find ${EXTER}/config/distributions -mindepth 1 -maxdepth 1 -type d))
for i in ${releases[@]}
do
echo "$(echo $i | sed 's/.*\///')=$(cat $i/support)" >> "${destination}"/etc/orangepi-distribution-status
done
# armhwinfo, firstrun, orangepimonitor, etc. config file
cat <<-EOF > "${destination}"/etc/orangepi-release
# PLEASE DO NOT EDIT THIS FILE
BOARD=${BOARD}
BOARD_NAME="$BOARD_NAME"
BOARDFAMILY=${BOARDFAMILY}
BUILD_REPOSITORY_URL=${BUILD_REPOSITORY_URL}
BUILD_REPOSITORY_COMMIT=${BUILD_REPOSITORY_COMMIT}
DISTRIBUTION_CODENAME=${RELEASE}
DISTRIBUTION_STATUS=${DISTRIBUTION_STATUS}
VERSION=${REVISION}
LINUXFAMILY=${LINUXFAMILY}
ARCH=${ARCHITECTURE}
IMAGE_TYPE=$IMAGE_TYPE
BOARD_TYPE=$BOARD_TYPE
INITRD_ARCH=${INITRD_ARCH}
KERNEL_IMAGE_TYPE=${KERNEL_IMAGE_TYPE}
BRANCH=${BRANCH}
EOF
# this is required for NFS boot to prevent deconfiguring the network on shutdown
sed -i 's/#no-auto-down/no-auto-down/g' "${destination}"/etc/network/interfaces.default
if [[ ( $LINUXFAMILY == sun8i ) && $BRANCH == legacy ]]; then
# add mpv config for vdpau_sunxi
mkdir -p "${destination}"/etc/mpv/
cp "${EXTER}"/packages/bsp/mpv/mpv_sunxi.conf "${destination}"/etc/mpv/mpv.conf
echo "export VDPAU_OSD=1" > "${destination}"/etc/profile.d/90-vdpau.sh
chmod 755 "${destination}"/etc/profile.d/90-vdpau.sh
fi
if [[ $LINUXFAMILY == sunxi* ]]; then
# add mpv config for x11 output - slow, but it works compared to no config at all
# TODO: Test which output driver is better with DRM
mkdir -p "${destination}"/etc/mpv/
cp "${EXTER}"/packages/bsp/mpv/mpv_mainline.conf "${destination}"/etc/mpv/mpv.conf
fi
case $RELEASE in
xenial)
if [[ $BRANCH == legacy && $LINUXFAMILY == sun8i ]]; then
# this is required only for old kernels
# not needed for Stretch since there will be no Stretch images with kernels < 4.4
mkdir -p "${destination}"/lib/systemd/system/haveged.service.d/
cp "${EXTER}"/packages/bsp/10-no-new-privileges.conf "${destination}"/lib/systemd/system/haveged.service.d/
fi
;;
esac
# execute $LINUXFAMILY-specific tweaks
[[ $(type -t family_tweaks_bsp) == function ]] && family_tweaks_bsp
call_extension_method "post_family_tweaks_bsp" << 'POST_FAMILY_TWEAKS_BSP'
*family_tweaks_bsp overrrides what is in the config, so give it a chance to override the family tweaks*
This should be implemented by the config to tweak the BSP, after the board or family has had the chance to.
POST_FAMILY_TWEAKS_BSP
# add some summary to the image
fingerprint_image "${destination}/etc/orangepi.txt"
# fixing permissions (basic), reference: dh_fixperms
find "${destination}" -print0 2>/dev/null | xargs -0r chown --no-dereference 0:0
find "${destination}" ! -type l -print0 2>/dev/null | xargs -0r chmod 'go=rX,u+rw,a-s'
# create board DEB file
fakeroot dpkg-deb -b -Z${DEB_COMPRESS} "${destination}" "${destination}.deb" >> "${DEST}"/${LOG_SUBPATH}/output.log 2>&1
mkdir -p "${DEB_STORAGE}/${RELEASE}/"
rsync --remove-source-files -rq "${destination}.deb" "${DEB_STORAGE}/${RELEASE}/"
# cleanup
rm -rf ${bsptempdir}
}
接下来我们对该函数进行一一分析。
5.1 准备工作
最开始是一系列的准备工作,具体如下。
5.1.1 确定目标路径
创建BSP
临时目录,全路径为${bsptempdir}/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64
;
# 创建临时目录
bsptempdir=$(mktemp -d)
# 修改权限
chmod 700 ${bsptempdir}
# 设置信号处理器,当收到信号0/1/2/3/15 删除临时目录
trap "rm -rf \"${bsptempdir}\" ; exit 0" 0 1 2 3 15
# 设置目标目录${bsptempdir}/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64
local destination=${bsptempdir}/${RELEASE}/${BSP_CLI_PACKAGE_FULLNAME}
# 创建目录{bsptempdir}/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64/DEBIAN
mkdir -p "${destination}"/DEBIAN
cd $destination
注意:后文我们就把$destination
这个目录称为bsp
目录。
5.1.2 拷贝bsp-cli
包
接着是将若干个目录复制到bsp
目录中;
# copy general overlay from packages/bsp-cli
copy_all_packages_files_for "bsp-cli"
copy_all_packages_files_for
函数定义在scripts/image-helpers.sh
;
# copy_all_packages_files_for <folder> to package
#
copy_all_packages_files_for()
{
# bsp-cli
local package_name="${1}"
# 遍历以下目录
# <SDK>/external/packages => 不存在子目录bsp-cli
# <SDK>/external/config/optional/_any_board/_packages => 不存在子目录bsp-cli
# <SDK>/external/config/optional/architectures/arm64/_packages => 不存在子目录bsp-cli
# <SDK>/external/config/optional/families/rockchip-rk356x/_packages
# <SDK>/external/config/optional/boards/orangepi3b/_packages => 不存在子目录bsp-cli
for package_src_dir in ${PACKAGES_SEARCH_ROOT_ABSOLUTE_DIRS};
do
# ..../bsp-cli
local package_dirpath="${package_src_dir}/${package_name}"
# 如果目录存在,则拷贝到${bsptempdir}/bullseye/orangepi-bsp-cli-orangepi3b_1.0.6_arm64
if [ -d "${package_dirpath}" ];
then
cp -r "${package_dirpath}/"* "${destination}/" 2> /dev/null
display_alert "Adding files from" "${package_dirpath}"
fi
done
}
这里只有external/config/optional/boards/orangepi3b/_packages/bsp-cli/
目录是存在的;
root@ubuntu:/work/sambashare/rk3566/orangepi-build# tree external/config/optional/boards/orangepi3b/_packages/bsp-cli/
external/config/optional/boards/orangepi3b/_packages/bsp-cli/
└── usr
└── bin
└── hciattach_opi
5.1.3 拷贝boot
脚本/环境遍历文件
接着是拷贝boot
脚本以及环境变量文件到bsp
目录;
# install copy of boot script & environment file, BOOTCONFIG="orangepi-3b-rk3566_defconfig"
if [[ "${BOOTCONFIG}" != "none" ]]; then
# @TODO: add extension method bsp_prepare_bootloader(), refactor into u-boot extension
# 提取冒号前的部分boot-rockchip64.cmd
local bootscript_src=${BOOTSCRIPT%%:*}
# 提取冒号后的部分boot.cmd
local bootscript_dst=${BOOTSCRIPT##*:}
# 在rootfs创建/usr/share/orangepi/目录
mkdir -p "${destination}"/usr/share/orangepi/
# create extlinux config file
if [[ $SRC_EXTLINUX != yes ]]; then
# 不会进入
if [ -f "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" ]; then
cp "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" "${destination}/usr/share/orangepi/${bootscript_dst}"
else
# 进入
cp "${EXTER}/config/bootscripts/${bootscript_src}" "${destination}/usr/share/orangepi/${bootscript_dst}"
fi
# BOOTENV_FILE='rockchip.txt',$SRC/config/bootenv/$BOOTENV_FILE文件不存在,不会进入
[[ -n $BOOTENV_FILE && -f $SRC/config/bootenv/$BOOTENV_FILE ]] && \
cp "${EXTER}/config/bootenv/${BOOTENV_FILE}" "${destination}"/usr/share/orangepi/orangepiEnv.txt
fi
# add configuration for setting uboot environment from userspace with: fw_setenv fw_printenv,不会进入
if [[ -n $UBOOT_FW_ENV ]]; then
UBOOT_FW_ENV=($(tr ',' ' ' <<< "$UBOOT_FW_ENV"))
mkdir -p "${destination}"/etc
echo "# Device to access offset env size" > "${destination}"/etc/fw_env.config
echo "/dev/mmcblk0 ${UBOOT_FW_ENV[0]} ${UBOOT_FW_ENV[1]}" >> "${destination}"/etc/fw_env.config
fi
fi
该段脚本会就是复制<SDK>/external/config/bootscripts/boot-rockchip64.cmd
到根文件系统/usr/share/orangepi/boot.cmd
。
5.2 DEBIAN
目录
5.2.1 创建/DEBIAN/control
接着生成一个Debian
包的控制文件 (control
),包含了必要的元数据、依赖关系和建议项,确保正确的安装和管理;
# Replaces: base-files is needed to replace /etc/update-motd.d/ files on Xenial
# Replaces: unattended-upgrades may be needed to replace /etc/apt/apt.conf.d/50unattended-upgrades
# (distributions provide good defaults, so this is not needed currently)
# Depends: linux-base is needed for "linux-version" command in initrd cleanup script
# Depends: fping is needed for orangepimonitor to upload orangepi-hardware-monitor.log
cat <<-EOF > "${destination}"/DEBIAN/control
Package: ${BSP_CLI_PACKAGE_NAME}
Version: $REVISION
Architecture: $ARCH
Maintainer: $MAINTAINER <$MAINTAINERMAIL>
Installed-Size: 1
Section: kernel
Priority: optional
Depends: bash, linux-base, u-boot-tools, initramfs-tools, lsb-release, fping
Provides: linux-${RELEASE}-root-legacy-$BOARD, linux-${RELEASE}-root-current-$BOARD, linux-${RELEASE}-root-next-$BOARD
Suggests: orangepi-config
Replaces: zram-config, base-files, orangepi-tools-$RELEASE, linux-${RELEASE}-root-legacy-$BOARD (<< $REVISION~), linux-${RELEASE}-root-current-$BOARD (<< $REVISION~), linux-${RELEASE}-root-next-$BOARD (<< $REVISION~)
Breaks: linux-${RELEASE}-root-legacy-$BOARD (<< $REVISION~), linux-${RELEASE}-root-current-$BOARD (<< $REVISION~), linux-${RELEASE}-root-next-$BOARD (<< $REVISION~)
Recommends: bsdutils, parted, util-linux, toilet
Description: OrangePi board support files for $BOARD
EOF
5.2.1 创建/DEBIAN/preinst
接着是生成一个Debian
软件包的preinst
脚本,用于在软件包安装之前执行一些操作;
# set up pre install script
cat <<-EOF > "${destination}"/DEBIAN/preinst
#!/bin/sh
# tell people to reboot at next login
[ "\$1" = "upgrade" ] && touch /var/run/.reboot_required
# convert link to file
if [ -L "/etc/network/interfaces" ]; then
cp /etc/network/interfaces /etc/network/interfaces.tmp
rm /etc/network/interfaces
mv /etc/network/interfaces.tmp /etc/network/interfaces
fi
# fixing ramdisk corruption when using lz4 compression method
sed -i "s/^COMPRESS=.*/COMPRESS=gzip/" /etc/initramfs-tools/initramfs.conf
# swap
grep -q vm.swappiness /etc/sysctl.conf
case \$? in
0)
sed -i 's/vm\.swappiness.*/vm.swappiness=100/' /etc/sysctl.conf
;;
*)
echo vm.swappiness=100 >>/etc/sysctl.conf
;;
esac
sysctl -p >/dev/null 2>&1
# disable deprecated services
[ -f "/etc/profile.d/activate_psd_user.sh" ] && rm /etc/profile.d/activate_psd_user.sh
[ -f "/etc/profile.d/check_first_login.sh" ] && rm /etc/profile.d/check_first_login.sh
[ -f "/etc/profile.d/check_first_login_reboot.sh" ] && rm /etc/profile.d/check_first_login_reboot.sh
[ -f "/etc/profile.d/ssh-title.sh" ] && rm /etc/profile.d/ssh-title.sh
[ -f "/etc/update-motd.d/10-header" ] && rm /etc/update-motd.d/10-header
[ -f "/etc/update-motd.d/30-sysinfo" ] && rm /etc/update-motd.d/30-sysinfo
[ -f "/etc/update-motd.d/35-tips" ] && rm /etc/update-motd.d/35-tips
[ -f "/etc/update-motd.d/40-updates" ] && rm /etc/update-motd.d/40-updates
[ -f "/etc/update-motd.d/98-autoreboot-warn" ] && rm /etc/update-motd.d/98-autoreboot-warn
[ -f "/etc/update-motd.d/99-point-to-faq" ] && rm /etc/update-motd.d/99-point-to-faq
[ -f "/etc/update-motd.d/80-esm" ] && rm /etc/update-motd.d/80-esm
[ -f "/etc/update-motd.d/80-livepatch" ] && rm /etc/update-motd.d/80-livepatch
[ -f "/etc/apt/apt.conf.d/02compress-indexes" ] && rm /etc/apt/apt.conf.d/02compress-indexes
[ -f "/etc/apt/apt.conf.d/02periodic" ] && rm /etc/apt/apt.conf.d/02periodic
[ -f "/etc/apt/apt.conf.d/no-languages" ] && rm /etc/apt/apt.conf.d/no-languages
[ -f "/etc/init.d/armhwinfo" ] && rm /etc/init.d/armhwinfo
[ -f "/etc/logrotate.d/armhwinfo" ] && rm /etc/logrotate.d/armhwinfo
[ -f "/etc/init.d/firstrun" ] && rm /etc/init.d/firstrun
[ -f "/etc/init.d/resize2fs" ] && rm /etc/init.d/resize2fs
[ -f "/lib/systemd/system/firstrun-config.service" ] && rm /lib/systemd/system/firstrun-config.service
[ -f "/lib/systemd/system/firstrun.service" ] && rm /lib/systemd/system/firstrun.service
[ -f "/lib/systemd/system/resize2fs.service" ] && rm /lib/systemd/system/resize2fs.service
[ -f "/usr/lib/orangepi/apt-updates" ] && rm /usr/lib/orangepi/apt-updates
[ -f "/usr/lib/orangepi/firstrun-config.sh" ] && rm /usr/lib/orangepi/firstrun-config.sh
# fix for https://bugs.launchpad.net/ubuntu/+source/lightdm-gtk-greeter/+bug/1897491
[ -d "/var/lib/lightdm" ] && (chown -R lightdm:lightdm /var/lib/lightdm ; chmod 0750 /var/lib/lightdm)
exit 0
EOF
chmod 755 "${destination}"/DEBIAN/preinst
5.2.3 创建/DEBIAN/postinst
接着是生成一个Debian
软件包的postinst
脚本,用于在软件包安装之后执行一些操作;
# 第一段
# set up post install script
cat <<-EOF > "${destination}"/DEBIAN/postinst
#!/bin/sh
#
# ${BOARD} BSP post installation script
#
[ -f /etc/lib/systemd/system/orangepi-ramlog.service ] && systemctl --no-reload enable orangepi-ramlog.service
# check if it was disabled in config and disable in new service
if [ -n "\$(grep -w '^ENABLED=false' /etc/default/log2ram 2> /dev/null)" ]; then
sed -i "s/^ENABLED=.*/ENABLED=false/" /etc/default/orangepi-ramlog
fi
# fix boot delay "waiting for suspend/resume device"
if [ -f "/etc/initramfs-tools/initramfs.conf" ]; then
if ! grep --quiet "RESUME=none" /etc/initramfs-tools/initramfs.conf; then
echo "RESUME=none" >> /etc/initramfs-tools/initramfs.conf
fi
fi
EOF
# install bootscripts if they are not present. Fix upgrades from old images
if [[ $FORCE_BOOTSCRIPT_UPDATE == yes ]]; then
# 第二段
cat <<-EOF >> "${destination}"/DEBIAN/postinst
if [ true ]; then
# this package recreate boot scripts
EOF
else
cat <<-EOF >> "${destination}"/DEBIAN/postinst
if [ ! -f /boot/$bootscript_dst ]; then
# if boot script does not exits its recreated
EOF
fi
# 第二段
cat <<-EOF >> "${destination}"/DEBIAN/postinst
# move bootscript to /usr/share/orangepi
# create a backup
[ -f /etc/orangepi-release ] && . /etc/orangepi-release
[ -z \${VERSION} ] && VERSION=$(echo \`date +%s\`)
if [ -f /boot/$bootscript_dst ]; then
cp /boot/$bootscript_dst /usr/share/orangepi/${bootscript_dst}-\${VERSION} >/dev/null 2>&1
echo "NOTE: You can find previous bootscript versions in /usr/share/orangepi !"
fi
# cleanup old bootscript backup
ls /usr/share/orangepi/boot.cmd-* >/dev/null 2>&1 | head -n -5 | xargs rm -f --
ls /usr/share/orangepi/boot.ini-* >/dev/null 2>&1 | head -n -5 | xargs rm -f --
echo "Recreating boot script"
cp /usr/share/orangepi/$bootscript_dst /boot >/dev/null 2>&1
rootdev=\$(sed -e 's/^.*root=//' -e 's/ .*\$//' < /proc/cmdline)
rootfstype=\$(sed -e 's/^.*rootfstype=//' -e 's/ .*$//' < /proc/cmdline)
# recreate orangepiEnv.txt if it and extlinux does not exists
if [ ! -f /boot/orangepiEnv.txt ] && [ ! -f /boot/extlinux/extlinux.conf ]; then
cp /usr/share/orangepi/orangepiEnv.txt /boot >/dev/null 2>&1
echo "rootdev="\$rootdev >> /boot/orangepiEnv.txt
echo "rootfstype="\$rootfstype >> /boot/orangepiEnv.txt
fi
[ -f /boot/boot.ini ] && sed -i "s/setenv rootdev.*/setenv rootdev \\"\$rootdev\\"/" /boot/boot.ini
[ -f /boot/boot.ini ] && sed -i "s/setenv rootfstype.*/setenv rootfstype \\"\$rootfstype\\"/" /boot/boot.ini
[ -f /boot/boot.cmd ] && mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr >/dev/null 2>&1
fi
[ ! -f "/etc/network/interfaces" ] && [ -f "/etc/network/interfaces.default" ] && cp /etc/network/interfaces.default /etc/network/interfaces
ln -sf /var/run/motd /etc/motd
rm -f /etc/update-motd.d/00-header /etc/update-motd.d/10-help-text
if [ -f "/boot/bin/$BOARD.bin" ] && [ ! -f "/boot/script.bin" ]; then ln -sf bin/$BOARD.bin /boot/script.bin >/dev/null 2>&1 || cp /boot/bin/$BOARD.bin /boot/script.bin; fi
if [ ! -f "/etc/default/orangepi-motd" ]; then
mv /etc/default/orangepi-motd.dpkg-dist /etc/default/orangepi-motd
fi
if [ ! -f "/etc/default/orangepi-ramlog" ] && [ -f /etc/default/orangepi-ramlog.dpkg-dist ]; then
mv /etc/default/orangepi-ramlog.dpkg-dist /etc/default/orangepi-ramlog
fi
if [ ! -f "/etc/default/orangepi-zram-config" ] && [ -f /etc/default/orangepi-zram-config.dpkg-dist ]; then
mv /etc/default/orangepi-zram-config.dpkg-dist /etc/default/orangepi-zram-config
fi
if [ -L "/usr/lib/chromium-browser/master_preferences.dpkg-dist" ]; then
mv /usr/lib/chromium-browser/master_preferences.dpkg-dist /usr/lib/chromium-browser/master_preferences
fi
# Read release value
if [ -f /etc/lsb-release ]; then
RELEASE=\$(cat /etc/lsb-release | grep CODENAME | cut -d"=" -f2 | sed 's/.*/\u&/')
sed -i "s/^PRETTY_NAME=.*/PRETTY_NAME=\"${VENDOR} $REVISION "\${RELEASE}"\"/" /etc/os-release
echo "${VENDOR} ${REVISION} \${RELEASE} \\l \n" > /etc/issue
echo "${VENDOR} ${REVISION} \${RELEASE}" > /etc/issue.net
fi
# Reload services
systemctl --no-reload enable orangepi-hardware-monitor.service orangepi-hardware-optimize.service orangepi-zram-config.service >/dev/null 2>&1
exit 0
EOF
5.3 其它
5.3.1 orangepi-distribution-status
接着是将这段脚本片段的作用是将<external/config/distributions/>
路径下的各个发行版支持状态信息复制到/etc/orangepi-distribution-status
;
# copy distribution support status
local releases=($(find ${EXTER}/config/distributions -mindepth 1 -maxdepth 1 -type d))
for i in ${releases[@]}
do
# 读取每个发行版目录中的support文件的内容,然后将发行版名称和其支持状态写入到orangepi-distribution-status
echo "$(echo $i | sed 's/.*\///')=$(cat $i/support)" >> "${destination}"/etc/orangepi-distribution-status
done
最终得到的orangepi-distribution-status
文件内容;
sid=csc
jammy=supported
focal=supported
bullseye=supported
bionic=supported
stretch=eos
xenial=eos
buster=supported
raspi=supported
bookworm=supported
5.3.2 orangepi-release
接着向/etc/orangepi-release
写入一些配置信息;
# armhwinfo, firstrun, orangepimonitor, etc. config file
cat <<-EOF > "${destination}"/etc/orangepi-release
# PLEASE DO NOT EDIT THIS FILE
BOARD=${BOARD}
BOARD_NAME="$BOARD_NAME"
BOARDFAMILY=${BOARDFAMILY}
BUILD_REPOSITORY_URL=${BUILD_REPOSITORY_URL}
BUILD_REPOSITORY_COMMIT=${BUILD_REPOSITORY_COMMIT}
DISTRIBUTION_CODENAME=${RELEASE}
DISTRIBUTION_STATUS=${DISTRIBUTION_STATUS}
VERSION=${REVISION}
LINUXFAMILY=${LINUXFAMILY}
ARCH=${ARCHITECTURE}
IMAGE_TYPE=$IMAGE_TYPE
BOARD_TYPE=$BOARD_TYPE
INITRD_ARCH=${INITRD_ARCH}
KERNEL_IMAGE_TYPE=${KERNEL_IMAGE_TYPE}
BRANCH=${BRANCH}
EOF
最终得到的orangepi-release
文件内容;
# PLEASE DO NOT EDIT THIS FILE
BOARD=orangepi3b
BOARD_NAME="OPI 3B"
BOARDFAMILY=rockchip-rk356x
BUILD_REPOSITORY_URL=https://kkgithub.com/orangepi-xunlong/orangepi-build.git
BUILD_REPOSITORY_COMMIT=5262437
DISTRIBUTION_CODENAME=bullseye
DISTRIBUTION_STATUS=supported
VERSION=1.0.6
LINUXFAMILY=rockchip-rk356x
ARCH=arm64
IMAGE_TYPE=user-built
BOARD_TYPE=conf
INITRD_ARCH=arm64
KERNEL_IMAGE_TYPE=Image
BRANCH=current
5.3.3 生成deb
包
函数最后先是将/etc/network/interfaces.default
文件中的#no-auto-down
替换为no-auto-down
;
接着执行了family_tweaks_bsp
函数,其定义在<SDK>/external/config/sources/families/rockchip-rk356x.conf
;
然后设置bsp
目录下的所有文件和目录的所有者、组以及权限;
最后就是使用fakeroot
将bsp
目录打包成deb
包,包名为orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb
,并拷贝到<SDK>/output/debs/bullseye
目录;
# this is required for NFS boot to prevent deconfiguring the network on shutdown
sed -i 's/#no-auto-down/no-auto-down/g' "${destination}"/etc/network/interfaces.default
# execute $LINUXFAMILY-specific tweaks
[[ $(type -t family_tweaks_bsp) == function ]] && family_tweaks_bsp
call_extension_method "post_family_tweaks_bsp" << 'POST_FAMILY_TWEAKS_BSP'
*family_tweaks_bsp overrrides what is in the config, so give it a chance to override the family tweaks*
This should be implemented by the config to tweak the BSP, after the board or family has had the chance to.
POST_FAMILY_TWEAKS_BSP
# add some summary to the image
fingerprint_image "${destination}/etc/orangepi.txt"
# fixing permissions (basic), reference: dh_fixperms,将根文件系统下的所有文件和目录的所有者和组设置为root
find "${destination}" -print0 2>/dev/null | xargs -0r chown --no-dereference 0:0
# 将不是符号链接的文件和目录,权限设置为为755(目录)和644(文件)
find "${destination}" ! -type l -print0 2>/dev/null | xargs -0r chmod 'go=rX,u+rw,a-s'
# create board DEB file
fakeroot dpkg-deb -b -Z${DEB_COMPRESS} "${destination}" "${destination}.deb" >> "${DEST}"/${LOG_SUBPATH}/output.log 2>&1
mkdir -p "${DEB_STORAGE}/${RELEASE}/"
rsync --remove-source-files -rq "${destination}.deb" "${DEB_STORAGE}/${RELEASE}/"
# cleanup
rm -rf ${bsptempdir}
将orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb
包解压,包含如下文件;
View Code
root@ubuntu:/work/sambashare/rk3566/orangepi-build/output/debs/bullseye$ sudo dpkg -x orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb ./
root@ubuntu:/work/sambashare/rk3566/orangepi-build/output/debs/bullseye$ ll
drwxr-xr-x 17 root root 4096 7月 10 18:01 etc/
drwxr-xr-x 4 root root 4096 7月 10 13:40 lib/
-rw-r--r-- 1 root sudo 781316 7月 10 18:01 orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb
drwxr-xr-x 8 root root 4096 7月 10 13:40 usr/
drwxr-xr-x 3 root root 4096 7月 10 13:40 var/
root@ubuntu:/work/sambashare/rk3566/orangepi-build/output/debs/bullseye# tree
.
├── etc
│ ├── apt
│ │ └── apt.conf.d
│ │ ├── 02-orangepi-compress-indexes
│ │ ├── 02-orangepi-periodic
│ │ ├── 71-orangepi-no-recommends
│ │ └── 81-orangepi-no-languages
│ ├── cron.d
│ │ ├── orangepi-truncate-logs
│ │ └── orangepi-updates
│ ├── cron.daily
│ │ └── orangepi-ram-logging
│ ├── default
│ │ ├── orangepi-motd.dpkg-dist
│ │ ├── orangepi-ramlog.dpkg-dist
│ │ └── orangepi-zram-config.dpkg-dist
│ ├── initramfs
│ │ └── post-update.d
│ │ └── 99-uboot
│ ├── initramfs-tools
│ │ └── hooks
│ │ └── bootsplash.sh
│ ├── kernel
│ │ ├── postinst.d
│ │ │ └── xx-initramfs-cleanup
│ │ └── postrm.d
│ │ └── xx-initramfs-cleanup
│ ├── modprobe.d
│ │ ├── 8189fs.conf
│ │ └── r8723bs.conf
│ ├── network
│ │ └── interfaces.default
│ ├── NetworkManager
│ │ └── conf.d
│ │ ├── 10-override-wifi-random-mac-disable.conf
│ │ └── 20-override-wifi-powersave-disable.conf
│ ├── orangepi-distribution-status
│ ├── orangepi-release
│ ├── orangepi.txt
│ ├── profile.d
│ │ ├── orangepi-activate-profile-sync-daemon.sh
│ │ ├── orangepi-check-first-login-reboot.sh
│ │ ├── orangepi-check-first-login.sh
│ │ ├── orangepi-lang.sh
│ │ └── orangepi-ssh-title.sh
│ ├── skel
│ ├── systemd
│ │ └── system
│ │ └── logrotate.service
│ ├── udev
│ │ └── rules.d
│ │ ├── 10-wifi-disable-powermanagement.rules
│ │ └── 50-usb-realtek-net.rules
│ └── update-motd.d
│ ├── 10-orangepi-header
│ ├── 30-orangepi-sysinfo
│ ├── 35-orangepi-tips
│ ├── 40-orangepi-updates
│ ├── 41-orangepi-config
│ └── 98-orangepi-autoreboot-warn
├── lib
│ ├── systemd
│ │ └── system
│ │ ├── bootsplash-ask-password-console.path
│ │ ├── bootsplash-ask-password-console.service
│ │ ├── bootsplash-hide-when-booted.service
│ │ ├── bootsplash-show-on-shutdown.service
│ │ ├── getty@tty1.service.d
│ │ │ └── 10-noclear.conf
│ │ ├── orangepi-disable-autologin.service
│ │ ├── orangepi-disable-autologin.timer
│ │ ├── orangepi-firstrun-config.service
│ │ ├── orangepi-firstrun.service
│ │ ├── orangepi-hardware-monitor.service
│ │ ├── orangepi-hardware-optimize.service
│ │ ├── orangepi-ramlog.service
│ │ ├── orangepi-resize-filesystem.service
│ │ ├── orangepi-zram-config.service
│ │ ├── serial-getty@.service.d
│ │ │ └── 10-term.conf
│ │ ├── systemd-journald.service.d
│ │ │ └── override.conf
│ │ └── systemd-modules-load.service.d
│ │ └── 10-timeout.conf
│ └── udev
│ └── rules.d
│ └── 71-axp-power-button.rules
├── orangepi-bsp-cli-orangepi3b_1.0.6_arm64.deb
├── usr
│ ├── bin
│ │ ├── adbd
│ │ ├── hciattach_opi
│ │ ├── memtester.sh
│ │ └── orangepimonitor
│ ├── lib
│ │ ├── chromium-browser
│ │ │ └── master_preferences.dpkg-dist -> ../../share/chromium/master_preferences
│ │ ├── nand-sata-install
│ │ │ └── exclude.txt
│ │ └── orangepi
│ │ ├── orangepi-apt-updates
│ │ ├── orangepi-audio-config
│ │ ├── orangepi-common
│ │ ├── orangepi-firstlogin
│ │ ├── orangepi-firstrun
│ │ ├── orangepi-firstrun-config
│ │ ├── orangepi-hardware-monitor
│ │ ├── orangepi-hardware-optimization
│ │ ├── orangepi-ramlog
│ │ ├── orangepi-resize-filesystem
│ │ ├── orangepi-truncate-logs
│ │ └── orangepi-zram-config
│ ├── local
│ │ └── bin
│ │ └── test_pwm.sh
│ ├── sbin
│ │ ├── blink_all_gpio
│ │ ├── burn_to_emmc
│ │ ├── nand-sata-install
│ │ └── orangepi-add-overlay
│ ├── share
│ │ ├── initramfs-tools
│ │ │ ├── conf-hooks.d
│ │ │ │ └── orangepi-plymouth
│ │ │ └── hooks
│ │ │ └── usb_modeswitch
│ │ └── orangepi
│ │ └── boot.cmd
│ └── src
│ └── hello
│ ├── hello.c
│ └── Makefile
└── var
└── lib
└── polkit-1
└── localauthority
└── 50-local.d
├── backlight.pkla
├── networkmanager.pkla
├── plugdev.pkla
├── power.pkla
└── printing.pkla
54 directories, 88 files
上面我们看到了一大堆文件,但是在create_board_package
中并没有创建那么多文件,那么其它一些文件哪里来的呢?这个我们后续会介绍到。
六 debootstrap.sh
debootstrap.sh
脚本文件实现了rootfs
文件系统以及Linux
镜像文件(统一固件)的制作,该文件主要提供了debootstrap_ng
、create_rootfs_cache
、prepare_partitions
、update_initramfs
、create_image
函数。
6.1 debootstrap_ng
View Code
debootstrap_ng()
{
display_alert "Starting rootfs and image building process for" "${BRANCH} ${BOARD} ${RELEASE} ${DESKTOP_APPGROUPS_SELECTED:-null} ${DESKTOP_ENVIRONMENT:-null} ${BUILD_MINIMAL}" "info"
# ROOTFS_TYPE默认为ext4
[[ $ROOTFS_TYPE != ext4 ]] && display_alert "Assuming $BOARD $BRANCH kernel supports $ROOTFS_TYPE" "" "wrn"
# trap to unmount stuff in case of error/manual interruption,
trap unmount_on_exit INT TERM EXIT
# stage: clean and create directories
rm -rf $SDCARD $MOUNT
mkdir -p $SDCARD $MOUNT $DEST/images $EXTER/cache/rootfs
# stage: verify tmpfs configuration and mount
# CLI needs ~1.5GiB, desktop - ~3.5GiB
# calculate and set tmpfs mount to use 9/10 of available RAM+SWAP
local phymem=$(( (($(awk '/MemTotal/ {print $2}' /proc/meminfo) + $(awk '/SwapTotal/ {print $2}' /proc/meminfo))) / 1024 * 9 / 10 )) # MiB
if [[ $BUILD_DESKTOP == yes ]]; then local tmpfs_max_size=3500; else local tmpfs_max_size=1500; fi # MiB
if [[ $FORCE_USE_RAMDISK == no ]]; then local use_tmpfs=no
elif [[ $FORCE_USE_RAMDISK == yes || $phymem -gt $tmpfs_max_size ]]; then
local use_tmpfs=yes
fi
[[ -n $FORCE_TMPFS_SIZE ]] && phymem=$FORCE_TMPFS_SIZE
[[ $use_tmpfs == yes ]] && mount -t tmpfs -o size=${phymem}M tmpfs $SDCARD
# stage: prepare basic rootfs: unpack cache or create from scratch
create_rootfs_cache
call_extension_method "pre_install_distribution_specific" "config_pre_install_distribution_specific" << 'PRE_INSTALL_DISTRIBUTION_SPECIFIC'
*give config a chance to act before install_distribution_specific*
Called after `create_rootfs_cache` (_prepare basic rootfs: unpack cache or create from scratch_) but before `install_distribution_specific` (_install distribution and board specific applications_).
PRE_INSTALL_DISTRIBUTION_SPECIFIC
# stage: install kernel and u-boot packages
# install distribution and board specific applications
if [[ ${RELEASE} == "raspi" ]]; then
install_opi_specific
else
install_distribution_specific
install_common
# install locally built packages or install pre-built packages from orangepi
[[ $EXTERNAL_NEW == compile || $EXTERNAL_NEW == prebuilt ]] && chroot_installpackages_local
#[[ $EXTERNAL_NEW == prebuilt ]] && chroot_installpackages "yes"
# stage: user customization script
# NOTE: installing too many packages may fill tmpfs mount
customize_image
# remove packages that are no longer needed. Since we have intrudoced uninstall feature, we might want to clean things that are no longer needed
display_alert "No longer needed packages" "purge" "info"
chroot $SDCARD /bin/bash -c "apt-get autoremove -y" >/dev/null 2>&1
# create list of installed packages for debug purposes
chroot $SDCARD /bin/bash -c "dpkg --get-selections" | grep -v deinstall | awk '{print $1}' | cut -f1 -d':' > $DEST/${LOG_SUBPATH}/installed-packages-${RELEASE}$([[ ${BUILD_MINIMAL} == yes ]] && echo "-minimal")$([[ ${BUILD_DESKTOP} == yes ]] && echo "-desktop").list 2>&1
fi
# clean up / prepare for making the image
umount_chroot "$SDCARD"
post_debootstrap_tweaks
if [[ $ROOTFS_TYPE == fel ]]; then
FEL_ROOTFS=$SDCARD/
display_alert "Starting FEL boot" "$BOARD" "info"
source $SRC/scripts/fel-load.sh
else
prepare_partitions
create_image
fi
# stage: unmount tmpfs
umount $SDCARD 2>&1
if [[ $use_tmpfs = yes ]]; then
while grep -qs "$SDCARD" /proc/mounts
do
umount $SDCARD
sleep 5
done
fi
rm -rf $SDCARD
# remove exit trap
trap - INT TERM EXIT
} #############################################################################
6.1.1 准备工作
函数最开始是一些准备工作,比如:
- 输出构建
rootfs
开始的日志信息; - 设置陷阱,当接收到
INT/TERM/EXIT
信号时执行unmount_on_exit
; - 删除
$SDCARD
目录,SDCARD
被设置为<SDK>/.tmp/rootfs-$(uuidgen)
:用于挂载tmpfs
文件系统,存放根文件系统文件(对于tmpfs
文件系统,数据是放在内存的); - 删除
$MOUNT
目录,MOUNT
被设置为<SDK>/.tmp/mount-$(uuidgen)
:创建根文件系统镜像<SDK>/.tmp/rootfs-$(uuidgen).raw
时的挂载点; - 创建临时目录:
$SDCARD
、$MOUNT
、<SDK>/output/images
、<SDK>/external/cache/rootfs
; - 设置
phymem
=RAM+SWAP
内存空间的9/10
,比如我使用的宿主机这个大小为8949MB
; - 设置
tmpfs_max_size=1500
(根文件系统在临时文件系统占用的最大空间)、use_tmpfs=yes
; - 最后将一个大小为
phymem
的tmpfs
文件系统挂载到$SDCARD
目录;tmpfs
是一种存在于内存中的临时文件系统,用于存储临时数据,因此要求phymem
>tmpfs_max_size
;
比如我们在编译过程中可以查看<SDK>/.tmp
目录;
root@ubuntu:/work/sambashare/rk3566/orangepi-build/.tmp$ ll
-rw-rw-r-- 1 root root 219 8月 4 11:31 extension_function_cleanup.sh
drwxrwxr-x 3 root root 4096 8月 4 11:31 .extensions/
drwxrwxr-x 2 root root 4096 8月 4 11:31 mount-1b5ba10e-5b78-4dbc-b6d5-01dd1f829aa1/
drwxrwxrwt 18 root root 420 8月 4 11:31 rootfs-1b5ba10e-5b78-4dbc-b6d5-01dd1f829aa1/
root@ubuntu:/work/sambashare/rk3566/orangepi-build/.tmp$ ls rootfs-1b5ba10e-5b78-4dbc-b6d5-01dd1f829aa1/
bin boot dev etc home lib media mnt opt proc root run sbin selinux srv sys tmp usr var
root@ubuntu:/work/sambashare/rk3566/orangepi-build/.tmp$ df -hT
文件系统 类型 大小 已用 可用 已用% 挂载点
......
tmpfs tmpfs 8.8G 1.2G 7.6G 14% /work/sambashare/rk3566/orangepi-build/.tmp/rootfs-1b5ba10e-5b78-4dbc-b6d5-01dd1f829aa1
/dev/loop18p2 ext4 2.8G 2.0G 776M 73% /work/sambashare/rk3566/orangepi-build/.tmp/mount-1b5ba10e-5b78-4dbc-b6d5-01dd1f829aa1
/dev/loop18p1 vfat 1022M 67M 956M 7% /work/sambashare/rk3566/orangepi-build/.tmp/mount-1b5ba10e-5b78-4dbc-b6d5-01dd1f829aa1/boot
相关脚本如下:
display_alert "Starting rootfs and image building process for" "${BRANCH} ${BOARD} ${RELEASE} ${DESKTOP_APPGROUPS_SELECTED:-null} ${DESKTOP_ENVIRONMENT:-null} ${BUILD_MINIMAL}" "info"
[[ $ROOTFS_TYPE != ext4 ]] && display_alert "Assuming $BOARD $BRANCH kernel supports $ROOTFS_TYPE" "" "wrn"
# trap to unmount stuff in case of error/manual interruption,设置信号处理器,当收到信号INT/TERM/EXIT取消挂载
trap unmount_on_exit INT TERM EXIT
# stage: clean and create directories
rm -rf $SDCARD $MOUNT
mkdir -p $SDCARD $MOUNT $DEST/images $EXTER/cache/rootfs
# stage: verify tmpfs configuration and mount
# CLI needs ~1.5GiB, desktop - ~3.5GiB
# calculate and set tmpfs mount to use 9/10 of available RAM+SWAP
local phymem=$(( (($(awk '/MemTotal/ {print $2}' /proc/meminfo) + $(awk '/SwapTotal/ {print $2}' /proc/meminfo))) / 1024 * 9 / 10 )) # MiB
# 无桌面环境,因此设置tmpfs_max_size=1500
if [[ $BUILD_DESKTOP == yes ]]; then local tmpfs_max_size=3500; else local tmpfs_max_size=1500; fi # MiB
# 判断是否使用tmpfs文件系统
if [[ $FORCE_USE_RAMDISK == no ]]; then local use_tmpfs=no
elif [[ $FORCE_USE_RAMDISK == yes || $phymem -gt $tmpfs_max_size ]]; then
local use_tmpfs=yes
fi
[[ -n $FORCE_TMPFS_SIZE ]] && phymem=$FORCE_TMPFS_SIZE
# 将一个大小为phymem的tmpfs文件系统挂载到$SDCARD目录
[[ $use_tmpfs == yes ]] && mount -t tmpfs -o size=${phymem}M tmpfs $SDCARD
unmount_on_exit
定义在scripts/image-helpers.sh
;
umount_chroot()
{
local target=$1
display_alert "Unmounting" "$target" "info"
# 检查并卸载chroot环境中的${target}/dev、${target}/proc和${target}/sys目录下的挂载点
while grep -Eq "${target}.*(dev|proc|sys)" /proc/mounts
do
umount -l --recursive "${target}"/dev >/dev/null 2>&1
umount -l "${target}"/proc >/dev/null 2>&1
umount -l "${target}"/sys >/dev/null 2>&1
sleep 5
done
}
unmount_on_exit()
{
trap - INT TERM EXIT
local stacktrace="$(get_extension_hook_stracktrace "${BASH_SOURCE[*]}" "${BASH_LINENO[*]}")"
display_alert "unmount_on_exit() called!" "$stacktrace" "err"
if [[ "${ERROR_DEBUG_SHELL}" == "yes" ]]; then
ERROR_DEBUG_SHELL=no # dont do it twice
display_alert "MOUNT" "${MOUNT}" "err"
display_alert "SDCARD" "${SDCARD}" "err"
display_alert "ERROR_DEBUG_SHELL=yes, starting a shell." "ERROR_DEBUG_SHELL" "err"
bash < /dev/tty || true
fi
# 卸载chroot环境中的挂载点
umount_chroot "${SDCARD}/"
umount -l "${SDCARD}"/tmp >/dev/null 2>&1
umount -l "${SDCARD}" >/dev/null 2>&1
umount -l "${MOUNT}"/boot >/dev/null 2>&1
umount -l "${MOUNT}" >/dev/null 2>&1
[[ $CRYPTROOT_ENABLE == yes ]] && cryptsetup luksClose "${ROOT_MAPPER}"
losetup -d "${LOOP}" >/dev/null 2>&1
rm -rf --one-file-system "${SDCARD}"
exit_with_error "debootstrap-ng was interrupted" || true # don't trigger again
}
6.1.2 create_rootfs_cache
接着调用create_rootfs_cache
准备基本的根文件系统:解压缓存或从头开始创建。
6.1.3 install_common
install_common
定义在scripts/distributions.sh
;
View Code
install_common()
{
display_alert "Applying common tweaks" "" "info"
# install rootfs encryption related packages separate to not break packages cache
if [[ $CRYPTROOT_ENABLE == yes ]]; then
display_alert "Installing rootfs encryption related packages" "cryptsetup" "info"
chroot "${SDCARD}" /bin/bash -c "apt-get -y -qq --no-install-recommends install cryptsetup" \
>> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
if [[ $CRYPTROOT_SSH_UNLOCK == yes ]]; then
display_alert "Installing rootfs encryption related packages" "dropbear-initramfs" "info"
chroot "${SDCARD}" /bin/bash -c "apt-get -y -qq --no-install-recommends install dropbear-initramfs cryptsetup-initramfs" \
>> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
fi
fi
# add dummy fstab entry to make mkinitramfs happy
echo "/dev/mmcblk0p1 / $ROOTFS_TYPE defaults 0 1" >> "${SDCARD}"/etc/fstab
# required for initramfs-tools-core on Stretch since it ignores the / fstab entry
echo "/dev/mmcblk0p2 /usr $ROOTFS_TYPE defaults 0 2" >> "${SDCARD}"/etc/fstab
# adjust initramfs dropbear configuration
# needs to be done before kernel installation, else it won't be in the initrd image
if [[ $CRYPTROOT_ENABLE == yes && $CRYPTROOT_SSH_UNLOCK == yes ]]; then
# Set the port of the dropbear ssh daemon in the initramfs to a different one if configured
# this avoids the typical 'host key changed warning' - `WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!`
[[ -f "${SDCARD}"/etc/dropbear-initramfs/config ]] && \
sed -i 's/^#DROPBEAR_OPTIONS=/DROPBEAR_OPTIONS="-p '"${CRYPTROOT_SSH_UNLOCK_PORT}"'"/' \
"${SDCARD}"/etc/dropbear-initramfs/config
# setup dropbear authorized_keys, either provided by userpatches or generated
if [[ -f $USERPATCHES_PATH/dropbear_authorized_keys ]]; then
cp "$USERPATCHES_PATH"/dropbear_authorized_keys "${SDCARD}"/etc/dropbear-initramfs/authorized_keys
else
# generate a default ssh key for login on dropbear in initramfs
# this key should be changed by the user on first login
display_alert "Generating a new SSH key pair for dropbear (initramfs)" "" ""
ssh-keygen -t ecdsa -f "${SDCARD}"/etc/dropbear-initramfs/id_ecdsa \
-N '' -O force-command=cryptroot-unlock -C 'AUTOGENERATED_BY_ARMBIAN_BUILD' >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
# /usr/share/initramfs-tools/hooks/dropbear will automatically add 'id_ecdsa.pub' to authorized_keys file
# during mkinitramfs of update-initramfs
#cat "${SDCARD}"/etc/dropbear-initramfs/id_ecdsa.pub > "${SDCARD}"/etc/dropbear-initramfs/authorized_keys
# The version of the Linux kernel
CRYPTROOT_SSH_UNLOCK_KEY_NAME="${BOARD^}_${REVISION}_${DISTRIBUTION,}_${RELEASE}_${SELECTED_CONFIGURATION}_linux"$(grab_version "$LINUXSOURCEDIR")"".key
# copy dropbear ssh key to image output dir for convenience
cp "${SDCARD}"/etc/dropbear-initramfs/id_ecdsa "${DEST}/images/${CRYPTROOT_SSH_UNLOCK_KEY_NAME}"
display_alert "SSH private key for dropbear (initramfs) has been copied to:" \
"$DEST/images/$CRYPTROOT_SSH_UNLOCK_KEY_NAME" "info"
fi
fi
# create modules file
local modules=MODULES_${BRANCH^^}
if [[ -n "${!modules}" ]]; then
tr ' ' '\n' <<< "${!modules}" > "${SDCARD}"/etc/modules
elif [[ -n "${MODULES}" ]]; then
tr ' ' '\n' <<< "${MODULES}" > "${SDCARD}"/etc/modules
fi
# create blacklist files
local blacklist=MODULES_BLACKLIST_${BRANCH^^}
if [[ -n "${!blacklist}" ]]; then
tr ' ' '\n' <<< "${!blacklist}" | sed -e 's/^/blacklist /' > "${SDCARD}/etc/modprobe.d/blacklist-${BOARD}.conf"
elif [[ -n "${MODULES_BLACKLIST}" ]]; then
tr ' ' '\n' <<< "${MODULES_BLACKLIST}" | sed -e 's/^/blacklist /' > "${SDCARD}/etc/modprobe.d/blacklist-${BOARD}.conf"
fi
# configure MIN / MAX speed for cpufrequtils
cat <<-EOF > "${SDCARD}"/etc/default/cpufrequtils
ENABLE=true
MIN_SPEED=$CPUMIN
MAX_SPEED=$CPUMAX
GOVERNOR=$GOVERNOR
EOF
# remove default interfaces file if present
# before installing board support package
rm -f "${SDCARD}"/etc/network/interfaces
# disable selinux by default
mkdir -p "${SDCARD}"/selinux
[[ -f "${SDCARD}"/etc/selinux/config ]] && sed "s/^SELINUX=.*/SELINUX=disabled/" -i "${SDCARD}"/etc/selinux/config
# remove Ubuntu's legal text
[[ -f "${SDCARD}"/etc/legal ]] && rm "${SDCARD}"/etc/legal
# Prevent loading paralel printer port drivers which we don't need here.
# Suppress boot error if kernel modules are absent
if [[ -f "${SDCARD}"/etc/modules-load.d/cups-filters.conf ]]; then
sed "s/^lp/#lp/" -i "${SDCARD}"/etc/modules-load.d/cups-filters.conf
sed "s/^ppdev/#ppdev/" -i "${SDCARD}"/etc/modules-load.d/cups-filters.conf
sed "s/^parport_pc/#parport_pc/" -i "${SDCARD}"/etc/modules-load.d/cups-filters.conf
fi
# console fix due to Debian bug
sed -e 's/CHARMAP=".*"/CHARMAP="'$CONSOLE_CHAR'"/g' -i "${SDCARD}"/etc/default/console-setup
# add the /dev/urandom path to the rng config file
echo "HRNGDEVICE=/dev/urandom" >> "${SDCARD}"/etc/default/rng-tools
# ping needs privileged action to be able to create raw network socket
# this is working properly but not with (at least) Debian Buster
chroot "${SDCARD}" /bin/bash -c "chmod u+s /bin/ping"
# change time zone data
echo "${TZDATA}" > "${SDCARD}"/etc/timezone
chroot "${SDCARD}" /bin/bash -c "dpkg-reconfigure -f noninteractive tzdata >/dev/null 2>&1"
# set root password
chroot "${SDCARD}" /bin/bash -c "(echo $ROOTPWD;echo $ROOTPWD;) | passwd root >/dev/null 2>&1"
# enable automated login to console(s)
#mkdir -p "${SDCARD}"/etc/systemd/system/getty@.service.d/
#mkdir -p "${SDCARD}"/etc/systemd/system/serial-getty@.service.d/
#cat <<-EOF > "${SDCARD}"/etc/systemd/system/serial-getty@.service.d/override.conf
#[Service]
#ExecStartPre=/bin/sh -c 'exec /bin/sleep 10'
#ExecStart=
#ExecStart=-/sbin/agetty --noissue --autologin root %I \$TERM
#Type=idle
#EOF
#cp "${SDCARD}"/etc/systemd/system/serial-getty@.service.d/override.conf "${SDCARD}"/etc/systemd/system/getty@.service.d/override.conf
# force change root password at first login
#chroot "${SDCARD}" /bin/bash -c "chage -d 0 root"
# change console welcome text
echo -e "${VENDOR} ${REVISION} ${RELEASE^} \\l \n" > "${SDCARD}"/etc/issue
echo "${VENDOR} ${REVISION} ${RELEASE^}" > "${SDCARD}"/etc/issue.net
sed -i "s/^PRETTY_NAME=.*/PRETTY_NAME=\"${VENDOR} $REVISION "${RELEASE^}"\"/" "${SDCARD}"/etc/os-release
# enable few bash aliases enabled in Ubuntu by default to make it even
sed "s/#alias ll='ls -l'/alias ll='ls -l'/" -i "${SDCARD}"/etc/skel/.bashrc
sed "s/#alias la='ls -A'/alias la='ls -A'/" -i "${SDCARD}"/etc/skel/.bashrc
sed "s/#alias l='ls -CF'/alias l='ls -CF'/" -i "${SDCARD}"/etc/skel/.bashrc
# root user is already there. Copy bashrc there as well
cp "${SDCARD}"/etc/skel/.bashrc "${SDCARD}"/root
# display welcome message at first root login
touch "${SDCARD}"/root/.not_logged_in_yet
if [[ ${DESKTOP_AUTOLOGIN} != no ]]; then
# set desktop autologin
touch "${SDCARD}"/root/.desktop_autologin
fi
# NOTE: this needs to be executed before family_tweaks
local bootscript_src=${BOOTSCRIPT%%:*}
local bootscript_dst=${BOOTSCRIPT##*:}
# create extlinux config file
if [[ $SRC_EXTLINUX == yes ]]; then
mkdir -p $SDCARD/boot/extlinux
cat <<-EOF > "$SDCARD/boot/extlinux/extlinux.conf"
label ${VENDOR}
kernel /boot/$NAME_KERNEL
initrd /boot/$NAME_INITRD
EOF
if [[ -n $BOOT_FDT_FILE ]]; then
if [[ $BOOT_FDT_FILE != "none" ]]; then
echo " fdt /boot/dtb/$BOOT_FDT_FILE" >> "$SDCARD/boot/extlinux/extlinux.conf"
fi
else
echo " fdtdir /boot/dtb/" >> "$SDCARD/boot/extlinux/extlinux.conf"
fi
else
if [[ "${BOOTCONFIG}" != "none" ]]; then
if [ -f "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" ]; then
cp "${USERPATCHES_PATH}/bootscripts/${bootscript_src}" "${SDCARD}/boot/${bootscript_dst}"
else
cp "${EXTER}/config/bootscripts/${bootscript_src}" "${SDCARD}/boot/${bootscript_dst}"
fi
fi
if [[ -n $BOOTENV_FILE ]]; then
if [[ -f $USERPATCHES_PATH/bootenv/$BOOTENV_FILE ]]; then
cp "$USERPATCHES_PATH/bootenv/${BOOTENV_FILE}" "${SDCARD}"/boot/orangepiEnv.txt
elif [[ -f $EXTER/config/bootenv/$BOOTENV_FILE ]]; then
cp "${EXTER}/config/bootenv/${BOOTENV_FILE}" "${SDCARD}"/boot/orangepiEnv.txt
fi
fi
# TODO: modify $bootscript_dst or orangepiEnv.txt to make NFS boot universal
# instead of copying sunxi-specific template
if [[ $ROOTFS_TYPE == nfs ]]; then
display_alert "Copying NFS boot script template"
if [[ -f $USERPATCHES_PATH/nfs-boot.cmd ]]; then
cp "$USERPATCHES_PATH"/nfs-boot.cmd "${SDCARD}"/boot/boot.cmd
else
cp "${EXTER}"/config/templates/nfs-boot.cmd.template "${SDCARD}"/boot/boot.cmd
fi
fi
[[ -n $OVERLAY_PREFIX && -f "${SDCARD}"/boot/orangepiEnv.txt && ($BRANCH =~ current|next || $BOARDFAMILY =~ "rockchip-rk3588"|"rockchip-rk356x") ]] && \
echo "overlay_prefix=$OVERLAY_PREFIX" >> "${SDCARD}"/boot/orangepiEnv.txt
[[ -n $DEFAULT_OVERLAYS && -f "${SDCARD}"/boot/orangepiEnv.txt && ($BRANCH =~ current|next || $BOARDFAMILY =~ "rockchip-rk3588"|"rockchip-rk356x") ]] && \
echo "overlays=${DEFAULT_OVERLAYS//,/ }" >> "${SDCARD}"/boot/orangepiEnv.txt
[[ -n $BOOT_FDT_FILE && -f "${SDCARD}"/boot/orangepiEnv.txt ]] && \
echo "fdtfile=${BOOT_FDT_FILE}" >> "${SDCARD}/boot/orangepiEnv.txt"
fi
# initial date for fake-hwclock
date -u '+%Y-%m-%d %H:%M:%S' > "${SDCARD}"/etc/fake-hwclock.data
echo "${HOST}" > "${SDCARD}"/etc/hostname
# set hostname in hosts file
cat <<-EOF > "${SDCARD}"/etc/hosts
127.0.0.1 localhost
127.0.1.1 $HOST
::1 localhost $HOST ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
EOF
cd $SRC
# Prepare and export caching-related params common to all apt calls below, to maximize apt-cacher-ng usage
export APT_EXTRA_DIST_PARAMS=""
[[ $NO_APT_CACHER != yes ]] && APT_EXTRA_DIST_PARAMS="-o Acquire::http::Proxy=\"http://${APT_PROXY_ADDR:-localhost:3142}\" -o Acquire::http::Proxy::localhost=\"DIRECT\""
display_alert "Cleaning" "package lists"
chroot "${SDCARD}" /bin/bash -c "apt-get clean"
display_alert "Updating" "package lists"
chroot "${SDCARD}" /bin/bash -c "apt-get ${APT_EXTRA_DIST_PARAMS} update" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
display_alert "Temporarily disabling" "initramfs-tools hook for kernel"
chroot "${SDCARD}" /bin/bash -c "chmod -v -x /etc/kernel/postinst.d/initramfs-tools" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
# install family packages
if [[ -n ${PACKAGE_LIST_FAMILY} ]]; then
display_alert "Installing PACKAGE_LIST_FAMILY packages" "${PACKAGE_LIST_FAMILY}"
chroot "${SDCARD}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive apt-get ${APT_EXTRA_DIST_PARAMS} -yqq --no-install-recommends install $PACKAGE_LIST_FAMILY" >> "${DEST}"/${LOG_SUBPATH}/install.log
fi
# install board packages
if [[ -n ${PACKAGE_LIST_BOARD} ]]; then
display_alert "Installing PACKAGE_LIST_BOARD packages" "${PACKAGE_LIST_BOARD}"
chroot "${SDCARD}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive apt-get ${APT_EXTRA_DIST_PARAMS} -yqq --no-install-recommends install $PACKAGE_LIST_BOARD" >> "${DEST}"/${LOG_SUBPATH}/install.log || { display_alert "Failed to install PACKAGE_LIST_BOARD" "${PACKAGE_LIST_BOARD}" "err"; exit 2; }
fi
# remove family packages
if [[ -n ${PACKAGE_LIST_FAMILY_REMOVE} ]]; then
display_alert "Removing PACKAGE_LIST_FAMILY_REMOVE packages" "${PACKAGE_LIST_FAMILY_REMOVE}"
chroot "${SDCARD}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive apt-get ${APT_EXTRA_DIST_PARAMS} -yqq remove --auto-remove $PACKAGE_LIST_FAMILY_REMOVE" >> "${DEST}"/${LOG_SUBPATH}/install.log
fi
# remove board packages
if [[ -n ${PACKAGE_LIST_BOARD_REMOVE} ]]; then
display_alert "Removing PACKAGE_LIST_BOARD_REMOVE packages" "${PACKAGE_LIST_BOARD_REMOVE}"
for PKG_REMOVE in ${PACKAGE_LIST_BOARD_REMOVE}; do
chroot "${SDCARD}" /bin/bash -c "DEBIAN_FRONTEND=noninteractive apt-get ${APT_EXTRA_DIST_PARAMS} -yqq remove --auto-remove ${PKG_REMOVE}" >> "${DEST}"/${LOG_SUBPATH}/install.log
done
fi
# install u-boot
# @TODO: add install_bootloader() extension method, refactor into u-boot extension
[[ "${BOOTCONFIG}" != "none" ]] && {
if [[ "${REPOSITORY_INSTALL}" != *u-boot* ]]; then
UBOOT_VER=$(dpkg --info "${DEB_STORAGE}/u-boot/${CHOSEN_UBOOT}_${REVISION}_${ARCH}.deb" | grep Descr | awk '{print $(NF)}')
install_deb_chroot "${DEB_STORAGE}/u-boot/${CHOSEN_UBOOT}_${REVISION}_${ARCH}.deb"
else
UBOOT_VER=$(dpkg --info "${DEB_ORANGEPI}/u-boot/${CHOSEN_UBOOT}_${REVISION}_${ARCH}.deb" | grep Descr | awk '{print $(NF)}')
install_deb_chroot "${DEB_ORANGEPI}/u-boot/${CHOSEN_UBOOT}_${REVISION}_${ARCH}.deb" "orangepi"
fi
}
call_extension_method "pre_install_kernel_debs" << 'PRE_INSTALL_KERNEL_DEBS'
*called before installing the Armbian-built kernel deb packages*
It is not too late to `unset KERNELSOURCE` here and avoid kernel install.
PRE_INSTALL_KERNEL_DEBS
# install kernel
[[ -n $KERNELSOURCE ]] && {
if [[ "${REPOSITORY_INSTALL}" != *kernel* ]]; then
VER=$(dpkg --info "${DEB_STORAGE}/${CHOSEN_KERNEL}_${REVISION}_${ARCH}.deb" | awk -F"-" '/Source:/{print $2}')
install_deb_chroot "${DEB_STORAGE}/${CHOSEN_KERNEL}_${REVISION}_${ARCH}.deb"
if [[ -f ${DEB_STORAGE}/${CHOSEN_KERNEL/image/dtb}_${REVISION}_${ARCH}.deb ]]; then
install_deb_chroot "${DEB_STORAGE}/${CHOSEN_KERNEL/image/dtb}_${REVISION}_${ARCH}.deb"
fi
if [[ $INSTALL_HEADERS == yes ]]; then
install_deb_chroot "${DEB_STORAGE}/${CHOSEN_KERNEL/image/headers}_${REVISION}_${ARCH}.deb"
else
cp "${DEB_STORAGE}/${CHOSEN_KERNEL/image/headers}_${REVISION}_${ARCH}.deb" "${SDCARD}"/opt/
fi
else
VER=$(dpkg --info "${DEB_ORANGEPI}/${CHOSEN_KERNEL}_${REVISION}_${ARCH}.deb" | grep Descr | awk '{print $(NF)}')
VER="${VER/-$LINUXFAMILY/}"
install_deb_chroot "${DEB_ORANGEPI}/${CHOSEN_KERNEL}_${REVISION}_${ARCH}.deb" "orangepi"
if [[ -f ${DEB_ORANGEPI}/${CHOSEN_KERNEL/image/dtb}_${REVISION}_${ARCH}.deb ]]; then
install_deb_chroot "${DEB_ORANGEPI}/${CHOSEN_KERNEL/image/dtb}_${REVISION}_${ARCH}.deb" "orangepi"
fi
if [[ $INSTALL_HEADERS == yes ]]; then
install_deb_chroot "${DEB_ORANGEPI}/${CHOSEN_KERNEL/image/headers}_${REVISION}_${ARCH}.deb" "orangepi"
fi
fi
}
call_extension_method "post_install_kernel_debs" << 'POST_INSTALL_KERNEL_DEBS'
*allow config to do more with the installed kernel/headers*
Called after packages, u-boot, kernel and headers installed in the chroot, but before the BSP is installed.
If `KERNELSOURCE` is (still?) unset after this, Armbian-built firmware will not be installed.
POST_INSTALL_KERNEL_DEBS
# install board support packages
if [[ "${REPOSITORY_INSTALL}" != *bsp* ]]; then
install_deb_chroot "${DEB_STORAGE}/$RELEASE/${BSP_CLI_PACKAGE_FULLNAME}.deb"
else
install_deb_chroot "${DEB_ORANGEPI}/$RELEASE/${CHOSEN_ROOTFS}_${BSP_CLI_PACKAGE_FULLNAME}.deb" "orangepi"
fi
# install orangepi-desktop
if [[ "${REPOSITORY_INSTALL}" != *orangepi-desktop* ]]; then
if [[ $BUILD_DESKTOP == yes ]]; then
install_deb_chroot "${DEB_STORAGE}/${RELEASE}/${CHOSEN_DESKTOP}_${REVISION}_all.deb"
install_deb_chroot "${DEB_STORAGE}/${RELEASE}/${BSP_DESKTOP_PACKAGE_FULLNAME}.deb"
# install display manager and PACKAGE_LIST_DESKTOP_FULL packages if enabled per board
desktop_postinstall
fi
else
if [[ $BUILD_DESKTOP == yes ]]; then
install_deb_chroot "${CHOSEN_DESKTOP}" "orangepi"
# install display manager and PACKAGE_LIST_DESKTOP_FULL packages if enabled per board
desktop_postinstall
fi
fi
# install orangepi-firmware
if [[ "${REPOSITORY_INSTALL}" != *orangepi-firmware* ]]; then
if [[ -f ${DEB_STORAGE}/orangepi-firmware_${REVISION}_all.deb ]]; then
install_deb_chroot "${DEB_STORAGE}/orangepi-firmware_${REVISION}_all.deb"
fi
else
if [[ -f ${DEB_STORAGE}/orangepi-firmware_${REVISION}_all.deb ]]; then
install_deb_chroot "${DEB_ORANGEPI}/orangepi-firmware_${REVISION}_all.deb" "orangepi"
fi
fi
# install orangepi-config
if [[ "${PACKAGE_LIST_RM}" != *orangepi-config* ]]; then
if [[ "${REPOSITORY_INSTALL}" != *orangepi-config* ]]; then
if [[ $BUILD_MINIMAL != yes ]]; then
install_deb_chroot "${DEB_STORAGE}/orangepi-config_${REVISION}_all.deb"
fi
else
if [[ $BUILD_MINIMAL != yes ]]; then
install_deb_chroot "${DEB_ORANGEPI}/orangepi-config_${REVISION}_all.deb" "orangepi"
fi
fi
fi
# install orangepi-zsh
if [[ "${PACKAGE_LIST_RM}" != *orangepi-zsh* ]]; then
if [[ "${REPOSITORY_INSTALL}" != *orangepi-zsh* ]]; then
if [[ $BUILD_MINIMAL != yes ]]; then
install_deb_chroot "${DEB_STORAGE}/orangepi-zsh_${REVISION}_all.deb"
fi
else
if [[ $BUILD_MINIMAL != yes ]]; then
install_deb_chroot "orangepi-zsh" "remote"
fi
fi
fi
# install plymouth-theme-orangepi
if [[ $PLYMOUTH == yes && $BUILD_DESKTOP == yes && $RELEASE != buster ]]; then
if [[ "${REPOSITORY_INSTALL}" != *plymouth-theme-orangepi* ]]; then
install_deb_chroot "${DEB_STORAGE}/orangepi-plymouth-theme_${REVISION}_all.deb"
else
install_deb_chroot "orangepi-plymouth-theme" "remote"
fi
fi
# install kernel sources
if [[ -f ${DEB_STORAGE}/${CHOSEN_KSRC}_${REVISION}_all.deb && $INSTALL_KSRC == yes ]]; then
install_deb_chroot "${DEB_STORAGE}/${CHOSEN_KSRC}_${REVISION}_all.deb"
elif [[ $INSTALL_KSRC == yes ]]; then
display_alert "Please set BUILD_KSRC=yes to generate the kernel source package" "" "wrn"
fi
# install wireguard tools
if [[ $WIREGUARD == yes ]]; then
chroot "${SDCARD}" /bin/bash -c "apt-get -y -qq install wireguard-tools --no-install-recommends" >> "${DEST}"/debug/install.log 2>&1
fi
# freeze orangepi packages
if [[ $BSPFREEZE == yes ]]; then
display_alert "Freezing Orange Pi packages" "$BOARD" "info"
chroot "${SDCARD}" /bin/bash -c "apt-mark hold ${CHOSEN_KERNEL} ${CHOSEN_KERNEL/image/headers} \
linux-u-boot-${BOARD}-${BRANCH} ${CHOSEN_KERNEL/image/dtb}" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
fi
# add orangepi user
chroot "${SDCARD}" /bin/bash -c "adduser --quiet --disabled-password --shell /bin/bash --home /home/${OPI_USERNAME} --gecos ${OPI_USERNAME} ${OPI_USERNAME}"
chroot "${SDCARD}" /bin/bash -c "(echo ${OPI_PWD};echo ${OPI_PWD};) | passwd "${OPI_USERNAME}" >/dev/null 2>&1"
for additionalgroup in sudo netdev audio video disk tty users games dialout plugdev input bluetooth systemd-journal ssh; do
chroot "${SDCARD}" /bin/bash -c "usermod -aG ${additionalgroup} ${OPI_USERNAME} 2>/dev/null"
done
# fix for gksu in Xenial
touch ${SDCARD}/home/${OPI_USERNAME}/.Xauthority
chroot "${SDCARD}" /bin/bash -c "chown ${OPI_USERNAME}:${OPI_USERNAME} /home/${OPI_USERNAME}/.Xauthority"
# set up profile sync daemon on desktop systems
chroot "${SDCARD}" /bin/bash -c "which psd >/dev/null 2>&1"
if [ $? -eq 0 ]; then
echo -e "${OPI_USERNAME} ALL=(ALL) NOPASSWD: /usr/bin/psd-overlay-helper" >> ${SDCARD}/etc/sudoers
touch ${SDCARD}/home/${OPI_USERNAME}/.activate_psd
chroot "${SDCARD}" /bin/bash -c "chown $OPI_USERNAME:$OPI_USERNAME /home/${OPI_USERNAME}/.activate_psd"
fi
# remove deb files
rm -f "${SDCARD}"/root/*.deb
# copy boot splash images
cp "${EXTER}"/packages/blobs/splash/orangepi-u-boot.bmp "${SDCARD}"/boot/boot.bmp
cp "${EXTER}"/packages/blobs/splash/logo.bmp "${SDCARD}"/boot/logo.bmp
# copy audio.wav and mute.wav
cp "${EXTER}"/packages/blobs/audio_wav/audio.wav "${SDCARD}"/usr/share/sounds/alsa/
cp "${EXTER}"/packages/blobs/audio_wav/mute.wav "${SDCARD}"/usr/share/sounds/alsa/
cp "${EXTER}"/packages/blobs/test.mp4 "${SDCARD}"/usr/local/
# copy watchdog test programm
cp "${EXTER}"/packages/blobs/watchdog/watchdog_test_${ARCH} "${SDCARD}"/usr/local/bin/watchdog_test
[[ -f "${SDCARD}"/usr/bin/gnome-session ]] && sed -i "s/user-session.*/user-session=ubuntu-wayland/" ${SDCARD}/etc/lightdm/lightdm.conf.d/22-orangepi-autologin.conf
[[ -f "${SDCARD}"/usr/bin/startplasma-x11 ]] && sed -i "s/user-session.*/user-session=plasma-x11/" ${SDCARD}/etc/lightdm/lightdm.conf.d/22-orangepi-autologin.conf
# execute $LINUXFAMILY-specific tweaks
[[ $(type -t family_tweaks) == function ]] && family_tweaks
call_extension_method "post_family_tweaks" << 'FAMILY_TWEAKS'
*customize the tweaks made by $LINUXFAMILY-specific family_tweaks*
It is run after packages are installed in the rootfs, but before enabling additional services.
It allows implementors access to the rootfs (`${SDCARD}`) in its pristine state after packages are installed.
FAMILY_TWEAKS
# enable additional services
chroot "${SDCARD}" /bin/bash -c "systemctl --no-reload enable orangepi-firstrun.service >/dev/null 2>&1"
chroot "${SDCARD}" /bin/bash -c "systemctl --no-reload enable orangepi-firstrun-config.service >/dev/null 2>&1"
chroot "${SDCARD}" /bin/bash -c "systemctl --no-reload enable orangepi-zram-config.service >/dev/null 2>&1"
chroot "${SDCARD}" /bin/bash -c "systemctl --no-reload enable orangepi-hardware-optimize.service >/dev/null 2>&1"
chroot "${SDCARD}" /bin/bash -c "systemctl --no-reload enable orangepi-ramlog.service >/dev/null 2>&1"
chroot "${SDCARD}" /bin/bash -c "systemctl --no-reload enable orangepi-resize-filesystem.service >/dev/null 2>&1"
chroot "${SDCARD}" /bin/bash -c "systemctl --no-reload enable orangepi-hardware-monitor.service >/dev/null 2>&1"
# copy "first run automated config, optional user configured"
cp ${EXTER}/packages/bsp/orangepi_first_run.txt.template "${SDCARD}"/boot/orangepi_first_run.txt.template
## switch to beta repository at this stage if building nightly images
#[[ $IMAGE_TYPE == nightly ]] \
#&& echo "deb http://beta.orangepi.com $RELEASE main ${RELEASE}-utils ${RELEASE}-desktop" \
#> "${SDCARD}"/etc/apt/sources.list.d/orangepi.list
# Cosmetic fix [FAILED] Failed to start Set console font and keymap at first boot
[[ -f "${SDCARD}"/etc/console-setup/cached_setup_font.sh ]] \
&& sed -i "s/^printf '.*/printf '\\\033\%\%G'/g" "${SDCARD}"/etc/console-setup/cached_setup_font.sh
[[ -f "${SDCARD}"/etc/console-setup/cached_setup_terminal.sh ]] \
&& sed -i "s/^printf '.*/printf '\\\033\%\%G'/g" "${SDCARD}"/etc/console-setup/cached_setup_terminal.sh
[[ -f "${SDCARD}"/etc/console-setup/cached_setup_keyboard.sh ]] \
&& sed -i "s/-u/-x'/g" "${SDCARD}"/etc/console-setup/cached_setup_keyboard.sh
# fix for https://bugs.launchpad.net/ubuntu/+source/blueman/+bug/1542723
chroot "${SDCARD}" /bin/bash -c "chown root:messagebus /usr/lib/dbus-1.0/dbus-daemon-launch-helper"
chroot "${SDCARD}" /bin/bash -c "chmod u+s /usr/lib/dbus-1.0/dbus-daemon-launch-helper"
# disable samba NetBIOS over IP name service requests since it hangs when no network is present at boot
chroot "${SDCARD}" /bin/bash -c "systemctl --quiet disable nmbd 2> /dev/null"
# disable low-level kernel messages for non betas
if [[ -z $BETA ]]; then
sed -i "s/^#kernel.printk*/kernel.printk/" "${SDCARD}"/etc/sysctl.conf
fi
# disable repeated messages due to xconsole not being installed.
[[ -f "${SDCARD}"/etc/rsyslog.d/50-default.conf ]] && \
sed '/daemon\.\*\;mail.*/,/xconsole/ s/.*/#&/' -i "${SDCARD}"/etc/rsyslog.d/50-default.conf
# disable deprecated parameter
sed '/.*$KLogPermitNonKernelFacility.*/,// s/.*/#&/' -i "${SDCARD}"/etc/rsyslog.conf
# enable getty on multiple serial consoles
# and adjust the speed if it is defined and different than 115200
#
# example: SERIALCON="ttyS0:15000000,ttyGS1"
#
ifs=$IFS
for i in $(echo "${SERIALCON:-'ttyS0'}" | sed "s/,/ /g")
do
IFS=':' read -r -a array <<< "$i"
[[ "${array[0]}" == "tty1" ]] && continue # Don't enable tty1 as serial console.
display_alert "Enabling serial console" "${array[0]}" "info"
# add serial console to secure tty list
[ -z "$(grep -w '^${array[0]}' "${SDCARD}"/etc/securetty 2> /dev/null)" ] && \
echo "${array[0]}" >> "${SDCARD}"/etc/securetty
if [[ ${array[1]} != "115200" && -n ${array[1]} ]]; then
# make a copy, fix speed and enable
cp "${SDCARD}"/lib/systemd/system/serial-getty@.service \
"${SDCARD}/lib/systemd/system/serial-getty@${array[0]}.service"
sed -i "s/--keep-baud 115200/--keep-baud ${array[1]},115200/" \
"${SDCARD}/lib/systemd/system/serial-getty@${array[0]}.service"
fi
chroot "${SDCARD}" /bin/bash -c "systemctl daemon-reload" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
chroot "${SDCARD}" /bin/bash -c "systemctl --no-reload enable serial-getty@${array[0]}.service" \
>> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
if [[ "${array[0]}" == "ttyGS0" && $LINUXFAMILY == sun8i && $BRANCH == legacy ]]; then
mkdir -p "${SDCARD}"/etc/systemd/system/serial-getty@ttyGS0.service.d
cat <<-EOF > "${SDCARD}"/etc/systemd/system/serial-getty@ttyGS0.service.d/10-switch-role.conf
[Service]
ExecStartPre=-/bin/sh -c "echo 2 > /sys/bus/platform/devices/sunxi_usb_udc/otg_role"
EOF
fi
done
IFS=$ifs
[[ $LINUXFAMILY == sun*i ]] && mkdir -p "${SDCARD}"/boot/overlay-user
# to prevent creating swap file on NFS (needs specific kernel options)
# and f2fs/btrfs (not recommended or needs specific kernel options)
[[ $ROOTFS_TYPE != ext4 ]] && touch "${SDCARD}"/var/swap
# install initial asound.state if defined
mkdir -p "${SDCARD}"/var/lib/alsa/
[[ -n $ASOUND_STATE ]] && cp "${EXTER}/packages/blobs/asound.state/${ASOUND_STATE}" "${SDCARD}"/var/lib/alsa/asound.state
# save initial orangepi-release state
cp "${SDCARD}"/etc/orangepi-release "${SDCARD}"/etc/orangepi-image-release
# DNS fix. package resolvconf is not available everywhere
if [ -d /etc/resolvconf/resolv.conf.d ] && [ -n "$NAMESERVER" ]; then
echo "nameserver $NAMESERVER" > "${SDCARD}"/etc/resolvconf/resolv.conf.d/head
fi
# permit root login via SSH for the first boot
sed -i 's/#\?PermitRootLogin .*/PermitRootLogin yes/' "${SDCARD}"/etc/ssh/sshd_config
# enable PubkeyAuthentication
sed -i 's/#\?PubkeyAuthentication .*/PubkeyAuthentication yes/' "${SDCARD}"/etc/ssh/sshd_config
if [ -f "${SDCARD}"/etc/NetworkManager/NetworkManager.conf ]; then
# configure network manager
sed "s/managed=\(.*\)/managed=true/g" -i "${SDCARD}"/etc/NetworkManager/NetworkManager.conf
# remove network manager defaults to handle eth by default
rm -f "${SDCARD}"/usr/lib/NetworkManager/conf.d/10-globally-managed-devices.conf
# most likely we don't need to wait for nm to get online
chroot "${SDCARD}" /bin/bash -c "systemctl disable NetworkManager-wait-online.service" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
# Just regular DNS and maintain /etc/resolv.conf as a file
sed "/dns/d" -i "${SDCARD}"/etc/NetworkManager/NetworkManager.conf
sed "s/\[main\]/\[main\]\ndns=default\nrc-manager=file/g" -i "${SDCARD}"/etc/NetworkManager/NetworkManager.conf
if [[ -n $NM_IGNORE_DEVICES ]]; then
mkdir -p "${SDCARD}"/etc/NetworkManager/conf.d/
cat <<-EOF > "${SDCARD}"/etc/NetworkManager/conf.d/10-ignore-interfaces.conf
[keyfile]
unmanaged-devices=$NM_IGNORE_DEVICES
EOF
fi
elif [ -d "${SDCARD}"/etc/systemd/network ]; then
# configure networkd
rm "${SDCARD}"/etc/resolv.conf
ln -s /run/systemd/resolve/resolv.conf "${SDCARD}"/etc/resolv.conf
# enable services
chroot "${SDCARD}" /bin/bash -c "systemctl enable systemd-networkd.service systemd-resolved.service" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
if [ -e /etc/systemd/timesyncd.conf ]; then
chroot "${SDCARD}" /bin/bash -c "systemctl enable systemd-timesyncd.service" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
fi
umask 022
cat > "${SDCARD}"/etc/systemd/network/eth0.network <<- __EOF__
[Match]
Name=eth0
[Network]
#MACAddress=
DHCP=ipv4
LinkLocalAddressing=ipv4
#Address=192.168.1.100/24
#Gateway=192.168.1.1
#DNS=192.168.1.1
#Domains=example.com
NTP=0.pool.ntp.org 1.pool.ntp.org
__EOF__
fi
# avahi daemon defaults if exists
[[ -f "${SDCARD}"/usr/share/doc/avahi-daemon/examples/sftp-ssh.service ]] && \
cp "${SDCARD}"/usr/share/doc/avahi-daemon/examples/sftp-ssh.service "${SDCARD}"/etc/avahi/services/
[[ -f "${SDCARD}"/usr/share/doc/avahi-daemon/examples/ssh.service ]] && \
cp "${SDCARD}"/usr/share/doc/avahi-daemon/examples/ssh.service "${SDCARD}"/etc/avahi/services/
# nsswitch settings for sane DNS behavior: remove resolve, assure libnss-myhostname support
sed "s/hosts\:.*/hosts: files mymachines dns myhostname/g" -i "${SDCARD}"/etc/nsswitch.conf
# build logo in any case
boot_logo
# disable MOTD for first boot - we want as clean 1st run as possible
chmod -x "${SDCARD}"/etc/update-motd.d/*
}
6.1.4 chroot_installpackages_local
chroot_installpackages_local
定义在scripts/chroot-buildpackages.sh
;
chroot_installpackages_local()
{
local conf=$EXTER/config/aptly-temp.conf
rm -rf /tmp/aptly-temp/
mkdir -p /tmp/aptly-temp/
aptly -config="${conf}" repo create temp >> "${DEST}"/${LOG_SUBPATH}/install.log
# NOTE: this works recursively
if [[ $EXTERNAL_NEW == prebuilt ]]; then
aptly -config="${conf}" repo add temp "${DEB_ORANGEPI}/extra/${RELEASE}-desktop/" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
aptly -config="${conf}" repo add temp "${DEB_ORANGEPI}/extra/${RELEASE}-utils/" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
else
aptly -config="${conf}" repo add temp "${DEB_STORAGE}/extra/${RELEASE}-desktop/" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
aptly -config="${conf}" repo add temp "${DEB_STORAGE}/extra/${RELEASE}-utils/" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
fi
# -gpg-key="925644A6"
[[ ! -d /root/.gnupg ]] && mkdir -p /root/.gnupg
aptly -keyring="$EXTER/packages/extras-buildpkgs/buildpkg-public.gpg" -secret-keyring="$EXTER/packages/extras-buildpkgs/buildpkg.gpg" -batch=true -config="${conf}" \
-gpg-key="925644A6" -passphrase="testkey1234" -component=temp -distribution="${RELEASE}" publish repo temp >> "${DEST}"/${LOG_SUBPATH}/install.log
#aptly -config="${conf}" -listen=":8189" serve &
aptly -config="${conf}" -listen=":8189" serve >> "${DEST}"/debug/install.log 2>&1 &
local aptly_pid=$!
cp $EXTER/packages/extras-buildpkgs/buildpkg.key "${SDCARD}"/tmp/buildpkg.key
cat <<-'EOF' > "${SDCARD}"/etc/apt/preferences.d/90-orangepi-temp.pref
Package: *
Pin: origin "localhost"
Pin-Priority: 550
EOF
cat <<-EOF > "${SDCARD}"/etc/apt/sources.list.d/orangepi-temp.list
deb http://localhost:8189/ $RELEASE temp
EOF
chroot_installpackages
kill "${aptly_pid}" >> "${DEST}"/${LOG_SUBPATH}/install.log 2>&1
} #############################################################################
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了