首页 > 系统相关 >Rockchip RK3588 - Rockchip Linux SDK脚本分析

Rockchip RK3588 - Rockchip Linux SDK脚本分析

时间:2024-07-09 21:33:17浏览次数:21  
标签:run RK3588 Rockchip sh hooks build Linux DIR RK

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

开发板 :ArmSoM-Sige7开发板
eMMC64GB
LPDDR48GB
显示屏 :15.6英寸HDMI接口显示屏
u-boot2017.09
linux5.10
----------------------------------------------------------------------------------------------------------------------------

在《Rockchip RK3588 - Rockchip Linux SDK编译》我们SDK的编译流程以及固件升级相关的内容,本节将会对编译脚本进行深入的分析。

一、build.sh分析

Rockchip Linux SDK编译命令是由build.sh脚本实现的,其入口函数为main函数。

1.1 main函数

由于main函数代码内容较长,我们只对重点内容进行分析:

点击查看代码
main()
{
        [ -z "$DEBUG" ] || set -x

        trap 'err_handler' ERR
        set -eE

        # Save intial envionments
        unset INITIAL_SESSION
        INITIAL_ENV=$(mktemp -u)
        if [ -z "$RK_SESSION" ]; then
                INITIAL_SESSION=1
                env > "$INITIAL_ENV"
        fi

        export LC_ALL=C

        export SCRIPTS_DIR="$(dirname "$(realpath "$BASH_SOURCE")")"
        export COMMON_DIR="$(realpath "$SCRIPTS_DIR/..")"
        export SDK_DIR="$(realpath "$COMMON_DIR/../../..")"
        export DEVICE_DIR="$SDK_DIR/device/rockchip"
        export CHIPS_DIR="$DEVICE_DIR/.chips"
        export CHIP_DIR="$DEVICE_DIR/.chip"

        export RK_DATA_DIR="$COMMON_DIR/data"
        export RK_TOOL_DIR="$COMMON_DIR/tools"
        export RK_IMAGE_DIR="$COMMON_DIR/images"
        export RK_KBUILD_DIR="$COMMON_DIR/linux-kbuild"
        export RK_CONFIG_IN="$COMMON_DIR/configs/Config.in"

        export RK_BUILD_HOOK_DIR="$COMMON_DIR/build-hooks"
        export BUILD_HELPER="$RK_BUILD_HOOK_DIR/build-helper"
        export RK_POST_HOOK_DIR="$COMMON_DIR/post-hooks"
        export POST_HELPER="$RK_POST_HOOK_DIR/post-helper"

        export PARTITION_HELPER="$SCRIPTS_DIR/partition-helper"

        export RK_SESSION="${RK_SESSION:-$(date +%F_%H-%M-%S)}"

        export RK_OUTDIR="$SDK_DIR/output"
        export RK_SESSION_DIR="$RK_OUTDIR/sessions"
        export RK_LOG_BASE_DIR="$RK_OUTDIR/log"
        export RK_LOG_DIR="$RK_SESSION_DIR/$RK_SESSION"
        export RK_INITIAL_ENV="$RK_LOG_DIR/initial.env"
        export RK_CUSTOM_ENV="$RK_LOG_DIR/custom.env"
        export RK_FINAL_ENV="$RK_LOG_DIR/final.env"
        export RK_ROCKDEV_DIR="$SDK_DIR/rockdev"
        export RK_FIRMWARE_DIR="$RK_OUTDIR/firmware"
        export RK_SECURITY_FIRMWARE_DIR="$RK_OUTDIR/security-firmware"
        export RK_CONFIG="$RK_OUTDIR/.config"
        export RK_DEFCONFIG_LINK="$RK_OUTDIR/defconfig"

        # For Makefile
        case "$@" in
                make-targets)
                        # Chip targets
                        ls "$CHIPS_DIR"
                        ;&
                make-usage)
                        run_build_hooks "$@"
                        rm -f "$INITIAL_ENV"
                        exit 0 ;;
        esac


        # Log SDK information
        MANIFEST="$SDK_DIR/.repo/manifest.xml"
        if [ -e "$MANIFEST" ]; then
                if [ ! -L "$MANIFEST" ]; then
                        MANIFEST="$SDK_DIR/.repo/manifests/$(grep -o "[^\"]*\.xml" "$MANIFEST")"
                fi
                TAG="$(grep -o "linux-.*-gen-rkr[^.\"]*" "$MANIFEST" | \
                        head -n 1 || true)"
                MANIFEST="$(basename "$(realpath "$MANIFEST")")"
                echo
                echo -e "\e[35m############### Rockchip Linux SDK ###############\e[0m"
                echo
                echo -e "\e[35mManifest: $MANIFEST\e[0m"
                if [ "$TAG" ]; then
                        echo -e "\e[35mVersion: $TAG\e[0m"
                fi
                echo
        fi

        # Prepare firmware dirs
        mkdir -p "$RK_FIRMWARE_DIR" "$RK_SECURITY_FIRMWARE_DIR"

        cd "$SDK_DIR"
        [ -f README.md ] || ln -rsf "$COMMON_DIR/README.md" .
        [ -d common ] || ln -rsf "$COMMON_DIR" .

        # TODO: Remove it in the repo manifest.xml
        rm -f envsetup.sh

        OPTIONS=${@:-allsave}

        # Special handle for chip and defconfig
        # e.g. ./build.sh rk3588:rockchip_defconfig
        for opt in $OPTIONS; do
                if [ -d "$CHIPS_DIR/${opt%%:*}" ]; then
                        OPTIONS=$(echo "$OPTIONS" | xargs -n 1 | \
                                sed "s/^$opt$/chip:$opt/" | xargs)
                elif echo "$opt" | grep -q "^[0-9a-z_]*_defconfig$"; then
                        OPTIONS=$(echo "$OPTIONS" | xargs -n 1 | \
                                sed "s/^$opt$/defconfig:$opt/" | xargs)
                fi
        done

        # Options checking
        CMDS="$(run_build_hooks support-cmds all | xargs)"
        for opt in $OPTIONS; do
                case "$opt" in
                        help | h | -h | --help | usage | \?) usage ;;
                        clean:*)
                                # Check cleanup modules
                                for m in $(echo ${opt#clean:} | tr ':' ' '); do
                                        grep -wq clean_hook \
                                                "$SCRIPTS_DIR/mk-$m.sh" \
                                                2>/dev/null || usage
                                done
                                ;&
                        shell | cleanall)
                                # Check single options
                                if [ "$opt" = "$OPTIONS" ]; then
                                        break
                                fi

                                echo "ERROR: $opt cannot combine with other options!"
                                ;;
                        post-rootfs)
                                if [ "$opt" = "$1" -a -d "$2" ]; then
                                        # Hide other args from build stages
                                        OPTIONS=$opt
                                        break
                                fi

                                echo "ERROR: $opt should be the first option followed by rootfs dir!"
                                ;;
                        *)
                                # Make sure that all options are handled
                                if option_check "$CMDS" $opt; then
                                        continue
                                fi

                                echo "ERROR: Unhandled option: $opt"
                                ;;
                esac

                usage
        done

        # Prepare log dirs
        if [ ! -d "$RK_LOG_DIR" ]; then
                rm -rf "$RK_LOG_BASE_DIR" "$RK_LOG_DIR" "$RK_SESSION_DIR/latest"
                mkdir -p "$RK_LOG_DIR"
                ln -rsf "$RK_SESSION_DIR" "$RK_LOG_BASE_DIR"
                ln -rsf "$RK_LOG_DIR" "$RK_SESSION_DIR/latest"
                echo -e "\e[33mLog saved at $RK_LOG_DIR\e[0m"
                echo
        fi

        # Drop old logs
        cd "$RK_LOG_BASE_DIR"
        rm -rf $(ls -t | sed '1,10d')
        cd "$SDK_DIR"

        # Save initial envionments
        if [ "$INITIAL_SESSION" ]; then
                rm -f "$RK_INITIAL_ENV"
                mv "$INITIAL_ENV" "$RK_INITIAL_ENV"
                ln -rsf "$RK_INITIAL_ENV" "$RK_OUTDIR/"
        fi

        # Init stage (preparing SDK configs, etc.)
        run_build_hooks init $OPTIONS
        rm -f "$RK_OUTDIR/.tmpconfig*"

        # No need to go further
        CMDS="$(run_build_hooks support-cmds pre-build build \
                post-build | xargs) cleanall clean post-rootfs"
        option_check "$CMDS" $OPTIONS || return 0

        # Force exporting config environments
        set -a

        # Load config environments
        source "$RK_CONFIG"
        cp "$RK_CONFIG" "$RK_LOG_DIR"

        if [ -z "$INITIAL_SESSION" ]; then
                # Inherit session environments
                sed -n 's/^\(RK_.*=\)\(.*\)/\1"\2"/p' "$RK_FINAL_ENV" > \
                        "$INITIAL_ENV"
                source "$INITIAL_ENV"
                rm -f "$INITIAL_ENV"
        else
                # Detect and save custom environments

                # Find custom environments
                rm -f "$RK_CUSTOM_ENV"
                for cfg in $(grep "^RK_" "$RK_INITIAL_ENV" || true); do
                        env | grep -q "^${cfg//\"/}$" || \
                                echo "$cfg" >> "$RK_CUSTOM_ENV"
                done

                # Allow custom environments overriding
                if [ -e "$RK_CUSTOM_ENV" ]; then
                        ln -rsf "$RK_CUSTOM_ENV" "$RK_OUTDIR/"

                        echo -e "\e[31mWARN: Found custom environments: \e[0m"
                        cat "$RK_CUSTOM_ENV"

                        echo -e "\e[31mAssuming that is expected, please clear them if otherwise.\e[0m"
                        read -t 10 -p "Press enter to continue."
                        source "$RK_CUSTOM_ENV"

                        if grep -q "^RK_KERNEL_VERSION=" "$RK_CUSTOM_ENV"; then
                                echo -e "\e[31mCustom RK_KERNEL_VERSION ignored!\e[0m"
                                load_config RK_KERNEL_VERSION
                        fi

                        if grep -q "^RK_ROOTFS_SYSTEM=" "$RK_CUSTOM_ENV"; then
                                echo -e "\e[31mCustom RK_ROOTFS_SYSTEM ignored!\e[0m"
                                load_config RK_ROOTFS_SYSTEM
                        fi
                fi
        fi

        source "$PARTITION_HELPER"
        rk_partition_init

        set +a

        export PYTHON3=/usr/bin/python3
        export RK_KERNEL_VERSION_REAL=$(kernel_version_real)

        # Handle special commands
        case "$OPTIONS" in
                cleanall)
                        run_build_hooks clean
                        rm -rf "$RK_OUTDIR" "$SDK_DIR/rockdev"
                        finish_build cleanall
                        exit 0 ;;
                clean:*)
                        MODULES="$(echo ${OPTIONS#clean:} | tr ':' ' ')"
                        for m in $MODULES; do
                                "$SCRIPTS_DIR/mk-$m.sh" clean
                        done
                        finish_build clean - $MODULES
                        exit 0 ;;
                post-rootfs)
                        shift
                        run_post_hooks $@
                        finish_build post-rootfs
                        exit 0 ;;
        esac

        # Save final environments
        rm -f "$RK_FINAL_ENV"
        env > "$RK_FINAL_ENV"
        ln -rsf "$RK_FINAL_ENV" "$RK_OUTDIR/"

        # Log configs
        echo
        echo "=========================================="
        echo "          Final configs"
        echo "=========================================="
        env | grep -E "^RK_.*=.+" | grep -vE "PARTITION_[0-9]" | \
                grep -vE "=\"\"$|_DEFAULT=y" | \
                grep -vE "^RK_CONFIG|_BASE_CFG=|_LINK=|DIR=|_ENV=|_NAME=" | sort
        echo

        # Pre-build stage (submodule configuring, etc.)
        run_build_hooks pre-build $OPTIONS

        # No need to go further
        CMDS="$(run_build_hooks support-cmds build post-build | xargs)"
        option_check "$CMDS" $OPTIONS || return 0

        # Build stage (building, etc.)
        run_build_hooks build $OPTIONS

        # No need to go further
        CMDS="$(run_build_hooks support-cmds post-build | xargs)"
        option_check "$CMDS" $OPTIONS || return 0

        # Post-build stage (firmware packing, etc.)
        run_build_hooks post-build $OPTIONS
}
1.1.1 提示模式和错误处理

