Orange Pi编译脚本的分析

脚本的运行流程

/scripts/main.sh


变量设置

DEST=“${SRC}”/output
REVISION=“2.2.2”
DOWNLOAD_MIRROR == “china”
NTP_SERVER=“cn.pool.ntp.org” 通过网络校准您计算机上的时钟
BUILD_ALL
COLUMNS, LINES
TTY_X, TTY_Y
LANGUAGE=“en_US:en”
CONSOLE_CHAR=“UTF-8”
FORCE_CHECKOUT=yes
PROGRESS_DISPLAY == none ?
OUTPUT_VERYSILENT=yes
OUTPUT_DIALOG=yes
PROGRESS_LOG_TO_FILE,
SHOW_WARNING=yes
USE_CCACHE
CCACHE=ccache
export PATH=“/usr/lib/ccache:$PATH”
PRIVATE_CCACHE
export CCACHE_DIR=$DEST/cache/ccache
OFFLINE_WORK
BUILD_OPT
BOARD
BOARD_TYPE=“conf”
LINUXFAMILY=“${BOARDFAMILY}”
KERNEL_TARGET
BRANCH
EXPERT
KERNEL_CONFIGURE
RELEASE_TARGET
RELEASE
BUILD_MINIMAL == yes
BUILD_DESKTOP
IMAGETYPE
EXTERNAL_NEW
CONTAINER_COMPAT=“no”
COMPRESS_OUTPUTIMAGE
CPUS
USEALLCORES
CTHREADS
GPG_PASS
IMAGE_TYPE
BOOTSOURCEDIR, BOOTDIR, BOOTBRANCH
LINUXSOURCEDIR, KERNELDIR, KERNELBRANCH
ATFSOURCE, ATFSOURCEDIR, ATFDIR, ATFBRANCH
DEB_BRANCH
CHOSEN_UBOOT
CHOSEN_KERNEL
CHOSEN_ROOTFS
CHOSEN_DESKTOP
CHOSEN_KSRC
CLEAN_LEVEL
IGNORE_UPDATES
DEB_STORAGE
REPOSITORY_INSTALL
CHOSEN_UBOOT, REVISION, ARCH
EXTERNAL_NEW
BSP_BUILD
KERNEL_CONFIGURE

if [[ $(basename "$0") == main.sh ]]; then
  • basename 从文件名中剥离目录和后缀
  • $0 执行文件名
umask 002

文件权限是三类用户, 文件所有者user(u),文件所有者所在主群组group(g)、其它用户others(o),上述命令, 可清除其他用户的写权限.

[[ -n $COLUMNS ]] && stty cols $COLUMNS
TTY_X=$(($(stty size | awk '{print $2}')-6))    # determine terminal width
  • stty 检查和修改当前注册的终端的通信参数, cols N, tell the kernel that the terminal has N columns
  • size 显示终端的大小,即行数和列数
source "${SRC}"/scripts/debootstrap.sh	# system specific install
source "${SRC}"/scripts/image-helpers.sh	# helpers for OS image building
source "${SRC}"/scripts/distributions.sh	# system specific install
source "${SRC}"/scripts/desktop.sh		# desktop specific install
source "${SRC}"/scripts/compilation.sh	# patching and compilation of kernel, uboot, ATF
source "${SRC}"/scripts/makeboarddeb.sh	# create board support package
source "${SRC}"/scripts/general.sh		# general functions
source "${SRC}"/scripts/chroot-buildpackages.sh	# building packages in chroot
source "${SRC}"/scripts/pack-uboot.sh
prepare_host_basic
if [[ -z $BUILD_OPT ]]; then
  • -z str  如果给定字符串的长度为0,测试结果为真。
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)

whiptail 是替代 dialog 的实现,它基于 newt 库.而 newt 则是为了简化 ncurses 开发而产生的新的 tty 下的UI库

3>&1 1>&2 2>&3
The 3>&1 in your command line will create a new file descriptor and redirect it to 1 which is STDOUT. Now 1>&2 will redirect the file descriptor 1 to STDERR and 2>&3 will redirect file descriptor 2 to 3 which is STDOUT.

  • Create a new fd 3 and point it to the fd 1
  • Redirect file descriptor 1 to file descriptor 2. If we wouldn’t have saved the file descriptor in 3 we would lose the target.
  • Redirect file descriptor 2 to file descriptor 3. Now file descriptors one and two are switched.

/build.sh


变量设置

