【嵌入式移植】5、U-Boot源码分析2—make nanopi_neo2_defconfig

2024-01-29 06:20

本文主要是介绍【嵌入式移植】5、U-Boot源码分析2—make nanopi_neo2_defconfig,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

U-Boot源码分析2—make nanopi_neo2_defconfig

  • 1 概述
  • 2 nanopi_neo2_defconfig
  • 3 编译过程分析
    • 3.1 编译目标
    • 3.2 scripts_basic
    • 3.2.1 prefix src定义
    • 3.2.2 PHONY
    • 3.2.3 __build
    • 3.2.4 fixdep
    • 3.3 obj=scripts/kconfig

1 概述

上一章中,对Makefile相关源码进行了初步分析,这里结合编译过程具体分析其执行过程。

2 nanopi_neo2_defconfig

nanopi_neo2_defconfig文件位于./config/目录下,内容如下

CONFIG_ARM=y
CONFIG_ARCH_SUNXI=y
CONFIG_MACH_SUN50I_H5=y
CONFIG_DRAM_CLK=672
CONFIG_DRAM_ZQ=3881977
CONFIG_DEFAULT_DEVICE_TREE="sun50i-h5-nanopi-neo2"
# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
CONFIG_SPL=y
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_FPGA is not set
# CONFIG_SPL_DOS_PARTITION is not set
# CONFIG_SPL_ISO_PARTITION is not set
# CONFIG_SPL_EFI_PARTITION is not set
CONFIG_SUN8I_EMAC=y
CONFIG_USB_EHCI_HCD=y
CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y

3 编译过程分析

首先通过make nanopi_neo2_defconfig -n命令,-n表示仅输出执行过程中的命令序列,而不真正执行

make -f ./scripts/Makefile.build obj=scripts/basic
set -e;  echo '  HOSTCC  scripts/basic/fixdep'; cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer      -o scripts/basic/fixdep scripts/basic/fixdep.c  ; scripts/basic/fixdep scripts/basic/.fixdep.d scripts/basic/fixdep 'cc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer      -o scripts/basic/fixdep scripts/basic/fixdep.c  ' > scripts/basic/.fixdep.tmp; rm -f scripts/basic/.fixdep.d; mv -f scripts/basic/.fixdep.tmp scripts/basic/.fixdep.cmd
:
rm -f .tmp_quiet_recordmcount
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig
set -e;  echo '  HOSTCC  scripts/kconfig/conf.o'; cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE   -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c; scripts/basic/fixdep scripts/kconfig/.conf.o.d scripts/kconfig/conf.o 'cc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE   -c -o scripts/kconfig/conf.o scripts/kconfig/conf.c' > scripts/kconfig/.conf.o.tmp; rm -f scripts/kconfig/.conf.o.d; mv -f scripts/kconfig/.conf.o.tmp scripts/kconfig/.conf.o.cmd
echo '  SHIPPED scripts/kconfig/zconf.tab.c'; cat scripts/kconfig/zconf.tab.c_shipped > scripts/kconfig/zconf.tab.c
echo '  SHIPPED scripts/kconfig/zconf.lex.c'; cat scripts/kconfig/zconf.lex.c_shipped > scripts/kconfig/zconf.lex.c
echo '  SHIPPED scripts/kconfig/zconf.hash.c'; cat scripts/kconfig/zconf.hash.c_shipped > scripts/kconfig/zconf.hash.c
set -e;  echo '  HOSTCC  scripts/kconfig/zconf.tab.o'; cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE  -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c; scripts/basic/fixdep scripts/kconfig/.zconf.tab.o.d scripts/kconfig/zconf.tab.o 'cc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE  -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.c' > scripts/kconfig/.zconf.tab.o.tmp; rm -f scripts/kconfig/.zconf.tab.o.d; mv -f scripts/kconfig/.zconf.tab.o.tmp scripts/kconfig/.zconf.tab.o.cmd
set -e;  echo '  HOSTLD  scripts/kconfig/conf'; cc  -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o  ; printf '%s\n' 'cmd_scripts/kconfig/conf := cc  -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o  ' > scripts/kconfig/.conf.cmd
scripts/kconfig/conf  --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig

也可以通过make nanopi_neo2_defconfig V=1命令查看编译过程中的详细输出

make -f ./scripts/Makefile.build obj=scripts/basiccc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer      -o scripts/basic/fixdep scripts/basic/fixdep.c  
rm -f .tmp_quiet_recordmcount
make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfigcc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE   -c -o scripts/kconfig/conf.o scripts/kconfig/conf.ccat scripts/kconfig/zconf.tab.c_shipped > scripts/kconfig/zconf.tab.ccat scripts/kconfig/zconf.lex.c_shipped > scripts/kconfig/zconf.lex.ccat scripts/kconfig/zconf.hash.c_shipped > scripts/kconfig/zconf.hash.ccc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE  -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.ccc  -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o  
scripts/kconfig/conf  --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig
#
# configuration written to .config
#

下面根据上述内容,对照Makefile源码进行分析

3.1 编译目标

执行make nanopi_neo2_defconfig V=1时,编译目标为nanopi_neo2_defconfig ,即MAKECMDGOALS = nanopi_neo2_defconfig

在Makefile源码中搜索:defconfig:无相关项,搜索config:有两处匹配
请添加图片描述
对应Makefile中源码为
请添加图片描述
根据上一章3.16节的分析,当执行make xxx_defconfig时,此时config-targets = 1, mixed-targets = 0, dot-config = 1,满足第467行条件 ,因此分支有效。

根据编译目标MAKECMDGOALS = nanopi_neo2_defconfig,与第478行匹配(其中%为通配符),即nanopi_neo2_defconfig依赖项为scripts_basic outputmakefile FORCE,其中FORCE在第1702行定义
请添加图片描述
FORCE的依赖项与执行语句均为空,即为没有命令或者依赖的规则,这样的规则每次在执行时,目标总会被认为是最新的(更新过的),因此当它被作为其它规则的依赖时,由于FORCE总是被认为是更新过的,所以在FORCE所在的规则中定义的命令总会被执行

也就是说,由于FORCE是没有命令或者依赖的规则,而nanopi_neo2_defconfig依赖项包含FORCE,每次都会执行nanopi_neo2_defconfig规则的命令

将Makefile源码中的变量替换为其值,得到nanopi_neo2_defconfig规则的全貌(其中$@为Makefile的自动化变量,表示目前规则中所有的目标的集合)

nanopi_neo2_defconfig: scripts_basic outputmakefile FORCEmake -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig

对于依赖项outputmakefile,根据上一章分析可知为空,因此

nanopi_neo2_defconfig: scripts_basic FORCEmake -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig

3.2 scripts_basic

搜索Makefile中scripts_basic规则,仅有一处
请添加图片描述
scripts_basic规则没有依赖项,其命令为(-f为指定其它文件为描述文件)

scripts_basic:make -f ./scripts/Makefile.build obj=scripts/basicrm -f .tmp_quiet_recordmcount

对应命令序列的第1行和第3行,也即编译过程中输出信息的第1行和第3行

后续对./scripts/Makefile.build文件进行分析

3.2.1 prefix src定义

第9行~17行,定义了2个变量,这里obj在执行命令时输入,为scripts/basic
请添加图片描述
最终结果为

prefix = .
src = scripts/basic

3.2.2 PHONY

第19行~54行,定义PHONY等变量,并包含一些文件
请添加图片描述
PHONY为第一个出现的规则,也为默认规则,实际上的默认目标为其依赖项__build,在这里__build暂时为空

第57行~59行,定义了kbuild-file并包含。
首先是kbuild-dir的赋值,这里if语句不满足条件,因此kbuild-dir的值为后半部分$(srctree)/$(src),即kbuild-dir = ./scripts/basic
./scripts/basic目录下无Kbuild文件,因此58行的if语句不满足条件,kbuild-file的值为后半部分$(kbuild-dir)/Makefile,即kbuild-file = ./scripts/basic/Makefile
第59行包含此Makefile

