当前位置: 首页 > news >正文

【嵌入式Linux】源码菜单配置 | 编译 | 菜单配置的实现 | 源码编译的实现

源码配置编译

源码配置编译,要把中间各个环节都理清楚

厂商把自己增加的东西专门放了个文件独立,方便开发者发现变化

1.菜单配置

移植的第一步,就是选配,通过make menuconfig图形化界面选配

//载入配置
$ make ARCH=arm64 tegra_defconfig  //导入官方配置//会从arch/arm64/configs下 查找tegra_defconfig,导入到当前目录,重命名为.config)
$ make menuconfig //在官方配置基础上进行配置//从零配置
$ mv  .config .config.ago //如有,则改名 -> 清除当前配置(.config)
$ make  menuconfig ARCH=arm64 /*生成最初始配置界面(如不指定ARCH,默认的是x86的)当前目录有.config则导入,如无则用默认x86配置生成.config*///保存配置
$ make savedefconfig //生成defconfig  (相比make  menuconfig 里的Save保存的配置,这是最简的)
$ cp defconfig arch/arm64/configs/my_defconfig //发布配置(原厂发布配置到内核就是该方式)

1.1载入配置

//载入配置
$ make ARCH=arm64 tegra_defconfig  //导入官方配置//会从arch/arm64/configs下 查找tegra_defconfig,导入到当前目录,重命名为.config)
$ make menuconfig //在官方配置基础上进行配置

1.2从零配置

//从零配置
$ mv  .config .config.ago //如有,则改名 -> 清除当前配置(.config)
$ make  menuconfig ARCH=arm64 /*生成最初始配置界面(如不指定ARCH,默认的是x86的)当前目录有.config则导入,如无则用默认x86配置生成.config*/

ARM64的全新的配置

image-20220911224510091

General setup->Cross-compiler tool prefix 交叉编译工具(可以这里指定,也可以Makefile中改)

Enable loadable module support 模块的支持ko文件

Enable the block layer 块设备支持

Platform selection 平台选择,虽然架构一样,但是不同厂商的芯片也各不同

Bus support 总线支持,例如PCIe等

Kernel Features 内核特性

Boot options 启动选项,可以默认bootargs

Power management options 电源管理

Networking support 网络

Device Drivers 驱动

1.3保存配置

//第一种,make menuconfig生成的.config放到对应目录,比较多无关信息
cd ~/kernel-4.9
cp .config arch/arm64/configs/yhai_defconfig
//第二种保存配置
$ make savedefconfig //生成defconfig  (相比make  menuconfig 里的Save保存的配置,这是最简的)
$ cp defconfig arch/arm64/configs/yhai_defconfig //发布配置(原厂发布配置到内核就是该方式)

2.编译

$ make  /*编译所有常需指定 交叉编译工具链 CROSS_COMPILE(如无默认采用 gcc)
方式一: make  CROSS_COMPILE=aarch64-linux-gnu-   直接指定
方式二: export CROSS_COMPILE=aarch64-linux-gnu-  导出环境变量*/
$ make  all
$ make Image //只编译内核
$ make modules //只编译模块
$ make dtbs //只编译设备树$ make install /*安装内核  就是把编译出来的二进制文件,库,配置文件等等放到相应目录下常需指定 安装路径 INSTALL_PATH
方式一: make install INSTALL_PATH=/tftpboot   直接指定
方式二: export INSTALL_PATH=/tftpboot  导出环境变量*/
$ make modules_install /*安装模块常需指定 安装路径 INSTALL_MOD_PATH
方式一:make modules_install INSTALL_MOD_PATH=~/Linux_for_Tegra/rootfs   直接指定
方式二:export INSTALL_MOD_PATH=~/Linux_for_Tegra/rootfs  导出环境变量*/

3.菜单配置的实现

为什么make menuconfig后能生成图形界面

image-20220912134924752

3.1顶层配置

Kconfig 总菜单

source “arch/$SRCARCH/Kconfig” 子菜单

menu “Bus support” 显示的字

menuconfig 可以选的菜单

config 可以选的参数

default 默认选择 显示-*-

bool 只有YN 显示[*]

tristate 三态YNM 显示<>

{//Kconfig
//对应菜单信息 .config - Linux/arm64 4.9.253 Kernel Configuration
mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration"config SRCARCHstringoption env="SRCARCH"source "arch/$SRCARCH/Kconfig" //导入子Kconfig}{//arch/arm64/Kconfig
source "init/Kconfig"  //gf  跳转到子配置【这个对应General setup --->】source "kernel/Kconfig.freezer"                                       source "arch/arm64/Kconfig.platforms"     //3.2平台选择                            menu "Bus support"                                                    config PCI                                                            bool "PCI support"help                                                              This feature enables support for PCI bus system. If you say Yhere, the kernel will include drivers and infrastructure code   to support PCI bus devices.   
source "drivers/pci/Kconfig"endmenumenu "Kernel Features"
menu "Boot options"
config CMDLINEstring "Default kernel command string"default ""helpProvide a set of default command-line options at build time byentering them here. As a minimum, you should specify the theroot device (e.g. root=/dev/nfs).source "net/Kconfig"source "drivers/Kconfig" //gf跳转   //3.3驱动配置source "drivers/firmware/Kconfig"}{//init/Kconfigmenu "General setup"  //常规的内核选项安装config CROSS_COMPILEstring "Cross-compiler tool prefix"  //设置交叉编译工具链前缀helpSame as running make CROSS_COMPILE=prefix-' but stored fordefault make runs in this kernel build directory.  You don'tneed to set this unless you want the configured kernel builddirectory to select the cross-compiler automatically.config BLK_DEV_INITRD      //是否支持ramdisk 做引导rootsbool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"}

3.2平台选择

//arch/arm64/Kconfig.platforms	  平台选择
menu "Platform selection"	
config ARCH_TEGRAbool "NVIDIA Tegra SoC Family"select ARCH_HAS_RESET_CONTROLLERselect CLKDEV_LOOKUPselect CLKSRC_MMIOselect CLKSRC_OFselect GENERIC_CLOCKEVENTSselect GPIOLIBselect PINCTRLselect GENERIC_PINCONFselect PMselect PM_GENERIC_DOMAINSselect RESET_CONTROLLERhelpThis enables support for the NVIDIA Tegra SoC family

3.3驱动配置

{//drivers/Kconfig
menu "Device Drivers"source "drivers/base/Kconfig"
source "drivers/net/Kconfig"}

image-20220912141132800

{//drivers/net/Kconfig
menuconfig NETDEVICESdefault y if UMLdepends on NETbool "Network device support"source "drivers/net/ethernet/Kconfig"}

image-20220912141219159

{//drivers/net/ethernet/Kconfig
source "drivers/net/ethernet/realtek/Kconfig"
}

image-20220912141349572

{//drivers/net/ethernet/realtek/Kconfig
config R8169   //对应Makefile里 $(CONFIG_R8169)tristate "Realtek 8169 gigabit ethernet support"depends on PCIselect FW_LOADERselect CRC32select MII---help---Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.To compile this driver as a module, choose M here: the modulewill be called r8169.  This is recommended.}

image-20220912141446199

3.4当前的配置文件

//Makefile在编译时通过读取.config文件的配置来选择要编译的文件
CONFIG_ARM64=y
CONFIG_MMU=y
CONFIG_CROSS_COMPILE=""
CONFIG_ROOT_NFS=y	
CONFIG_R8169=y
CONFIG_VIDEO_IMX219=y	

3.5配置头文件

//include/generated/autoconf.h	配置头文件(编译后自动生成的 )
//通过该文件,可知当前生效的配置是那些
#define CONFIG_R8169 1     //有线网卡
#define CONFIG_VIDEO_IMX219 1	 //排线摄像头

4.源码编译的实现

image-20220912144604399

image-20220912144637098

make的时候根据时间最新原则以及该最新变过的依赖重新编译生成.o文件,再连接到一起

make clean会把.o文件给删掉,下次再make就会很废时间

Kconfig和Makefile都是成对出现的,从最顶层逐渐往下面的子文件走

4.1顶层管理

//Makefile : 顶层 Makefile,负责总体内核的编译链接ARCH      ?= $(SUBARCH)  //指定arch(如传参 make  ARCH=arm64),如不指定默认x86//为避免重复输入,强制写死 如ARCH        ?= arm64
CROSS_COMPILE  ?= $(CONFIG_CROSS_COMPILE:"%"=%) //指定交叉编译工具链//(如传参 make  CROSS_COMPILE=aarch64-linux-gnu-)//强制写死CROSS_COMPILE   ?= aarch64-linux-gnu-LD		= $(CROSS_COMPILE)ld
CC		= $(CROSS_COMPILE)gcc//指定源码子目录
drivers-y   := drivers/ sound/ firmware/
core-y      += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/	srctree := .  //指定源码树顶层目录
objtree := .  //指定目标文件树顶层目录include arch/$(SRCARCH)/Makefile //指定导入 arch的子MakefilePHONY := _all //入口:默认的依赖目标: make时,递归查_all依赖文件,//某文件不存在或有更改(时间最新),则把依赖它的文件都重新编译。
_all: allall: modules //make all时,递归查modules的依赖%config: scripts_basic outputmakefile FORCE   //%通配符,xxconfig就从这里走$(Q)$(MAKE) $(build)=scripts/kconfig $@   //再脚本选择配置入口 如make menuconfigKCONFIG_CONFIG  ?= .config  //读入当前配置文件modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpostdistclean: mrproper    //慎用,它会把你前面的配置,全部清除掉@find $(srctree) $(RCS_FIND_IGNORE) \-o -name '.*.rej' -o -name '*%' help:@echo  'Cleaning targets:'@echo  '$(CROSS_COMPILE)'	 //查看变量CROSS_COMPILE的内容, 	 @表示不显示eho本身

4.2通用规则、脚本

//scripts/kconfig/Makefile	
menuconfig: $(obj)/mconf$< $(silent) $(Kconfig) 		//导入Kconfig ,生成图形界面

4.3体系结构的管理

{//arch/arm64/Makefile:  编译体系结构的子Makefile
//负责本体系结构的相关代码编译 生成内核镜像//指定源码子目录
core-y		+= arch/arm64/kernel/ arch/arm64/mm/
core-$(CONFIG_NET) += arch/arm64/net/    //$(CONFIG_NET)是当配置后,会变为y,或m -> 实现界面配置 那些源码编译或不编译KBUILD_IMAGE	:= Image.gz
KBUILD_DTBS	:= dtbs  all:	$(KBUILD_IMAGE) $(KBUILD_DTBS)  //入口boot := arch/arm64/boot  //指定存放Image 的目录Image: vmlinux  //make Image 的入口,指定编译内核镜像$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@dtbs:    //make dtbs 的入口,指定编译设备树$(Q)$(MAKE) $(build)=$(boot)/dts
}{//arch/arm64/kernel/Makefile# Object file lists. //指定编译的文件(写死的),只需指定.o ,到时会自动找到.c 或.s的文件去编译
arm64-obj-y		:= debug-monitors.o entry.o irq.o fpsimd.o		\entry-fpsimd.o process.o 	
arm64-obj-$(CONFIG_PCI)			+= pci.o  //配置时可改变 $(CONFIG_PCI)的值  -> 实现编译文件的	动态调整	   obj-y					+= $(arm64-obj-y) //添加编进内核的文件
obj-m					+= $(arm64-obj-m) //添加编成模块的文件			   
}

4.4子文件的管理

{//init/Makefile
obj-y                          := main.o version.o mounts.o
obj-$(CONFIG_BLK_DEV_INITRD)   += initramfs.o	
}{//drivers/net/ethernet/realtek/Makefile
obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_ATP) += atp.o
obj-$(CONFIG_R8169) += r8169.o  //变量$(CONFIG_NET) 由配置时决定 -> 动态决定编译文件}

如果要添加新的驱动,将其编译进内核,如vr_sensor.c文件,放到对应的文件夹下

直接在Makefile中添加obj-y += vr_sensor.o即可,这样最快,可以不用和Kconfig和CONFIG打交道

当然这样添加多了比较混乱

还是在这个文件夹下Kconfig中添加对应config即可,再到顶层make menuconfig也不麻烦

image-20220912201357705

相关文章:

【嵌入式Linux】源码菜单配置 | 编译 | 菜单配置的实现 | 源码编译的实现

源码配置编译 源码配置编译,要把中间各个环节都理清楚 厂商把自己增加的东西专门放了个文件独立&#xff0c;方便开发者发现变化 1.菜单配置 移植的第一步&#xff0c;就是选配&#xff0c;通过make menuconfig图形化界面选配 //载入配置 $ make ARCHarm64 tegra_defconfi…...

python自动化爬虫实战

python自动化爬虫实战 偶然的一次机会再次用到爬虫&#xff0c;借此机会记录一下爬虫的学习经历&#xff0c;方便后续复用。 需求&#xff1a;爬取网站数据并存入的csv文件中&#xff0c;总体分为两步 爬取网站数据存到到csv文件中 1、配置爬虫环境 1.1、下载自动化测试驱动 …...

LVGL-最新版本及其版本定义标准

lvgl的最新版本是9.0.0&#xff0c;处于开发分支中。 稳定版本是8.3.0. 建议一般开发使用稳定版8.3.0. .\lvgl.h定义了当前版本 /*************************** CURRENT VERSION OF LVGL ***************************/ #define LVGL_VERSION_MAJOR 8 #define LVGL_VERSION_MINO…...

ORB_SLAM2算法中如何计算右目和左目两个特征点的是否匹配?

文章目录 if(kpR.octave<levelL-1 || kpR.octave>levelL+1)const int &levelL = kpL.octave;if(uR>=minU && uR<=maxU)const cv::Mat &dR = mDescriptorsRight.row(iR);const int dist = ORBmatcher::DescriptorDistance(dL,dR);筛选最佳匹配特征点…...

Android 12.0系统Settings主页去掉搜索框

1.概述 在12.0定制化开发中,在系统原生设置中主页的搜索框是要求去掉的,不需要搜索功能,所以首选看下布局文件 看下搜索框是哪个布局,然后隐藏到布局,达到实现功能的目的 2.系统Settings主页去掉搜索框的主要代码 packages/apps/Settings/src/com/android/settings/home…...

电脑数据丢失如何恢复

随着电脑使用的日益普及&#xff0c;数据丢失成为了很多用户不得不面对的问题。数据丢失的原因有很多&#xff0c;例如误删除文件、磁盘格式化、电脑病毒等等。一旦发生数据丢失的情况&#xff0c;我们就需要利用专业的数据恢复工具来尽快找回被丢失的数据。下面我们就来详细介…...

大数据分析案例-基于决策树算法构建世界杯比赛预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…...

Python 图形界面框架 PyQt5 使用指南

Python 图形界面框架 PyQt5 使用指南 使用Python开发图形界面的软件其实并不多&#xff0c;相对于GUI界面&#xff0c;可能Web方式的应用更受人欢迎。但对于像我一样对其他编程语言比如C#或WPF并不熟悉的人来说&#xff0c;未必不是一个好的工具。 常见GUI框架 PyQt5[1]&#…...

代码随想录算法训练营第四十二天 | 二维dp数组01背包, 力扣 416. 分割等和子集

背包 解析 1.确定dp数组以及下标的含义 对于背包问题&#xff0c;有一种写法&#xff0c; 是使用二维数组&#xff0c;即dp[i][j] 表示从下标为[0-i]的物品里任意取&#xff0c;放进容量为j的背包&#xff0c;价值总和最大是多少。 2.确定递推公式 有两个方向推出来dp[i][…...

【1110. 删点成林】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给出二叉树的根节点 root&#xff0c;树上每个节点都有一个不同的值。 如果节点值在 to_delete 中出现&#xff0c;我们就把该节点从树上删去&#xff0c;最后得到一个森林&#xff08;一些不相交的…...

第三章 JVM内存概述

附录&#xff1a;精选面试题 Q&#xff1a;为什么虚拟机必须保证一个类的Clinit( )方法在多线程的情况下被同步加锁 &#xff1f; A: 因为虚拟机在加载完一个类之后直接把这个类放到本地内存的方法区&#xff08;也叫原空间&#xff09;中了&#xff0c;当其他程序再来调这个类…...

基于SpringBoot的企业客户信息反馈平台的设计与实现

背景 企业客户信息反馈平台能够通过互联网得到广泛的、全面的宣传&#xff0c;让尽可能多的用户了解和熟知企业客户信息反馈平台的便捷高效&#xff0c;不仅为客户提供了服务&#xff0c;而且也推广了自己&#xff0c;让更多的客户了解自己。对于企业客户信息反馈而言&#xf…...

【SA8295P 源码分析】01 - SA8295P 芯片介绍

【SA8295P 源码分析】01 - SA8295P 芯片介绍 一、Processors 处理器介绍二、Memory 内存介绍三、Multimedia 多媒体介绍3.1 DPU 显示处理器:Adreno DPU 11993.2 摄像头ISP:Spectra 395 ISP3.3 视频处理器:Adreno video processing unit (VPU)3.4 图像处理器:Adreno graphic…...

扩展1:Ray Core详细介绍

扩展1:Ray Core详细介绍 导航 1. 简介和背景2. Ray的基本概念和核心组件3. 分布式任务调度和依赖管理4. 对象存储和数据共享5. Actor模型和并发编程6. Ray的高级功能和扩展性7. 使用Ray构建分布式应用程序的案例研究8. Ray社区和资源9. 核心框架介绍...

day08 Spring MVC

spring MVC相当于Servlet mvc解释:模型,视图,控制器 **使用该思想的作用:**减少耦合性,提高可维护性 Spring MVC前端控制器 方式1 1.在web.xml中配置前端控制器方式2 ​ 要是用前端控制器,必须在web.xml中配置DidpatcherServlet类 <!--前端控制器--> <servlet&g…...

c++中的extern “C“

在一些c语言的library库中&#xff0c;我们经常可以还看下面这样的结构 #ifndef __TEST_H #define __TEST_H#ifdef _cplusplus extern "C" { #endif/*...*/#ifdef _cplusplus } #endif #endif#ifndef __TEST_H这样的宏定义应该是非常常见了&#xff0c;其作用是为了…...

python异常处理名称整理

Python 异常处理 python提供了两个非常重要的功能来处理python程序在运行中出现的异常和错误。你可以使用该功能来调试python程序。BaseException所有异常的基类UnboundLocalError访问未初始化的本地变量SystemExit...

SpringMVC拦截器

SpringMVC拦截器 介绍 拦截器&#xff08;interceptor&#xff09;的作用 SpringMVC的拦截器类似于Servlet开发中的过滤器Filter&#xff0c;用于对处理器 进行预处理和后处理 将拦截器按一定的顺序连接成一条链&#xff0c;这条链称为拦截器链&#xff08;Interception Ch…...

Python第八章作业(初级)

目录 第1关&#xff1a;统计字母数量 第2关&#xff1a;统计文章字符数 第3关&#xff1a;查询高校信息 第4关&#xff1a;查询高校名 第5关&#xff1a;通讯录读取 第6关&#xff1a;JSON转列表 第7关&#xff1a;利用数据文件统计成绩 第8关&#xff1a;研究生录取数据…...

chatgpt赋能python:Python中如何取消列表

Python中如何取消列表 在Python中使用列表是一种非常常见的数据结构&#xff0c;它允许我们在其中存储任意数量的元素&#xff0c;并且可以非常容易地进行遍历和操作。但是&#xff0c;有时候我们需要从列表中删除元素。这个过程并不难&#xff0c;但是有些细节需要注意。本文…...

大模型应用落地:新手/程序员必备五类关键技术选型指南(收藏版)

大模型应用落地&#xff1a;新手/程序员必备五类关键技术选型指南&#xff08;收藏版&#xff09; 本文从产品经理视角出发&#xff0c;详细介绍了大模型应用落地的五类关键技术&#xff08;Prompt、RAG、Workflow、Agent、模型微调&#xff09;及其适用场景。强调技术选型应遵…...

【Ease UI】2026-04-03组件更新:新增组件xly-file-preview文件预览组件

&#x1f680; 即插即用的 Vue 3 业务组件库&#xff0c;让中后台开发回归简单 Ease UI 是一套为「快速复制」而生的 Vue 3 业务组件库。每个组件都是独立的 .vue 单文件&#xff0c;不依赖任何外部样式或工具函数&#xff0c;直接复制到你的项目即可使用。它仅依赖 Element P…...

seo网络优化如何提高网站的转化率

SEO网络优化如何提高网站的转化率 在当前的互联网时代&#xff0c;网站的流量和转化率是衡量企业在网络上竞争力的重要指标。而搜索引擎优化&#xff08;SEO&#xff09;网络优化作为提高网站流量和转化率的有效手段&#xff0c;其重要性不言而喻。SEO网络优化究竟能如何有效提…...

[x-cmd] 写给计算机科学爱好者的 x-cmd 入门指南

写给计算机科学爱好者的 x-cmd 入门指南 为什么要用 命令行 整合多样能力: 当你长期只需要做一件事时&#xff0c;其实只需熟悉这项业务的图形用户界面&#xff08;例如一个网页控制台&#xff09;&#xff1b;但如果要处理多项业务时: 例如&#xff0c;在开发时&#xff0c;…...

实战应用:基于快马平台开发智能家居设备配对与控制中心

最近在做一个智能家居设备的控制中心项目&#xff0c;正好用InsCode(快马)平台快速实现了原型开发。这个项目最核心的就是设备配对功能&#xff0c;下面分享下我的实战经验。 项目架构设计 整个控制中心采用前后端分离架构&#xff0c;前端用ReactTypeScript实现&#xff0c;后…...

TouchGal终极指南:3步打造你的专属Galgame社区家园

TouchGal终极指南&#xff1a;3步打造你的专属Galgame社区家园 【免费下载链接】kun-touchgal-next TouchGAL是立足于分享快乐的一站式Galgame文化社区, 为Gal爱好者提供一片净土! 项目地址: https://gitcode.com/gh_mirrors/ku/kun-touchgal-next TouchGal是一个专为Ga…...

BilibiliDown:突破B站视频离线限制的高效解决方案

BilibiliDown&#xff1a;突破B站视频离线限制的高效解决方案 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader &#x1f633; 项目地址: https://gitcode.com/gh_mirrors/bi/Bi…...

Mac小白必看:OpenClaw汉化版安装与Qwen3.5-9B快速接入

Mac小白必看&#xff1a;OpenClaw汉化版安装与Qwen3.5-9B快速接入 1. 为什么选择OpenClaw汉化版&#xff1f; 作为一个长期在Mac上折腾各种开发工具的老用户&#xff0c;我最近被OpenClaw这个"能像人类一样操作电脑"的AI智能体框架深深吸引。但官方英文文档和复杂的…...

4步攻克Dlib库Windows安装难题:从环境诊断到功能验证的完整指南

4步攻克Dlib库Windows安装难题&#xff1a;从环境诊断到功能验证的完整指南 【免费下载链接】Dlib_Windows_Python3.x Dlib compiled binaries (.whl) for Python 3.7-3.14 and Windows x64 项目地址: https://gitcode.com/gh_mirrors/dl/Dlib_Windows_Python3.x 一、环…...

PICO开发效率翻倍:手把手教你用PDC串流实现Unity场景‘所见即所得’

PICO开发效率革命&#xff1a;用PDC串流实现Unity场景实时同步的终极指南 在VR内容开发领域&#xff0c;迭代效率往往决定着项目的成败。传统开发流程中&#xff0c;开发者需要反复在Unity编辑器和头显设备之间切换&#xff0c;每次修改后都要经历漫长的构建部署过程&#xff0…...