SRC=“$(dirname “$(realpath “${BASH_SOURCE[0]}”)”)”
CHANGED_FILES=$(git diff --name-only)
SHELL_ONLY=yes
export DEBIAN_FRONTEND=noninteractive
EXTER=“${SRC}/external”
CONFIG=“userpatches/config-$1.conf”
CONFIG_FILE=“$(realpath “$CONFIG”)”
CONFIG_PATH=$(dirname “$CONFIG_FILE”)
USERPATCHES_PATH=“$CONFIG_PATH”
BUILD_ALL == demo

SRC="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"`
  • BASH_SOURCE[0]: 取得bash的当前路径, 以及完整命令
  • realpath: 获取bash绝对路径
  • dirname: 获取路径信息, 剔除文件名
grep -q "[[:space:]]" <<<"${SRC}" && { echo "\"${SRC}\" contains whitespace. Not supported. Aborting." >&2 ; exit 1 ; }
  • <<< : ${SRC}将作为grep命令, 需处理的信息
  • grep -q "[[:space:]]" : -q, 不显示任何信息, [[:space:]], 匹配空白字符
  • >&2: 将echo包含的信息, 输出到控制台
  • exit 1 : 退出执行
  • cd "${SRC}" || exit || : 当测试条件有一个为真时返回0(真), 全假为假
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

如果general.sh存在, 则(source)_执行_该脚本, 否则输出错误信息,
source的作用, 把一个文件的内容变成shell环境, 即general.sh包含的脚本函数, 将被缓冲, 等待后续调用.

if [[ $EUID == 0 ]] || [[ "$1" == vagrant ]]; then
	:
elif [[ "$1" == docker || "$1" == dockerpurge || "$1" == docker-shell ]] && grep -q `whoami` <(getent group docker); then
	:
else
	display_alert "This script requires root privileges, trying to use sudo" "" "wrn"
	sudo "$SRC/build.sh" "$@"
	exit $?
fi
  • $EUID : ??? 有效用户ID
  • vagrant : 一款用来构建虚拟开发环境的工具,非常适合 php/python/ruby/java 这类语言开发 web 应用,“代码在我机子上运行没有问题”这种说辞将成为历史。可以通过 Vagrant 封装一个 Linux 的开发环境,分发给团队成员。成员可以在自己喜欢的桌面系统(Mac /Windows /Linux)上开发程序,代码却能统一在封装好的环境里运行,非常霸气。
  • docker : 一个开源引擎,可以轻松为任何应用创建一个轻量级、可移植、自给自足的容器。开发者在笔记本上编译测试通过的容器, 可以批量在生产环境中部署,包括VMs(虚拟机)、bare metal、OpenStack 集群和其他的基础应用平台。
  • dockerpurge : ??? docker-purge, docker用户组
  • docker-shell : docker用户组
  • grep -q `whoami` <(getent group docker);在docker组中, 匹配用户名whoami
if [[ -z "$(which whiptail)" ]]; then
	sudo apt-get update
	sudo apt-get install -y whiptail
fi
  • -y : -y/–yes/–assume-yes – assume “yes” as an answer to prompts

apt-get install -y command is usually used to download your desired application which has many configuration options from an online software repository pointed to by your sources.list configuration file and install that application on your Linux machine in a non-interactive manner asking the apt-get package management tool to assume “yes” to any questions that pop-up during the installation process.

  • whiptail : bash交互界面命令whiptail(消息框,提示框,输入框)
if [[ -z "$(which getfacl)" ]]; then
	sudo apt-get update
	sudo apt-get install -y acl
fi
  • getfacl : ”get file access control list“的缩写,其功能是用于显示文件或目录的ACL策略。对指定的文件或目录进行精准的权限控制,FACL一定是不二之选
  • acl : Access Control List 的缩写,主要的目的是在提供传统的 owner,group,others 的 read,write,execute 权限之外的细部权限配置。ACL 可以针对单一使用者,单一文件或目录来进行 r,w,x 的权限规范,对于需要特殊权限的使用状况非常有帮助

检查是否支持ACL
ACL需要Linux内核和文件系统的配合才能工作,大多数Linux发行版本默认都是支持的。但最好能检查一下:
sudo tune2fs -l /dev/sda1 |grep “Default mount options:”
Default mount options: user_xattr acl

if [[ "$1" == vagrant && -z "$(which vagrant)" ]]; then
	display_alert "Vagrant not installed." "Installing"
	sudo apt-get update
	sudo apt-get install -y vagrant virtualbox
fi
  • vagrant : 一款用来构建虚拟开发环境的工具,非常适合 php/python/ruby/java 这类语言开发 web 应用,“代码在我机子上运行没有问题”这种说辞将成为历史。可以通过 Vagrant 封装一个 Linux 的开发环境,分发给团队成员。成员可以在自己喜欢的桌面系统(Mac /Windows /Linux)上开发程序,代码却能统一在封装好的环境里运行,非常霸气。
if [[ "$1" == dockerpurge && -f /etc/debian_version ]]; then
	display_alert "Purging Orange Pi Docker containers" "" "wrn"
	docker container ls -a | grep orangepi | awk '{print $1}' | xargs docker container rm &> /dev/null
	docker image ls | grep orangepi | awk '{print $3}' | xargs docker image rm &> /dev/null
	shift
	set -- "docker" "$@"
fi
  • -f 如果给定的文件存在,且是一个普通文件,测试结果为真。
  • docker container ls -a 可以列出所有的容器,包括正在运行的和没有运行的容器
  • awk '{print $1}' 将某行(一条记录)中, 以空格为分割符, 打印第一个字段
  • xargs

The xargs command builds and executes commands provided through the standard input. It takes the input and converts it into a command argument for another command. This feature is particularly useful in file management, where xargs is used in combination with rm, cp, mkdir, and other similar commands.

  • &> /dev/null 将命令输出, 重定向至空设备文件, 即, 不显示任何信息
  • docker image ls 列出所有的镜像 (包含中间镜像层)
  • awk '{print $3}' 将某行(一条记录)中, 以空格为分割符, 打印第三个字段
if [[ "$1" == docker-shell ]]; then
	shift
	SHELL_ONLY=yes
	set -- "docker" "$@"
fi
  • shift 命令参数的顺位获取,可从第一个参数开始, 依次遍历每个参数, 然后进行相应处理
  • set -- "docker" "$@"

直接运行set,会显示所有的环境变量和 Shell 函数
===========================================
$@表示从1开始的所有位置参数,每个参数是一个单独的字。单独引用时,$@相当于$1、$2、$3 …,表示多个单独的参数。前后加双引号引用时,“$@“相当于”$1”、“$2”、“$3”…,每个参数都是一个单独的前后加双引号的字符串。
=============================================
-- : If no arguments follow this option, then the positional parameters are unset. Otherwise, the positional parameters are set to the arguments, even if some of them begin with a ‘-’.

if [[ "$1" == docker && -f /etc/debian_version && -z "$(which docker)" ]]; then
	# add exception for Ubuntu Focal until Docker provides dedicated binary
	codename=$(lsb_release -sc)
	codeid=$(lsb_release -is | awk '{print tolower($0)}')
	[[ $codeid == linuxmint && $codename == debbie ]] && codename="buster" && codeid="debian"
	[[ $codename == focal ]] && codename="bionic"

	display_alert "Docker not installed." "Installing" "Info"
	echo "deb [arch=amd64] https://download.docker.com/linux/${codeid} ${codename} edge" > /etc/apt/sources.list.d/docker.list

	# minimal set of utilities that are needed for prep
	packages=("curl" "gnupg" "apt-transport-https")
	for i in "${packages[@]}"
	do
	[[ ! $(which $i) ]] && install_packages+=$i" "
	done
	[[ -z $install_packages ]] && apt-get update;apt-get install -y -qq --no-install-recommends $install_packages

	curl -fsSL "https://download.docker.com/linux/${codeid}/gpg" | apt-key add -qq - > /dev/null 2>&1
	export DEBIAN_FRONTEND=noninteractive
	apt-get update
	apt-get install -y -qq --no-install-recommends docker-ce
	display_alert "Add yourself to docker group to avoid root privileges" "" "wrn"
	"$SRC/build.sh" "$@"
	exit $?
fi
  • -z "$(which docker)"

which  在环境变量$PATH目录里, 匹配文件名
-z str  如果给定字符串的长度为0,测试结果为真

  • codename=$(lsb_release -sc)

lsb_release 查看Linux发行版本, -s, --short 输出简短的描述信息, -c 发行版代号

  • codeid=$(lsb_release -is | awk '{print tolower($0)}')

lsb_release -is, -i 显示发行版的id,
awk ‘{print tolower($0)}’ 字符串中每个大写字符将更改为小写, $0从管道中, 传入的整个字符串

  • for i in "${packages[@]}" [@]
    迭代提取packages包含的所有_字串_(空格分隔)

  • [[ ! $(which $i) ]] && install_packages+=$i" "

which $i1, 测试字串对应的命令, 是否存在
+= 如果命令存在, 可追加到install_packages末尾

  • [[ -z $install_packages ]] && apt-get update;apt-get install -y -qq --no-install-recommends $install_packages

-z 如果给定字符串的长度为0,测试结果为真
-y assume “yes” as an answer to prompts
-qq 不输出信息,错误除外
–no-install-recommends 避免安装非必须的文件,从而减小镜像的体积

  • curl -fsSL "https://download.docker.com/linux/${codeid}/gpg" | apt-key add -qq - > /dev/null 2>&1

curl -fsSL
-f/–fail 不输出错误
-s/–silent 静默模式,不输出任何东西
-S/–show-error 只输出错误信息,通常与-s一起使用
-L/–location 让 HTTP 请求跟随服务器的重定向。curl 默认不跟随重定向

  • apt-key 管理Debian Linux系统中的软件包密钥
  • 2>&1 将标准错误重定向到标准输出
display_alert "Add yourself to docker group to avoid root privileges" "" "wrn"
	"$SRC/build.sh" "$@"

display_alert()
{
#[[ -n $DEST ]] && echo “Displaying message: $@” >> $DEST/debug/output.log
local tmp=“”
[[ -n $2 ]] && tmp=“[\e[0;33m $2 \x1B[0m]”
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
}
display_alert “List of local repos” “local” “err”
display_alert “List of local repos” “local” “wrn”
display_alert “List of local repos” “local” “ext”
display_alert “List of local repos” “local” “info”
display_alert “List of local repos” “local” “other”
在这里插入图片描述
err) echo -e "[\e[0;31m error \x1B[0m] $1 $tmp";;
[\e[0;31m error \x1B[0m] 设置文本error的颜色值

# Create example configs if none found in userpatches
if [[ -z "$CONFIG" && -n "$1" && -f "${SRC}/userpatches/config-$1.conf" ]]; then
	CONFIG="userpatches/config-$1.conf"
	shift
fi

-z str  如果给定字符串的长度为0,测试结果为真。
-n str  如果给定字符串的长度大于0,测试结果为真

pushd $CONFIG_PATH > /dev/null
# shellcheck source=/dev/null
source "$CONFIG_FILE"
popd > /dev/null
  • pushd 将目录添加到目录堆栈顶部,切换当前工作目录到该目录
  • source "$CONFIG_FILE" 将文件中的变量, 设定为环境变量
  • popd 将目录栈中的栈顶目录, 出栈
while [[ $1 == *=* ]]; do
    parameter=${1%%=*}
    value=${1##*=}
    shift
    display_alert "Command line: setting $parameter to" "${value:-(empty)}" "info"
    eval "$parameter=\"$value\""
done

parameter=${1%%=*} 1: 即$1, =* : 匹配模式
==== % : 匹配等号后, 最短的字串, %% : 匹配等号后, 最长的字串(贪婪匹配?)
value=${1##*=} 1: 即$1, *= : 匹配模式
==== # : 匹配等号前, 最短的数字, ## : 匹配等号前, 最长的数字(贪婪匹配?)
eval [args] 读取随后的参数,组合成一个简单的命令,然后提交Shell执行。

update_src()
echo -e "[\e[0;32m o.k. \x1B[0m] This script will try to update"
git pull
CHANGED_FILES=$(git diff --name-only)

-e 输出文本中存在颜色值, [\e[0;32m o.k. \x1B[0m] 设置文本o.k.的颜色值
git pull 当前的本地分支, 将与(远程)唯一的追踪分支, 进行合并.
git diff --name-only 列出合并中, 被更改的文件


if [[ -n $CHANGED_FILES ]]; then
  • -n 如果给定字符串的长度大于0,测试结果为真

read -r

原样读取(Raw mode),不把反斜杠字符解释为转义字符


git checkout

用于切换分支或恢复工作树文件, 还会更新HEAD,将指定的分支设置为当前分支


scripts/general.sh


cleaning()
exit_with_error()
get_package_list_hash()
create_sources_list()
fetch_from_repo()
display_alert()
fingerprint_image()
function boot_logo ()
function distro_menu ()
wait_for_package_manager()
prepare_host_basic()
prepare_host()
function webseed ()
download_and_verify()
function run_after_build()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值