3.2.3 __build

查找__build,在**第116行119行**定义了依赖项和规则,116行118行为依赖项,119行为规则
请添加图片描述
这里KBUILD_BUILTINKBUILD_MODULES在顶层Makefile中定义:KBUILD_BUILTIN :=1 KBUILD_MODULES :=,因此__build规则为

__build: $(builtin-target) $(lib-target) $(extra-y) $(subdir-ym) $(always)@:

builtin-target在第108行~110行定义
请添加图片描述
其中obj-yobj-mobj-subdir-mextra-ysubdir-ym均为空,则lib-targetbuiltin-target也为空

因此__build规则为

__build: $(always)@:

always./scripts/basic/Makefile(根据前面的分析,在Makefile.build的第59行使用include关键字调用量,因此在第59行会先执行此Makefile文件中的内容)中赋值为always := $(hostprogs-y),而hostprogs-y := fixdep,并增加obj的值作为前缀请添加图片描述
always = scripts/basic/fixdep,因此__build规则最终为

__build: scripts/basic/fixdep@:

因此__build规则也即scripts_basic规则最终结果为生成fixdep,根据注释可知,fixdep是用于编译其它的宿主机程序

3.2.4 fixdep

使用grep命令grep -rnw fixdep搜索fixdep关键字
请添加图片描述
可以看到在scripts/Makefile.build文件中存在相应规则
请添加图片描述
可知fixdep通过调用make-cmd函数,输入参数为cc_o_c编译而来;搜索make-cmd关键字,在scripts/Kbuild.include中有定义
请添加图片描述
请添加图片描述
可知在make-cmd中,输入参数将组合成cmd_$(1),即cmd_cc_o_c;在scripts/路径下搜索cmd_cc_o_c
请添加图片描述
请添加图片描述
根据前述分析可知未定义CONFIG_MODVERSIONS,因此cmd_cc_o_c命令如下,其中@$为自动化变量,表示目标集合,@<表示所有的依赖集合

cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<

结合编译输出

make -f ./scripts/Makefile.build obj=scripts/basiccc -Wp,-MD,scripts/basic/.fixdep.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer      -o scripts/basic/fixdep scripts/basic/fixdep.c  

即使用CC命令,将scripts/basic/fixdep.c编译为scripts/basic/fixdep

另:(通过gcc -v --help可以查看所有 <options >用法)

  • -Wp, <option>将逗号分隔的 <options >传递给预处理器(preprocessor);-MD,scripts/basic/.fixdep.d生成文件关联信息,包含目标文件所依赖的所有源代码,将输出导入到.d文件里面;
  • -Wall生成所有警告信息;
  • -Wstrict-prototypesWarn about unprototyped function declarations;
  • -O0不做任何优化,这是默认的编译选项;
  • -O1优化会消耗少多的编译时间,它主要对代码的分支,常量以及表达式等进行优化;
  • -O2会尝试更多的寄存器级的优化以及指令级的优化,它会在编译期间占用更多的内存和编译时间;
  • -O3在 O2 的基础上进行更多的优化,例如使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化;
  • -Os主要是对代码大小的优化,我们基本不用做更多的关心。
`-O0`不做任何优化,这是默认的编译选项;
`-Os``-O1`对程序做部分编译优化,对于大函数,优化编译占用稍微多的时间和相当大的内存。使用本项优化,编译器会尝试减小生成代码的尺寸,以及缩短执行时间,但并不执行需要占用大量编译时间的优化;
`-O2`是比 O1 更高级的选项,进行更多的优化,Gcc 将执行几乎所有的不包含时间和空间折中的优化。当设置 O2 选项时,编译器并不进行循环打开 loop unrolling 以及函数内联。与 O1 比较而言,O2 优化增加了编译时间的基础上,提高了生成代码的执行效率;
`-O3`比 O2 更进一步的进行优化,打开`-finline-functions``-fweb``-frename-registers``-funswitch-loops`优化选项,即使用伪寄存器网络,普通函数的内联,以及针对循环的更多优化