调试模式设置:首先通过判断是否设置了环境变量DEBUG,决定是否启用调试模式。如果 DEBUG 被设置为非空值,则运行 set -x 开启调试模式,这样脚本执行时会显示每一行命令的执行情况。

错误处理:使用 trapERR 捕获脚本中的错误。一旦发生错误,将调用 err_handler 函数;同时,set -eE 确保如果任何命令失败,脚本会立即退出,并且支持 ERR 跟踪。

保存初始环境变量:接着尝试保存当前的环境变量到一个临时文件中。首先,它解除定义了 INITIAL_SESSION 变量(如果存在),然后使用 mktemp -u 生成一个唯一的临时文件路径。如果 RK_SESSION 变量未设置,则认为这是一个新的会话,并将所有当前环境变量保存到生成的临时文件中。

1.1.2 设置环境变量

接着是设置一系列环境变,这些变量定义了一些重要的目录路径,通常在脚本执行过程中会用到这些路径。

export LC_ALL=C

export SCRIPTS_DIR="$(dirname "$(realpath "$BASH_SOURCE")")"
export COMMON_DIR="$(realpath "$SCRIPTS_DIR/..")"
......

realpath "$BASH_SOURCE" 获取当前脚本的绝对路径,由于build.sh指向了device/rockchip/common/scripts/build.sh;所以:

SCRIPTS_DIR=<SDK>/device/rockchip/common/scripts
COMMON_DIR=<SDK>/device/rockchip/common
SDK_DIR=<SDK>
DEVICE_DIR=<SDK>/device/rockchip
CHIPS_DIR=<SDK>/device/rockchip/.chips
CHIP_DIR=<SDK>/device/rockchip/.chip
RK_DATA_DIR=<SDK>/device/rockchip/common/data
RK_TOOL_DIR=<SDK>/device/rockchip/common/tools
RK_IMAGE_DIR=<SDK>/device/rockchip/common/images
RK_KBUILD_DIR=<SDK>/device/rockchip/common/linux-kbuild
RK_CONFIG_IN=<SDK>/device/rockchip/common/configs/Config.in
RK_BUILD_HOOK_DIR=<SDK>/device/rockchip/common/build-hooks
BUILD_HELPER=<SDK>/device/rockchip/common/build-hooks/build-helper
RK_POST_HOOK_DIR=<SDK>/device/rockchip/common/post-hooks
POST_HELPER=<SDK>/device/rockchip/common/post-hooks/post-helper
PARTITION_HELPER=<SDK>/device/rockchip/common/scripts/partition-helper
RK_SESSION=2024-07-08_21-52-58
RK_OUTDIR=<SDK>/output
RK_SESSION_DIR=<SDK>output/sessions
RK_LOG_BASE_DIR=<SDK>/output/log
RK_LOG_DIR=<SDK>/output/sessions/2024-07-08_21-52-58
RK_INITIAL_ENV=<SDK>/output/sessions/2024-07-08_21-52-58/initial.env
RK_CUSTOM_ENV=<SDK>/output/sessions/2024-07-08_21-52-58/custom.env
RK_FINAL_ENV=<SDK>/output/sessions/2024-07-08_21-52-58/final.env
RK_ROCKDEV_DIR=<SDK>/rockdev
RK_FIRMWARE_DIR=<SDK>/output/firmware
RK_SECURITY_FIRMWARE_DIR=<SDK>/output/security-firmware
RK_CONFIG=<SDK>/output/.config
RK_DEFCONFIG_LINK=<SDK>/output/defconfig
1.1.3 选项make-targets/make-usage

接着就是对选项make-targetsmake-usage的支持,实际上也是输出帮助信息。

1.1.4 选项chip/defconfig

接着就是对如下选项的支持:

  • chip[:<chip>[:<config>]] <chip>可选,表示SoC,比如rk3588<config>可选,表示板级配置,比如rockchip_defconfig
  • defconfig[:<config>]:<config>可选,表示板级配置,比如rockchip_defconfig

(1) 如果有参数传递给脚本,则OPTIONS被设置为这些参数的组合;如果没有参数传递,则OPTIONS被设置为 allsave

(2) 接着对$OPTIONS变量进行特殊处理,用于处理 chipdefconfig的情况。它会检查每个参数,并根据特定的条件对其进行转换。

首先:

if [ -d "$CHIPS_DIR/${opt%%:*}" ]; then
    OPTIONS=$(echo "$OPTIONS" | xargs -n 1 | \
    sed "s/^$opt$/chip:$opt/" | xargs)

检查是否存在以$CHIPS_DIR开头、后面跟着$opt变量:分隔之前的字符串作为目录名, 如果满足;修改 $OPTIONS 变量,替换内容$optchip:$opt

  • 比如./builsh rk3588:rockchip_defconfigopt=rk3588:rockchip_defconfig,处理后OPTIONS=chip:rk3588:rockchip_defconfig

接着:

elif echo "$opt" | grep -q "^[0-9a-z_]*_defconfig$"; then
    OPTIONS=$(echo "$OPTIONS" | xargs -n 1 | \
        sed "s/^$opt$/defconfig:$opt/" | xargs)
fi

如果是以_defconfig结尾命名,修改 $OPTIONS 变量,替换内容$optdefconfig:$opt

  • 比如./builsh rockchip_defconfigopt=rockchip_defconfig,处理后OPTIONS=defconfig:rockchip_defconfig
1.1.5 选项检查

首先是获取支持的所有命令:

CMDS="$(run_build_hooks support-cmds all | xargs)"

xargs 将会把 run_build_hooks support-cmds all 的输出(echo函数的输出)捕获,并通过管道传递给 xargs。由于run_build_hooks函数会依次执行<SDK>/device/rockchip/common/build-hooks下的sh脚本,因此CMDS存储的就是这些脚本执行的输出结果,具体分析参考后文《run_build_hooks》。

执行完毕CMDS中存储build.sh支持的所有命令;

CMDS='chip defconfig lunch .*_defconfig olddefconfig savedefconfig menuconfig config shell print-parts mod-parts edit-parts new-parts insert-part del-part move-part rename-part resize-part kernel-config kernel-make kmake kernel modules linux-headers wifibt rtos buildroot debian yocto buildroot-config buildroot-make bmake rootfs buildroot debian yocto recovery pcba security_check createkeys security_ramboot security_uboot security_boot security_recovery security_rootfs loader uboot uefi firmware edit-package-file edit-ota-package-file edit-package-file edit-ota-package-file updateimg otapackage all allsave save'

接着是一段选项检查的代码;

for opt in $OPTIONS; do
		case "$opt" in
				help | h | -h | --help | usage | \?) usage ;;
				clean:*)
						# Check cleanup modules
						for m in $(echo ${opt#clean:} | tr ':' ' '); do
								grep -wq clean_hook \
										"$SCRIPTS_DIR/mk-$m.sh" \
										2>/dev/null || usage
						done
						;&
				shell | cleanall)
						# Check single options
						if [ "$opt" = "$OPTIONS" ]; then
								break
						fi

						echo "ERROR: $opt cannot combine with other options!"
						;;
				post-rootfs)
						if [ "$opt" = "$1" -a -d "$2" ]; then
								# Hide other args from build stages
								OPTIONS=$opt
								break
						fi

						echo "ERROR: $opt should be the first option followed by rootfs dir!"
						;;
				*)
						# Make sure that all options are handled
						if option_check "$CMDS" $opt; then
								continue
						fi

						echo "ERROR: Unhandled option: $opt"
						;;
		esac

		usage
done

根据传入的选项($OPTIONS)进行判断和处理,这里遍历选项依次执行:

  • 当选项满足help | h | -h | --help | usage | \?,执行usage函数。比如我们前文执行 ./build.sh help,就是则调用usage函数来显示帮助信息;
  • 如果选项以 clean: 开头,则验证验证相应的清理模块是否存在,比如./build.sh clean:kernel,则判断"device/rockchip/common/scripts/mk-kernel.sh/mk-kernel.sh中是否包含clean_hook方法;后续会调用mk-kernel.sh clean执行清理工作;
  • 如果选项是shellcleanall,执行函数run_build_hooks clean,该函数则会遍历device/rockchip/common/scriptsshell脚本文件,并传入clean参数函数依次执行;
  • 如果选项是post-rootfs,并且满足上面的条件,则设置OPTIONS=$opt
  • 如果不满足以上条件,则调用option_check函数检查给定的命令选项是否在指定的命令列表中,如果匹配失败,则输出错误信息,并调用usage函数。
1.1.6 准备日志目录

接着是创建编译日志目录:

# Prepare log dirs
if [ ! -d "$RK_LOG_DIR" ]; then
		rm -rf "$RK_LOG_BASE_DIR" "$RK_LOG_DIR" "$RK_SESSION_DIR/latest"
		mkdir -p "$RK_LOG_DIR"
		ln -rsf "$RK_SESSION_DIR" "$RK_LOG_BASE_DIR"
		ln -rsf "$RK_LOG_DIR" "$RK_SESSION_DIR/latest"
		echo -e "\e[33mLog saved at $RK_LOG_DIR\e[0m"
		echo
fi

首先判断日志目录$RK_LOG_DIR是否存在,如果该目录不存在,则执行一系列操作来创建目录结构并设置符号链接,将 $RK_LOG_DIR符号链接到$RK_SESSION_DIR/latest,确保最新日志目录符号链接始终指向最新的日志目录。

1.1.7 清理旧日志

接着是清理日志目录,只保留最新的10次编译的日志记录:

# Drop old logs
cd "$RK_LOG_BASE_DIR"
rm -rf $(ls -t | sed '1,10d')
cd "$SDK_DIR"

跳转到<SDK>/output/log目录,把除了最新的10个文件或目录外的所有内容传递给rm -rf命令进行删除操作。

1.1.8 保存初始化环境变量

接着是保存初始化环境变量;

# Save initial envionments
if [ "$INITIAL_SESSION" ]; then
		rm -f "$RK_INITIAL_ENV"
		mv "$INITIAL_ENV" "$RK_INITIAL_ENV"
		ln -rsf "$RK_INITIAL_ENV" "$RK_OUTDIR/"
fi

由于前文设置INITIAL_ENV=$(mktemp-u),即使用mktemp -u生成一个唯一的临时文件路径,比如/tmp/tmp.ag1ffjvNMG

因此该段脚本:

  • 它会先删除旧的<SDK>/output/sessions/initial.env文件;
  • 然后将临时文件移动并重命名为<SDK>/output/sessions/$RK_SESSION/initial.env
  • 最后在指定的输出目录<SDK>/output下创建一个指向<SDK>/output/sessions/$RK_SESSION/initial.env的符号链接。
1.1.9 初始化阶段

脚本进入初始化阶段,用于准备SDK配置等工作;

# Init stage (preparing SDK configs, etc.)
run_build_hooks init $OPTIONS
rm -f "$RK_OUTDIR/.tmpconfig*"

这里再次调用run_build_hooks函数,入参为init $OPTIONS,具体分析参考后文《run_build_hooks》。

1.1.10 选项检查
# No need to go further
CMDS="$(run_build_hooks support-cmds pre-build build \
		post-build | xargs) cleanall clean post-rootfs"
option_check "$CMDS" $OPTIONS || return 0

xargs 将会把 run_build_hooks support-cmds pre-build build post-build 的输出(echo函数的输出)捕获,并通过管道传递给 xargs。由于run_build_hooks函数会依次执行<SDK>/device/rockchip/common/build-hooks下的sh脚本,因此CMDS存储的就是这些脚本执行的输出结果。

执行完毕CMDS中存储build.sh支持的所有命令;

CMDS='shell print-parts mod-parts edit-parts new-parts insert-part del-part move-part rename-part resize-part kernel-config kernel-make kmake kernel modules linux-headers wifibt rtos buildroot-config buildroot-make bmake rootfs buildroot debian yocto recovery pcba security_check createkeys security_ramboot security_uboot security_boot security_recovery security_rootfs loader uboot uefi firmware edit-package-file edit-ota-package-file updateimg otapackage all allsave save cleanall clean post-rootfs'

接着调用option_check检查变量CMDS中的命令是否包含在$OPTIONS指定的选项中。

  • 如果找到任何一个在任何一个选项中有匹配,则函数返回0,表示命令匹配成功;
  • 如果所有的命令都没有在任何一个选项中找到匹配,则函数最终返回1,表示命令匹配失败。

如果option_check函数返回非0值(即失败),则执行return 0,表示退出当前函数。

1.2 option_check

option_check函数检查给定的命令选项是否在指定的命令列表中。

option_check()
{
        # 将第一个参数$1赋值给变量CMDS,这个参数是一组命令列表,用空格分隔
        CMDS="$1"
        # 将参数列表向左移动一位,去掉了第一个参数(即CMDS),剩下的参数存储在$@中
        shift

        # 嵌套循环检查选项和命令
        for opt in $@; do     # 遍历传递给函数的所有剩余参数(除了第一个参数CMDS)
                for cmd in $CMDS; do    # 再嵌套一个循环,遍历存储在CMDS变量中的命令列表
                        # NOTE: There might be patterns in commands 检查命令是否匹配选项,如果grep 命令没有匹配到,则继续下一次循>环
                        echo "${opt%%:*}" | grep -q "^$cmd$" || continue
                        # 如果匹配成功,则返回状态码 0,表示找到了匹配的命令选项
                        return 0
                done
        done

        return 1
}

比如我们给函数传入:

commands="run jump swim"
option_check "$commands" run swim sleep

在这个示例中:

  • $commands被传递给CMDS变量,即CMDS="run jump swim;
  • run swim sleep是要检查的选项,即option1=runoption2=swimoption3=sleep
    函数会逐个检查每个选项是否在命令列表CMDS中,如果找到任意匹配的命令,则返回状态码0;否则返回状态码1。

1.3 run_hooks

run_hooks在指定目录中查找并执行所有以 .sh 结尾的脚本文件。如果执行任何一个脚本失败,它将调用错误处理函数 err_handler 处理错误,并以失败的返回码退出整个脚本。

run_hooks()
{
        # 将第一个参数$1赋值给变量DIR
        DIR="$1"
        # 将参数列表向左移动一位,去掉了第一个参数(即DIR),剩下的参数存储在$@中
        shift

		# 遍历目录
        for dir in "$CHIP_DIR/$(basename "$DIR")/" "$DIR"; do
       	 	    # 当前的$dir是否是一个存在的目录。如果不是,则继续到下一个循环迭代
                [ -d "$dir" ] || continue
				# 在$dir目录下(不深入子目录,-maxdepth 1)查找所有以.sh结尾的文件
                for hook in $(find "$dir" -maxdepth 1 -name "*.sh" | sort); do
                        "$hook" $@ && continue   # *.sh退出状态码为0则执行continue
                        HOOK_RET=$?
                        err_handler $HOOK_RET "${FUNCNAME[0]} $*" "$hook $*"
                        exit $HOOK_RET
                done
        done
}

比如我们给函数传入:

RK_BUILD_HOOK_DIR=<SDK>/device/rockchip/common/build-hooks
run_hooks "$RK_BUILD_HOOK_DIR" support-cmds all

在这个示例中:

  • 将遍历目录<SDK>/device/rockchip/.chip/build-hooks<SDK>/device/rockchip/common/build-hooks

  • 由于<SDK>/device/rockchip/.chip/build-hooks不是目录将跳过;

  • 接着在<SDK>/device/rockchip/common/build-hooks 目录下(不深入子目录,-maxdepth 1)查找所有以.sh 结尾的文件;依次执行

    • 执行找到的每一个脚本文件,传递参数support-cmds all
    • 如果执行成功(exit 0),则继续下一个钩子脚本的执行;
    • 如果执行失败(exit 非0),调用err_handler 函数处理错误,传递错误码、当前函数名以及传递给当前函数的所有参数,以HOOK_RET的值退出脚本,终止整个构建过程。

我们查看<SDK>/device/rockchip/common/build-hooks目录下的sh脚本;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ ll device/rockchip/common/build-hooks/
lrwxrwxrwx  1 root root   23  6月  9 12:58 00-config.sh -> ../scripts/mk-config.sh*
lrwxrwxrwx  1 root root   22  6月  9 12:58 00-shell.sh -> ../scripts/mk-shell.sh*
lrwxrwxrwx  1 root root   27  6月  9 12:58 05-partitions.sh -> ../scripts/mk-partitions.sh*
lrwxrwxrwx  1 root root   23  6月  9 12:58 10-kernel.sh -> ../scripts/mk-kernel.sh*
lrwxrwxrwx  1 root root   23  6月  9 12:58 20-wifibt.sh -> ../scripts/mk-wifibt.sh*
lrwxrwxrwx  1 root root   21  6月  9 12:58 25-rtos.sh -> ../scripts/mk-rtos.sh*
lrwxrwxrwx  1 root root   23  6月  9 12:58 30-rootfs.sh -> ../scripts/mk-rootfs.sh*
lrwxrwxrwx  1 root root   25  6月  9 12:58 40-recovery.sh -> ../scripts/mk-recovery.sh*
lrwxrwxrwx  1 root root   21  6月  9 12:58 50-pcba.sh -> ../scripts/mk-pcba.sh*
lrwxrwxrwx  1 root root   25  6月  9 12:58 60-security.sh -> ../scripts/mk-security.sh*
lrwxrwxrwx  1 root root   23  6月  9 12:58 70-loader.sh -> ../scripts/mk-loader.sh*
lrwxrwxrwx  1 root root   25  6月  9 12:58 80-firmware.sh -> ../scripts/mk-firmware.sh*
lrwxrwxrwx  1 root root   26  6月  9 12:58 90-updateimg.sh -> ../scripts/mk-updateimg.sh*
lrwxrwxrwx  1 root root   20  6月  9 12:58 99-all.sh -> ../scripts/mk-all.sh*
lrwxrwxrwx  1 root root   23  6月  9 12:58 build-helper -> ../scripts/build-helper
-rwxr-xr-x  1 root root 4210  6月  9 12:58 example.sh.in*

在该示例中将会按顺序依次执行这些脚本,并传递参数support-cmds all

1.3.1 00-config.sh

我们以00-config.sh脚本执行为例;

# 如果板载配置不存在在,选择板载配置
prepare_config()
{	
		# 如果<SDK>/device/rockchip/.chip路径不存在,则执行choose_chip选择芯片
		# 如果存在,其指向如下:.chip -> .chips/rk3588/
        [ -e "$CHIP_DIR" ] || choose_chip

		# 进入<SDK>/device/rockchip
        cd "$DEVICE_DIR"
        # 查找/device/rockchip/.chips目录下文件,即删除rk3588   rk3588 -> .chips/rk3588/
        rm -f $(ls "$CHIPS_DIR")   
        # ln -rsf .chips/rk3588 .
        ln -rsf "$(readlink "$CHIP_DIR")" .
        
        # 跳转到SDK目录
        cd "$SDK_DIR"

		# 如果<SDK>/output/defconfig文件不存在或不可读,则执行choose_chip选择芯片		
        if [ ! -r "$RK_DEFCONFIG_LINK" ]; then
                echo "WARN: $RK_DEFCONFIG_LINK not exists"
                choose_defconfig
                return 0
        fi

	    # 由<SDK>/output/defconfig -> ../device/rockchip/.chips/rk3588/rockchip_rk3588_sige7_defconfig,得到rockchip_rk3588_sige7_defconfig
        DEFCONFIG=$(basename "$(realpath "$RK_DEFCONFIG_LINK")")
        
        # 检查两个文件是否不是同一个文件
        if [ ! "$RK_DEFCONFIG_LINK" -ef "$CHIP_DIR/$DEFCONFIG" ]; then
                echo "WARN: $RK_DEFCONFIG_LINK is invalid"
                choose_defconfig
                return 0
        fi

		# 检查文件$RK_CONFIG是否比$RK_DEFCONFIG_LINK更旧
        if [ "$RK_CONFIG" -ot "$RK_DEFCONFIG_LINK" ]; then
                echo "WARN: $RK_CONFIG is out-dated"
                $MAKE $DEFCONFIG &>/dev/null
                return 0
        fi

        CONFIG_DIR="$(dirname "$RK_CONFIG_IN")"
        if find "$CONFIG_DIR" -cnewer "$RK_CONFIG" | grep -q ""; then
                echo "WARN: $CONFIG_DIR is updated"
                $MAKE $DEFCONFIG &>/dev/null
                return 0
        fi

        CFG="RK_DEFCONFIG=\"$(realpath "$RK_DEFCONFIG_LINK")\""
        if ! grep -wq "$CFG" "$RK_CONFIG"; then
                echo "WARN: $RK_CONFIG is invalid"
                $MAKE $DEFCONFIG &>/dev/null
                return 0
        fi

        if [ "$RK_CONFIG" -nt "${RK_CONFIG}.old" ]; then
                $MAKE olddefconfig &>/dev/null
                touch "${RK_CONFIG}.old"
        fi
}
.......
# 这里实际上就是定义00-config.sh支持的命令
INIT_CMDS="chip defconfig lunch .*_defconfig olddefconfig savedefconfig menuconfig config default"

# init_hook default
init_hook()
{
        case "${1:-default}" in
                chip) shift; choose_chip $@ ;;
                lunch|defconfig) shift; choose_defconfig $@ ;;
                *_defconfig) switch_defconfig "$1" ;;
                olddefconfig | savedefconfig | menuconfig)
                        prepare_config
                        $MAKE $1
                        ;;
                config)
                        prepare_config
                        $MAKE menuconfig
                        $MAKE savedefconfig
                        ;;
                default) prepare_config ;; # End of init  走这里
                *) usage ;;
        esac
}

#  source SDK/device/rockchip/common/build-hooks/build-helper,将会输出00-config.sh支持的命令
source "${BUILD_HELPER:-$(dirname "$(realpath "$0")")/../build-hooks/build-helper}"

init_hook $@

首先执行SDK/device/rockchip/common/build-hooks/build-helper脚本,会将这个脚本的内容直接加载到当前shell环境中执行,因此build-helper.sh 能够获取父文件中的变量和参数;

......

# 跳转到<SDK>目录
cd "$SDK_DIR"

# 比如 LOG_FILE_NAME=00-config-support-cmds_2024-07-08_21-12-25
LOG_FILE_NAME="$(basename "${0%.sh}")-$1_$(date +"%F_%H-%M-%S")"

# 参数1为support-cmds
case "$1" in
        help | h | -h | --help | \?) usage ;;
        make-targets) make_targets; exit 0 ;;
        make-usage) make_usage; exit 0 ;;
        usage) usage_hook; exit 0 ;;
        support-cmds)    # 走这里
        	    # 将参数列表向左移动一位,去掉了第一个参数(support-cmds),剩下的参数存储在$@中(即all)
                shift
                {
                        ALL_CMDS="$INIT_CMDS $PRE_BUILD_CMDS $BUILD_CMDS \
                                $POST_BUILD_CMDS"
                        for stage in ${@:-all}; do
                                case $stage in
                                        init) echo "$INIT_CMDS" ;;
                                        pre-build) echo "$PRE_BUILD_CMDS" ;;
                                        build) echo "$BUILD_CMDS" ;;
                                        post-build) echo "$POST_BUILD_CMDS" ;;
                                        # 走这里,输出支持的命令 chip defconfig lunch .*_defconfig olddefconfig savedefconfig menuconfig config
                                        all) echo "$ALL_CMDS" ;;   
                                esac
                        done
                } | xargs -n 1 | grep -v "^default$" | xargs || true   # 过滤掉单独包含 "default" 的行,然后将剩余的行作为参数依次传递给下一个命令
                exit 0
                ;;
        clean)
                try_func clean_hook
                exit 0
                ;;
        init)
                shift
                try_hook init_hook "$INIT_CMDS" $@
                exit 0
                ;;
        pre-build)
                shift
                try_hook pre_build_hook "$PRE_BUILD_CMDS" $@
                exit 0
                ;;
        build)
                shift
                try_hook build_hook "$BUILD_CMDS" $@
                exit 0
                ;;
        post-build)
                shift
                try_hook post_build_hook "$POST_BUILD_CMDS" $@
                exit 0
                ;;
esac

if [ "$DRY_RUN" ]; then
        echo "Environment 'DRY_RUN' ignored!"
        unset DRY_RUN
fi

if [ "$2" = cmds ]; then
        export DRY_RUN=1
fi
1.3.1.1 入参为support-cmds all

如果入参为support-cmds all,代码会进入support-cmds分支;

support-cmds)    # 走这里
		# 将参数列表向左移动一位,去掉了第一个参数(support-cmds),剩下的参数存储在$@中(即all)
		shift
		{
				ALL_CMDS="$INIT_CMDS $PRE_BUILD_CMDS $BUILD_CMDS \
						$POST_BUILD_CMDS"
				for stage in ${@:-all}; do
						case $stage in
								init) echo "$INIT_CMDS" ;;
								pre-build) echo "$PRE_BUILD_CMDS" ;;
								build) echo "$BUILD_CMDS" ;;
								post-build) echo "$POST_BUILD_CMDS" ;;
								# 走这里,输出支持的命令 chip defconfig lunch .*_defconfig olddefconfig savedefconfig menuconfig config
								all) echo "$ALL_CMDS" ;;   
						esac
				done
		} | xargs -n 1 | grep -v "^default$" | xargs || true   # 过滤掉单独包含 "default" 的行,然后将剩余的行作为参数依次传递给下一个命令
		exit 0
		;;

首先输出$ALL_CMDS,最后执行exit 0退出00-config.sh脚本文件的执行。

1.3.1.2 入参为init recovery

如果入参为init recovery,代码会进入init分支;

init)
        # 将参数列表向左移动一位,去掉了第一个参数(support-cmds),剩下的参数存储在$@中(即recovery)
		shift
		try_hook init_hook "$INIT_CMDS" $@
		exit 0
		;;

因此将会执行try_hook函数,函数定义如下:

# try_hook init_hook 'chip defconfig lunch .*_defconfig olddefconfig savedefconfig menuconfig config default' recovery
try_hook()
{
	    # init_hook
        FUNC=$1
        # 将参数列表向左移动一位,去掉了第一个参数(init_hook)
        shift
        # 'chip defconfig lunch .*_defconfig olddefconfig savedefconfig menuconfig config default'
        CMDS="$1"
         # 将参数列表向左移动一位,去掉了第二个参数(CMDS)
        shift

        if echo "$CMDS" | grep -qE "^default( |$)"; then
                OPTS="default $@"
        else
        		# 走这里OPTS=recovery default
                OPTS="$@ default"
        fi
		# 检查名为$FUNC的函数是否存在并且可执行,不存在或不可执行则return 0
        type $FUNC >/dev/null 2>/dev/null || return 0
		
		# 遍历选项:recovery default
        for opt in $OPTS; do
                IS_DRY_RUN=$(echo $opt | grep -E ":cmds(:|$)" || true)
                # 遍历命令:chip defconfig lunch .*_defconfig olddefconfig 
                for cmd in $CMDS; do
                        # NOTE: There might be patterns in commands .... default
                        ARGS="$(echo $opt | grep -E "^$cmd(:|$)" | \
                                tr ':' ' ' || true)"
                        [ "$ARGS" ] || continue

                        DRY_RUN=${DRY_RUN:-${IS_DRY_RUN:+1}} \
                                try_func $FUNC $ARGS
                done
        done
}

双层循环匹配下来,只有opt=defaultcmd=default时会执行try_func $FUNC $ARGS

try_func init_hook default

try_func函数定义如下:

# try_func init_hook default
try_func()
{
		# 检查名为init_hook的函数是否存在并且可执行,不存在或不可执行则return 0
        type $1 >/dev/null 2>/dev/null || return 0

        # Don't log these hooks
        case "${1%_hook}" in   # 第一个参数移除_hook,即init
                init | pre_build)
                        $@          # 执行init_hook default
                        return 0
                        ;;
        esac

        if [ "$DRY_RUN" ]; then
                DRY_FUNC=$1_dry
                type $DRY_FUNC >/dev/null 2>/dev/null || return 0

                shift
                $DRY_FUNC $@
                return 0
        fi

        LOG_FILE="$(start_log ${LOG_FILE_NAME%%_*} $LOG_FILE_NAME)"
        echo -e "# run func: $@\n" >> "$LOG_FILE"
        $@ 2>&1 | tee -a "$LOG_FILE"

        FUNC_RET=${PIPESTATUS[0]}
        if [ $FUNC_RET -ne 0 ]; then
                err_handler $FUNC_RET "${FUNCNAME[0]} $*" "$@"
                exit $FUNC_RET
        fi
}

经过分析我们知道最终调用的是init_hook default

1.3.2 05-partitions.sh

我们以05-partitions.sh脚本执行为例;

......
# 这里实际上就是定义05-partitions.sh支持的命令
PRE_BUILD_CMDS="print-parts mod-parts edit-parts new-parts insert-part del-part move-part rename-part resize-part"
pre_build_hook()
{
        check_config RK_PARAMETER || return 0

        CMD=$1
        shift

        case "$CMD" in
                print-parts) rk_partition_print $@ ;;
                mod-parts) modify_partitions $@ ;;
                edit-parts) rk_partition_edit $@ ;;
                new-parts) rk_partition_create $@ ;;
                insert-part) rk_partition_insert $@ ;;
                del-part) rk_partition_del $@ ;;
                move-part) rk_partition_move $@ ;;
                rename-part) rk_partition_rename $@ ;;
                resize-part) rk_partition_resize $@ ;;
                *)
                        normalized_usage
                        exit 1
                        ;;
        esac

        finish_build $CMD $@
}

#  source SDK/device/rockchip/common/build-hooks/build-helper,将会输出05-partitions.sh支持的命令
source "${BUILD_HELPER:-$(dirname "$(realpath "$0")")/../build-hooks/build-helper}"

pre_build_hook $@
1.3.2.1 入参support-cmds all

如果入参为support-cmds all,代码会进入support-cmds分支,执行流程00-config,sh所介绍。

1.4 run_build_hooks

run_build_hooks函数作用是运行一些构建过程中的钩子(hooks),并且记录执行日志。

run_build_hooks()
{
        # Don't log these hooks
        case "$1" in
                init | pre-build | make-* | usage | support-cmds)
                        run_hooks "$RK_BUILD_HOOK_DIR" $@ || true
                        return 0
                        ;;
        esac

        LOG_FILE="$(start_log "$1")"

        echo -e "# run hook: $@\n" >> "$LOG_FILE"
        run_hooks "$RK_BUILD_HOOK_DIR" $@ 2>&1 | tee -a "$LOG_FILE"
        HOOK_RET=${PIPESTATUS[0]}
        if [ $HOOK_RET -ne 0 ]; then
                err_handler $HOOK_RET "${FUNCNAME[0]} $*" "$@"
                exit $HOOK_RET
        fi
}

函数执行流程如下:

  • 根据传递给函数的第一个参数$1进行匹配,如果$1匹配到initpre-build、以make-开头的任意字符串、usage或者 support-cmds中的一个;

    • 调用run_hooks函数,并传递参数<SDK>/device/rockchip/common/build-hooks$@(所有传递给当前函数的参数);
    • || true 确保即使run_hooks函数失败,也不会中断执行;
    • 返回状态码 0,表示成功执行;
  • 设置日志文件:LOG_FILE被设置为一个日志文件的路径,使用start_log函数生成基于传入参数$1的日志文件名;

  • 记录运行日志:将# run hook: $@打印到$LOG_FILE中;

  • 运行钩子并记录输出:

    • 再次调用run_hooks函数,传递<SDK>/device/rockchip/common/build-hooks$@,标准错误(2)输出到(>)到标准输出(&1);
    • 将标准错误输出重定向到标准输出,这样可以确保错误信息也被tee命令捕获到;
    • tee -a将管道中的输出同时输出到标准输出和追加到$LOG_FILE文件中;
  • 处理钩子执行结果:将管道中上一个命令的退出状态保存在HOOK_RET变量中,PIPESTATUS[0]Bash 内置的数组,包含了最近一个管道中命令的退出状态;

    • 如果HOOK_RET不等于 0,则表示有错误发生;
    • 调用err_handler 数处理错误,传递错误码、当前函数名以及传递给当前函数的所有参数;
    • HOOK_RET的值退出脚本,终止整个构建过程。

接下来我们以./build.sh recovery命令为例,介绍main函数中是如何调用run_build_hooks 函数的,其执行顺序依次为;

  • run_build_hooks support-cmds all
  • run_build_hooks init recovery
  • run_build_hooks support-cmds pre-build build post-build
  • run_build_hooks pre-build recovery
  • run_build_hooks support-cmds build post-build
  • run_build_hooks build recovery
  • run_build_hooks support-cmds post-build
  • run_build_hooks post-buildrecovery
1.4.1 run_build_hooks support-cmds all

比如我们给函数传入support-cmds all ,即获取./build.sh支持的所有命令:

run_build_hooks support-cmds all 

在这个示例中:

  • $1匹配到support-cmds
  • 调用run_hooks函数,并传递参数<SDK>/device/rockchip/common/build-hooks support-cmds all
    • 将依次执行<SDK>/device/rockchip/common/build-hooks目录下的sh脚本,入参为support-cmds all
    • 输出每个sh脚本支持的命令;
  • 所有sh脚本执行完,直接return 0
1.4.2 run_build_hooks init recovery

比如我们给函数传入 init recovery,则进行recovery相关的初始化工作:

run_build_hooks init recovery

在这个示例中:

  • $1匹配到init
  • 调用run_hooks函数,并传递参数<SDK>/device/rockchip/common/build-hooks init recovery
    • 将依次执行<SDK>/device/rockchip/common/build-hooks目录下的sh脚本,入参为init recovery
    • 在每个sh脚本执行try_hook init_hook "$INIT_CMDS" recovery;
      • 循环遍历数组recovery default,赋值给opt
      • 循环遍历数组$INIT_CMDS,赋值给cmd
      • 对于匹配项执行try_func init_hook $ARGS(姑且将ARGS等价成opt),最终调用sh脚本中的init_hook $ARGS方法;
  • 所有sh脚本执行完,直接return 0
1.4.3 run_build_hooks support-cmds pre-build build post-build
1.4.4 run_build_hooks pre-build recovery
1.4.5 run_build_hooks support-cmds build post-build
1.4.6 run_build_hooks build recovery

比如我们给函数传入:

run_build_hooks build  recovery

在这个示例中:

(1) $1无法匹配initpre-build等;

(2) 设置日志文件,并记录运行日志,比如output/sessions/latest/40-recovery-build_2024-07-08_23-05-50

# 2024-07-08 22:43:41
# run func: build_hook recovery

==========================================
          Start building recovery(buildroot)
==========================================
make: Entering directory '/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot'
  GEN     /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/Makefile
......
  Init Ramdisk: ramdisk
  FDT:          fdt
you take 0:01.02 to pack recovery image
^[[35mRunning 40-recovery.sh - build_recovery succeeded.^[[0m

(3) 调用run_hooks函数,传递<SDK>/device/rockchip/common/build-hooks build recovery

1.4.7 run_build_hooks support-cmds post-build
1.4.8 run_build_hooks post-buildrecovery

参考文章

[1] Rockchip_Developer_Guide_Linux_Software_CN.pdf

[2] repo介绍与使用

[3] Rockchip_Developer_Guide_Linux_Upgrade_CN.pdf

[4] Rockchip RK3588 - NanoPC-T6开发板介绍

[5] Rockchip RK3399 - NanoPC-T4开发板介绍

[6] Buildroot根文件系统构建

[7] Debian根文件系统构建

标签:run,RK3588,Rockchip,sh,hooks,build,Linux,DIR,RK
From: https://www.cnblogs.com/zyly/p/18292765

相关文章

  • Linux C++ 045-设计模式之工厂模式
    LinuxC++045-设计模式之工厂模式本节关键字:Linux、C++、设计模式、简单工厂模式、工厂方法模式、抽象工厂模式相关库函数:简单工厂模式基本简介从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(StaticFactoryMethod)模式,但不属于23种GOF设计模......
  • Linux常用命令
    1.1ls语法:ls[选项][⽬录或⽂件]功能:对于⽬录,该命令列出该⽬录下的所有⼦⽬录与⽂件。对于⽂件,将列出⽂件名以及其他信息。-a列出⽬录下的所有⽂件,包括以.开头的隐含⽂件。-d将⽬录象⽂件⼀样显⽰,⽽不是显⽰其下的⽂件。如:ls‒d指定⽬录-k以k字节的形式表......
  • 【Linux网络编程-4】线程
    开辟进程会分配新的地址空间,系统开销高。每个进程可以有很多线程,同个进程的线程共享地址空间,共享全局变量和对象,系统开销较低。头文件#include<pthread.h>pid类型pid类型pthread_t,实质是unsignedlongint,一串长长的无符号整数链接要指定pthread共享库g++-o......
  • linux进程管理
    Linux进程管理什么是程序:应用程序是用户选择安装的程序的总称,通常包括驱动程序的进程,看图软件、解压缩软件等通用软件的进程.也可以顾名思义地说:应用程序就是为使用者提供与电脑沟通所开发出来的程序软件什么是进程:狭义定义:进程就是一段程序的执行过程。 广义定义:进程是......
  • Linux从入门到精通—— 如何在 Linux 系统中启用 Kubectl 命令自动补全
    如何在Linux系统中启用Kubectl命令自动补全一、背景在使用Kubernetes进行日常开发和运维工作时,kubectl命令行工具是不可或缺的一部分。为了提升工作效率,启用kubectl命令的自动补全功能是一个明智的选择。本文将指导你如何在基于Linux的系统上安装并配置kubectl命令的......
  • Linux web服务
    Web服务在Linux中存在许多可以提供web服务的软件,httpd、tomcat、nginx等Web通信的基本概念基于B/S架构的网页服务HTTPHTML【1】、httpd软件1、httpd软件安装httpd是软件基金会写出的软件基金会(Apache)yuminstall-yhttpdrpm-qahttpdhttpd-2.4.37-62.mod......
  • Linux FTP服务
    FTP服务安装vsftpd软件yuminstall-yvsftpd[root@moudle0114:47:28~]#rpm-qvsftpdvsftpd-3.0.3-36.el8.x86_64修改配置文件,开启无需验证的功能vim/etc/vsftpd/vsftpd.conf#修改内容如下,将NO改为YESanonymous_enable=YES启动服务#找到vsftpd程序[ro......
  • linux学习之登录密码(ssh/telnet)
    在Linux系统中,用户登录密码是用于安全验证用户身份的一种方式。登录密码通常是加密后存储在系统的/etc/shadow文件中。如果您想要获取Linux系统中用户的登录密码,这通常是不可能的,因为密码是经过加密处理的,而且出于安全考虑,没有直接的方式可以获取它们的明文形式。/etc/passwd......
  • .net core部署linux下载文件 文件为中文下载
    在项目中,需要下载模板,某个文件夹下有excel文件或者word等 文件名为中文的时候在linux服务器下载不了  如果直接写路由的话在windows下是可以直接访问的,但是core部署在linux上所以会有些不同第一种:写一个接口使用流下载[httpget("download")]publicasyncTask<FileResult......
  • Linux 搭建SFTP环境
    SFTP(SSH文件传输协议)可以用来安全地传输文件。以下是在Linux服务器上设置SFTP服务的基本步骤: 1) 安装OpenSSH服务:sudoapt-getupdatesudoapt-getinstallopenssh-server2) 创建SFTP用户并设置密码:sudoaddusersftpusersudopasswdsftpuser3) 创建一个目录,用于SF......