任何级别的优化都将带来代码结构的改变。例如:对分支的合并和消除,对公用子表达式的消除,对循环内 load/store 操作的替换和更改等,都将会使目标代码的执行顺序变得面目全非,导致调试信息严重不足;在 O2 优化后,编译器会对影响内存操作的执行顺序

3.3 obj=scripts/kconfig

上述分析已经执行make nanopi_neo2_defconfig所需依赖目标scripts_basic进行了分析,结果为生成fixdep工具

nanopi_neo2_defconfig: scripts_basic FORCEmake -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig

现在来看后续的命令语句

	make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfig

根据3.2.1节和3.2.2节中对./scripts/Makefile.build文件的分析,各变量取值为

obj         = scripts/kconfig
prefix      = . 
src         = scripts/kconfig
kbuild-dir  = scripts/kconfig
kbuild-file = scripts/kconfig/Makefile

第59行通过include $(kbuild-file)语句调用scripts/kconfig/Makefile,目标为nanopi_neo2_defconfig,因此在文件中查找关键字defconfig
请添加图片描述
可知在第120行存在目标规则匹配
请添加图片描述
根据文件内变量取值,此规则翻译如下,其中$<表示依赖项的挨个值,这里只有一个,即scripts/kconfig/conf

nanopi_neo2_defconfig: scripts/kconfig/confscripts/kconfig/conf --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig

结合编译过程的输出,可知通过如下过程,编译出所需的conf工具
conf工具主要由conf.czconf.tab.czconf.lex.czconf.hash.c几个文件编译而来;其中zconf.tab.c-Bison解析器、zconf.lex.c-flex解析器、zconf.hash.c-哈希解析器?,从名字可知为不同解析器的函数源码;main函数在conf.c中)

make -f ./scripts/Makefile.build obj=scripts/kconfig nanopi_neo2_defconfigcc -Wp,-MD,scripts/kconfig/.conf.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE   -c -o scripts/kconfig/conf.o scripts/kconfig/conf.ccat scripts/kconfig/zconf.tab.c_shipped > scripts/kconfig/zconf.tab.ccat scripts/kconfig/zconf.lex.c_shipped > scripts/kconfig/zconf.lex.ccat scripts/kconfig/zconf.hash.c_shipped > scripts/kconfig/zconf.hash.ccc -Wp,-MD,scripts/kconfig/.zconf.tab.o.d -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer    -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DCURSES_LOC="<ncurses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE  -Iscripts/kconfig -c -o scripts/kconfig/zconf.tab.o scripts/kconfig/zconf.tab.ccc  -o scripts/kconfig/conf scripts/kconfig/conf.o scripts/kconfig/zconf.tab.o  

然后使用此conf工具,执行

scripts/kconfig/conf  --defconfig=arch/../configs/nanopi_neo2_defconfig Kconfig

根据conf.cmain函数,通过输入参数获取配置文件路径,然后调用conf_read函数读取文件内容,再调用conf_write,将内容写入默认的.config文件中

make nanopi_neo2_defconfig命令将生成fixdepconf两个工具,

然后根据默认的配置文件nanopi_neo2_defconfig生成U-Boot根目录下的.config文件

完结撒花✿✿ヽ(°▽°)ノ✿

这篇关于【嵌入式移植】5、U-Boot源码分析2—make nanopi_neo2_defconfig的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/656006

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

荣耀嵌入式面试题及参考答案

在项目中是否有使用过实时操作系统? 在我参与的项目中,有使用过实时操作系统。实时操作系统(RTOS)在对时间要求严格的应用场景中具有重要作用。我曾参与的一个工业自动化控制项目就采用了实时操作系统。在这个项目中,需要对多个传感器的数据进行实时采集和处理,并根据采集到的数据及时控制执行机构的动作。实时操作系统能够提供确定性的响应时间,确保关键任务在规定的时间内完成。 使用实时操作系统的

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud