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

OpenWrt kernel install分析(2)

一. 前言

        接下来分析make -C image compile install TARGET_BUILD=。

二. Makefile分析

1. 命令首先运行target/linux/mediatek/image/Makefile,该文件内容如下:

target/linux/mediatek/image/Makefile:
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/image.mk......# build signed fit
define Build/fit-sign$(TOPDIR)/scripts/mkits.sh \-D $(DEVICE_NAME) \-o $@.its \-k $@ \$(if $(word 2,$(1)),-d $(word 2,$(1))) -C $(word 1,$(1)) \-a $(KERNEL_LOADADDR) \-e $(if $(KERNEL_ENTRY),$(KERNEL_ENTRY),$(KERNEL_LOADADDR)) \-c $(if $(DEVICE_DTS_CONFIG),$(DEVICE_DTS_CONFIG),"config-1") \-A $(LINUX_KARCH) \-v $(LINUX_VERSION) \-s $(KDIR)/$(DEVICE_NAME)-u-boot-script \$(if $(FIT_KEY_NAME),-S $(FIT_KEY_NAME)) \$(if $(FW_AR_VER),-r $(FW_AR_VER))PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage \-f $@.its \$(if $(FIT_KEY_DIR),-k $(FIT_KEY_DIR)) \-r \$@.new@mv $@.new $@
endef# default all platform image(fit) build 
define Device/DefaultPROFILES = Default $$(DEVICE_NAME)KERNEL_NAME := ImageKERNEL = kernel-bin | lzma | \fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtbKERNEL_INITRAMFS = kernel-bin | lzma | \fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtbFILESYSTEMS := squashfsDEVICE_DTS_DIR := $(DTS_DIR)IMAGES := sysupgrade.binIMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | \pad-rootfs | append-metadataFIT_KEY_DIR :=FIT_KEY_NAME :=
endefinclude $(SUBTARGET).mkdefine Image/Build$(call Image/Build/$(1),$(1))
endef$(eval $(call BuildImage))

        BuildImage在include/image.mk中定义,install目标在里面,代码如下:

include/image.mk:
define BuildImage......download:prepare:compile:clean:image_prepare:ifeq ($(IB),).PHONY: download prepare compile clean image_prepare kernel_prepare install install-imagescompile:$(call Build/Compile)clean:$(call Build/Clean)image_prepare: compilemkdir -p $(BIN_DIR) $(KDIR)/tmprm -rf $(BUILD_DIR)/json_info_files$(call Image/Prepare)elseimage_prepare:mkdir -p $(BIN_DIR) $(KDIR)/tmpendifkernel_prepare: image_prepare$(call Image/Build/targz)$(call Image/Build/cpiogz)$(call Image/BuildKernel)$(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(if $(IB),,$(call Image/BuildKernel/Initramfs)))$(call Image/InstallKernel)$(foreach device,$(TARGET_DEVICES),$(call Device,$(device)))install-images: kernel_prepare $(foreach fs,$(filter-out $(if $(UBIFS_OPTS),,ubifs),$(TARGET_FILESYSTEMS) $(fs-subtypes-y)),$(KDIR)/root.$(fs))$(foreach fs,$(TARGET_FILESYSTEMS),$(call Image/Build,$(fs)))install: install-images$(call Image/Manifest)endef

        由上可知,install依赖于install-images,install-images依赖于kernel_prepare,kernel_prepare依赖于image_prepare,由于IB未定义,所以image_prepare定义如下:

compile:$(call Build/Compile)clean:$(call Build/Clean)image_prepare: compilemkdir -p $(BIN_DIR) $(KDIR)/tmprm -rf $(BUILD_DIR)/json_info_files$(call Image/Prepare)

image_prepare依赖于compile,这里,Build/Compile并未定义,所以什么都不干

注意:image_prepare在另一处也有定义,如下:

ifndef IB
define Device/Build/dtbifndef BUILD_DTS_$(1)BUILD_DTS_$(1) := 1$(KDIR)/image-$(1).dtb: FORCE$(call Image/BuildDTB,$(strip $(2))/$(strip $(3)).dts,$$@)image_prepare: $(KDIR)/image-$(1).dtbendifendef
endif

        这里在执行完上面compile依赖,接下来会完成$(KDIR)/image-$(1).dtb这个依赖,也就是生成设备树文件。

这种有两个相同目标的执行过程,下面用一个简单案例解释,如下:

act1:@echo "act1"act2:@echo "act2"target:act1target:act2@echo "target finish"all: target@echo "all finish"

     这里有两个target目标,分别依赖act1和act2,注意,一个target是有执行动作的,一个没有,这里先执行act2依赖,再act1依赖,执行结果如下:

act2
act1
target finish
all finish

 回到分析,

ifndef IB
define Device/Build/dtbifndef BUILD_DTS_$(1)BUILD_DTS_$(1) := 1$(KDIR)/image-$(1).dtb: FORCE$(call Image/BuildDTB,$(strip $(2))/$(strip $(3)).dts,$$@)image_prepare: $(KDIR)/image-$(1).dtbendifendef
endif

$(KDIR)/image-$(1).dtb也是一个目标,动作为$(call Image/BuildDTB,$(strip $(2))/$(strip $(3)).dts,$$@),Image/BuildDTB定义如下,

define Image/BuildDTB$(TARGET_CROSS)cpp -nostdinc -x assembler-with-cpp \-I$(DTS_DIR) \-I$(DTS_DIR)/include \-I$(LINUX_DIR)/include/ \-undef -D__DTS__ $(3) \-o $(2).tmp $(1)$(LINUX_DIR)/scripts/dtc/dtc -O dtb \-i$(dir $(1)) $(DTC_FLAGS) $(4) \-o $(2) $(2).tmp$(RM) $(2).tmp
endef

完整命令展开如下:

aarch64-openwrt-linux-musl-cpp -nostdinc -x assembler-with-cpp -I/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/arch/arm64/boot/dts -I/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/arch/arm64/boot/dts/include -I/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/include/ -undef -D__DTS__  -o /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/image-mt7981-spim-nor-rfb.dtb.tmp /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
aarch64-openwrt-linux-musl-cpp -nostdinc -x assembler-with-cpp -I/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/arch/arm64/boot/dts -I/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/arch/arm64/boot/dts/include -I/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/include/ -undef -D__DTS__ -o /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/image-mt7981-spim-nor-rfb.dtb.tmp /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/scripts/dtc/dtc -O dtb -i/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/arch/arm64/boot/dts/mediatek/ -Wno-unit_address_vs_reg -Wno-simple_bus_reg -Wno-unit_address_format -Wno-pci_bridge -Wno-pci_device_bus_num -Wno-pci_device_reg -Wno-avoid_unnecessary_addr_size -Wno-alias_paths -Wno-graph_child_address -Wno-graph_port -Wno-unique_unit_address  -o /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/image-mt7981-spim-nor-rfb.dtb /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/image-mt7981-spim-nor-rfb.dtb.tmp

注意:

        Device/Build/dtb是由下面代码展开得到的:

$(foreach device,$(TARGET_DEVICES),$(call Device,$(device)))

TARGET_DEVICES定义在target/linux/mediatek/image/mt7981.mk 中,可以如下:

openwrt# grep -rn "TARGET_DEVICES" target/linux/mediatek/image/mt7981.mk 
10:TARGET_DEVICES += mt7981-spim-nor-rfb
27:TARGET_DEVICES += mt7981-spim-nand-2500wan-gmac2
44:TARGET_DEVICES += mt7981-spim-nand-rfb
61:TARGET_DEVICES += mt7981-spim-nand-gsw
74:TARGET_DEVICES += mt7981-emmc-rfb
87:TARGET_DEVICES += mt7981-sd-rfb
104:TARGET_DEVICES += mt7981-snfi-nand-2500wan-p5
113:TARGET_DEVICES += mt7981-fpga-spim-nor
130:TARGET_DEVICES += mt7981-fpga-snfi-nand
147:TARGET_DEVICES += mt7981-fpga-spim-nand
160:TARGET_DEVICES += mt7981-fpga-emmc
173:TARGET_DEVICES += mt7981-fpga-sd

Device的定义如下:

define Device$(call Device/InitProfile,$(1))$(call Device/Init,$(1))$(call Device/Default,$(1))$(call Device/$(1),$(1))$(call Device/Check,$(1))$(call Device/$(if $(DUMP),Dump,Build),$(1))endef

        Device/Default定义在target/linux/mediatek/image/Makefile,内容如下:

define Device/DefaultPROFILES = Default $$(DEVICE_NAME)KERNEL_NAME := ImageKERNEL = kernel-bin | lzma | \fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtbKERNEL_INITRAMFS = kernel-bin | lzma | \fit lzma $$(KDIR)/image-$$(firstword $$(DEVICE_DTS)).dtbFILESYSTEMS := squashfsDEVICE_DTS_DIR := $(DTS_DIR)IMAGES := sysupgrade.binIMAGE/sysupgrade.bin := append-kernel | pad-to 128k | append-rootfs | \pad-rootfs | append-metadataFIT_KEY_DIR :=FIT_KEY_NAME :=
endef

        Device/$(1):由于$(1)=mt7981-spim-nor-rfb,表示Device/mt7981-spim-nor-rfb,定义在target/linux/mediatek/image/mt7981.mk,内容如下:

define Device/mt7981-spim-nor-rfbDEVICE_VENDOR := MediaTekDEVICE_MODEL := mt7981-spim-nor-rfbDEVICE_DTS := mt7981-spim-nor-rfbDEVICE_DTS_DIR := $(DTS_DIR)/mediatekSUPPORTED_DEVICES := mediatek,mt7981-spim-nor-rfb
endef
TARGET_DEVICES += mt7981-spim-nor-rfb

        由于DUMP未定义,$(call Device/$(if $(DUMP),Dump,Build),$(1))为Device/Build。

2. Device/Build展开如下

define Device/Build$$(eval $$(foreach image,$$(IMAGES), \$$(foreach fs,$$(filter $(TARGET_FILESYSTEMS),$$(FILESYSTEMS)), \$$(call Device/Build/per-device-fs,$$(fs),$$(image),$(1)))))$(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(call Device/Build/initramfs,$(1)))$(call Device/Build/kernel,$(1),$$(filter $(TARGET_FILESYSTEMS),$$(FILESYSTEMS)))$$(eval $$(foreach compile,$$(COMPILE), \$$(call Device/Build/compile,$$(compile),$(1))))$$(eval $$(foreach image,$$(IMAGES), \$$(foreach fs,$$(filter $(TARGET_FILESYSTEMS),$$(FILESYSTEMS)), \$$(call Device/Build/image,$$(fs),$$(image),$(1)))))$$(eval $$(foreach artifact,$$(ARTIFACTS), \$$(call Device/Build/artifact,$$(artifact))))endef

         注意:这里Device/Build/initramfs是关键,内存根文件系统只会执行到这个,Device/Build/initramfs,内容如下:

define split_args
$(foreach data, \$(subst |,$(space),\$(subst $(space),^,$(1))), \$(call $(2),$(strip $(subst ^,$(space),$(data)))))
endefdefine build_cmd
$(if $(Build/$(word 1,$(1))),,$(error Missing Build/$(word 1,$(1))))
$(call Build/$(word 1,$(1)),$(wordlist 2,$(words $(1)),$(1)))endefdefine concat_cmd
$(call split_args,$(1),build_cmd)
endefifndef IB
define Device/Build/initramfs$(call Device/Export,$(KDIR)/tmp/$$(KERNEL_INITRAMFS_IMAGE),$(1))$$(_TARGET): $$(if $$(KERNEL_INITRAMFS),$(BIN_DIR)/$$(KERNEL_INITRAMFS_IMAGE) \$$(if $$(CONFIG_JSON_OVERVIEW_IMAGE_INFO), $(BUILD_DIR)/json_info_files/$$(KERNEL_INITRAMFS_IMAGE).json,))$(KDIR)/$$(KERNEL_INITRAMFS_NAME):: image_prepare$(BIN_DIR)/$$(KERNEL_INITRAMFS_IMAGE): $(KDIR)/tmp/$$(KERNEL_INITRAMFS_IMAGE)cp $$^ $$@$(KDIR)/tmp/$$(KERNEL_INITRAMFS_IMAGE): $(KDIR)/$$(KERNEL_INITRAMFS_NAME) $(CURDIR)/Makefile $$(KERNEL_DEPENDS) image_prepare@rm -f $$@$$(call concat_cmd,$$(KERNEL_INITRAMFS))......
endef
endif

         注意:这里concat_cmd非常重要,lzma压缩,mkits.sh制作its文件以及mkimage打包最终镜像都是这里完成。展开结果命令如下:

        rm -f /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bincp /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/Image-initramfs /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin/home/work/openwrt/staging_dir/host/bin/lzma e /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin -lc1 -lp2 -pb2  /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin.new@mv /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin.new /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin/home/work/openwrt/scripts/mkits.sh -D mt7981-spim-nor-rfb -o /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin.its -k /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin -d /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/image-mt7981-spim-nor-rfb.dtb -C lzma -a 0x48080000 -e 0x48080000  -c "config-1" -A arm64 -v 5.4.203 PATH=/home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/linux-5.4.203/scripts/dtc:/home/work/openwrt/staging_dir/toolchain-aarch64_cortex-a53_gcc-8.4.0_musl/bin:/home/work/openwrt/staging_dir/toolchain-aarch64_cortex-a53_gcc-8.4.0_musl/bin:/home/work/openwrt/staging_dir/toolchain-aarch64_cortex-a53_gcc-8.4.0_musl/bin:/home/work/openwrt/staging_dir/host/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/work/openwrt/staging_dir/toolchain-aarch64_cortex-a53_gcc-8.4.0_musl/bin/ mkimage -f /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin.its /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin.new@mv /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin.new /home/work/openwrt/build_dir/target-aarch64_cortex-a53_musl/linux-mediatek_mt7981/tmp/openwrt-mediatek-mt7981-mt7981-spim-nor-rfb-initramfs-kernel.bin

        $$(eval $$(foreach compile,$$(COMPILE), $$(call Device/Build/compile,$$(compile),$(1))))展开如下:

Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-spim-nor-rfb)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-spim-nand-2500wan-gmac2)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-spim-nand-rfb)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-spim-nand-gsw)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-emmc-rfb)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-sd-rfb)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-snfi-nand-2500wan-p5)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-fpga-spim-nor)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-fpga-snfi-nand)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-fpga-spim-nand)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-fpga-emmc)))
Makefile:91: $(eval $(foreach compile,$(COMPILE), $(call Device/Build/compile,$(compile),mt7981-fpga-sd)))

        由于$(COMPILE)为空,所以这块执行没有效果。

接下来,

$$(eval $$(foreach image,$$(IMAGES), \$$(foreach fs,$$(filter $(TARGET_FILESYSTEMS),$$(FILESYSTEMS)), \$$(call Device/Build/image,$$(fs),$$(image),$(1)))))

        由于TARGET_FILESYSTEMS是要编译的镜像格式类型,如下:

fs-types-$(CONFIG_TARGET_ROOTFS_SQUASHFS) += squashfs
fs-types-$(CONFIG_TARGET_ROOTFS_JFFS2) += $(addprefix jffs2-,$(JFFS2_BLOCKSIZE))
fs-types-$(CONFIG_TARGET_ROOTFS_JFFS2_NAND) += $(addprefix jffs2-nand-,$(NAND_BLOCKSIZE))
fs-types-$(CONFIG_TARGET_ROOTFS_EXT4FS) += ext4
fs-types-$(CONFIG_TARGET_ROOTFS_UBIFS) += ubifs
fs-subtypes-$(CONFIG_TARGET_ROOTFS_JFFS2) += $(addsuffix -raw,$(addprefix jffs2-,$(JFFS2_BLOCKSIZE)))TARGET_FILESYSTEMS := $(fs-types-y)

        由于CONFIG_TARGET_ROOTFS_SQUASHFS等我都没选,所以,TARGET_FILESYSTEMS为空,这里也是不执行的。可以看出Device/Build/image的作用是生成不同文件系统的镜像。

接下来,

$$(eval $$(foreach artifact,$$(ARTIFACTS), \$$(call Device/Build/artifact,$$(artifact))))

        由于ARTIFACTS变量为空,所以,这里Device/Build/artifact什么也不干。

三. 总结

这里需要注意的以下几点:

1. image_prepare有两个目标,有动作的这个目标做的事情很少,没有目标的依赖是用于编译设备树的,要非常注意。

2. 由于编译选项没选,Image/Build/targz,Image/Build/cpiogz这里什么也不做,Image/BuildKernelImage/InstallKernel没有定义(可能是用于自定义的,这里没用到而已),这里什么也不做。

3. $(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(if $(IB),,$(call Image/BuildKernel/Initramfs))),这里结果为$(call Image/BuildKernel/Initramfs),继续展开为$(call Image/Build/Initramfs),但是Image/Build/Initramfs未定义,所以这里什么也不干,也是用于自定义的。

4. $(foreach device,$(TARGET_DEVICES),$(call Device,$(device))),这里TARGET_DEVICES定义在mt7981.mk中,表示不同的镜像(spi-nor,spi-nand,emmc等等),Device宏里面要关注Device/Default和Device/Build,Device/Default定义在target/linux/mediatek/image/Makefile中,定义了一些镜像相关的变量,Device/Build中要关注$(if $(CONFIG_TARGET_ROOTFS_INITRAMFS),$(call Device/Build/initramfs,$(1))),结果是$(call Device/Build/initramfs,$(1)),重点要关注$$(call concat_cmd,$$(KERNEL_INITRAMFS))这里,这里面打包了最终的镜像(lzma压缩,its文件生成,mkimage都在这里执行)。

相关文章:

OpenWrt kernel install分析(2)

一. 前言 接下来分析make -C image compile install TARGET_BUILD。 二. Makefile分析 1. 命令首先运行target/linux/mediatek/image/Makefile,该文件内容如下: target/linux/mediatek/image/Makefile: include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/image.…...

【计算机网络】传输层协议——TCP(下)

文章目录 1. 三次握手三次握手的本质是建立链接,什么是链接?整体过程三次握手过程中报文丢失问题为什么2次握手不可以?为什么要三次握手? 2. 四次挥手整体过程为什么要等待2MSL 3. 流量控制4. 滑动窗口共识滑动窗口的一般情况理解…...

Vue前端页面打印

前端依赖10-插件"print-js": “^1.6.0” 一:简介 print-js 是一个 Vue.js 插件,用于在 Vue.js 项目中实现打印功能。它依赖于 print-js 库,所以需要安装这个库。 能实现以下功能: PDF打印(默认&#xff…...

Visual Studio将C#项目编译成EXE可执行程序

经常看文章时会收获不少实用工具,有的在github上是编译好的,有的则是未编译的项目文件。所以经常会使用Visual Studio编译项目文件成exe可执行程序,以下为编译的流程。 第一步,从github上下载项目文件,举个例子&#…...

git把某一次commit修改过的文件打包导出(git)

1、使用命令把修改的文件打包导出:打包某次commit: git diff-tree -r --no-commit-id --name-only f4710c4a32975904b00609f3145c709f31392140 | xargs tar -rf xxx_1.1.tar 2、使用命令把某次节点后的文件导出: window 下: git diff f4710c4a32975904b00609f3145c709f31392…...

Vue3 Ajax(axios)异步

文章目录 Vue3 Ajax(axios)异步1. 基础1.1 安装Ajax1.2 使用方法1.3 浏览器支持情况 2. GET方法2.1 参数传递2.2 实例 3. POST方法4. 执行多个并发请求5. axios API5.1 传递配置创建请求5.2 请求方法的别名5.3 并发5.4 创建实例5.5 实例方法5.6 请求配置项5.7 响应结构5.8 配置…...

idea2023全量方法debug

为什么要全量debug 刚上手项目或者研读开源项目源码的时候,我们对项目的结构,尤其是功能链路非常陌生,想要debug根本不知道断点打在哪,光靠文件名类名或者方法名去猜也不是个事。这时候只要配置一下全量debug模式,就能…...

Docker镜像解析获取Dockerfile文件

01、概述 当涉及到容器镜像的安全时,特别是在出现镜像投毒引发的安全事件时,追溯镜像的来源和解析Dockerfile文件是应急事件处理的关键步骤。在这篇博客中,我们将探讨如何从镜像解析获取Dockerfile文件,这对容器安全至关重要。 02…...

使用maven命令打jar包

参考:https://blog.csdn.net/qq_27525611/article/details/123487255 https://blog.csdn.net/qq_35860138/article/details/82701919 小伙伴给我的项目自己尝试命令行打包遇到的坑,简单记录下 // 打包(1.8环境下打的,17会报错&…...

【多线程】死锁 详解

死锁 一. 死锁是什么二. 死锁的场景1. 一个线程一把锁2. 两个线程两把锁3. N 个线程 M 把锁 三. 死锁产生的四个必要条件四. 如何避免死锁 一. 死锁是什么 死锁是这样一种情形: 多个线程同时被阻塞,因为每个进程都在等其他线程释放某些资源,…...

成考[专升本政治]科目必背知识点

1. 马克思主义哲学研究的对象是:关于自然、社会、思维发展的一般规律。 2. 对待马克思主义的科学态度是:坚持和发展。 3. 物质的唯一特性是客观实在性。这里的客观实在是指:不以人的意志为转移。 4. 在实际工作中,要注意掌握…...

spring boot 使用AOP+自定义注解+反射实现操作日志记录修改前数据和修改后对比数据,并保存至日志表

一、添加aop starter依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency>二&#xff1a;自定义字段翻译注解。&#xff08;修改功能时&#xff0c;需要显示如…...

【深度学习】Pytorch 系列教程(二):PyTorch数据结构:1、Tensor(张量): GPU加速(GPU Acceleration)

目录 一、前言 二、实验环境 三、PyTorch数据结构 0、分类 1、张量&#xff08;Tensor&#xff09; 1. 维度&#xff08;Dimensions&#xff09; 2. 数据类型&#xff08;Data Types&#xff09; 3. GPU加速&#xff08;GPU Acceleration&#xff09; 一、前言 ChatGP…...

多线程|多进程|高并发网络编程

一.多进程并发服务器 多进程并发服务器是一种经典的服务器架构&#xff0c;它通过创建多个子进程来处理客户端连接&#xff0c;从而实现并发处理多个客户端请求的能力。 概念&#xff1a; 服务器启动时&#xff0c;创建主进程&#xff0c;并绑定监听端口。当有客户端连接请求…...

云计算——ACA学习 云计算分类

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ 目录 写在前面 前期回顾 本期介绍 一.云计算分类 1.公有云…...

3 分钟,带你了解低代码开发

一、低代码平台存在的意义 传统软件开发交付链中&#xff0c;需求经过3次传递&#xff0c;用户→业务→架构师→开发&#xff0c;每一层传递都可能使需求失真&#xff0c;导致最终交付的功能返工。 业务的变化促使软件开发过程不断更新、迭代和演进&#xff0c;而低代码开发即是…...

小白学Unity03-太空漫游游戏脚本,控制飞船移动旋转

首先搭建好太阳系以及飞机的场景 需要用到3个脚本 1.控制飞机移动旋转 2.控制摄像机LookAt朝向飞机和差值平滑跟踪飞机 3.控制各个星球自转以及围绕太阳旋转&#xff08;rotate()和RotateAround()&#xff09; 1.控制飞机移动旋转的脚本 using System.Collections; using…...

接口自动化测试推荐用什么框架?

在推荐接口自动化测试框架时&#xff0c;需要考虑多个因素&#xff0c;包括项目需求、技术栈、团队经验和个人偏好。 以下是几个常用的接口自动化测试框架供你参考&#xff1a; Postman&#xff1a; Postman是一个功能强大且易于上手的接口测试工具&#xff0c;它提供了许多…...

防火墙 FireWall

这里写自定义目录标题 一、概述二、防火墙分类三、防火墙性能四、硬件防火墙定义五、硬件防火墙作用&#xff08;拓扑图 ups&#xff09;六、硬件防火墙品牌七、软件防火墙八、iptables一、iptables是什么&#xff1f;二、netfilter/iptables功能三、iptables概念四、iptables中…...

【Linix-Day12-线程同步和线程安全】

线程同步 和 线程安全 线程同步 除了信号量和互斥锁&#xff08;互斥锁和条件变量上次介绍过&#xff09;&#xff0c;还有两种方式同步 1.读写锁 当同时对一块内存读写时&#xff0c;会出现下列问题&#xff0c;故而引入读写锁 接口介绍&#xff1a; 1.int pthread_rwloc…...

OpenClaw长期运行:Qwen3.5-9B自动化系统的维护与更新

OpenClaw长期运行&#xff1a;Qwen3.5-9B自动化系统的维护与更新 1. 为什么需要长期维护&#xff1f; 去年冬天&#xff0c;我部署了一个基于OpenClaw和Qwen3.5-9B的自动化系统来处理日常的文档整理工作。最初几周运行得很顺利&#xff0c;直到某个凌晨&#xff0c;系统突然停…...

三相桥式整流电路有源逆变状态的研究:基于Matlab仿真的直流发电机电动系统电能流转关系分析

三相桥式整流电路有源逆变状态 Matlab仿真可写报告 直流发电机电动系统入手&#xff0c;研究电能流转关系&#xff0c;再转入变流器分析交流和直流电之间流转&#xff0c;掌握有源逆变条件。玩过直流电机调速的朋友可能遇到过这样的情况&#xff1a;明明在减速状态&#xff0c;…...

swoole方案 实时监控大盘推送中心

业务服务 --写--> Kafka ---> Swoole消费 --WebSocket推--> 浏览器ECharts实时刷新Kafka 当缓冲层&#xff0c;业务打点不管推送快不快&#xff0c;Swoole 从 Kafka 拉数据&#xff0c;有新数据就推给所有看板页面。---代码<?php// composer require longlang/php…...

5分钟掌握ViGEmBus虚拟手柄驱动:Windows游戏控制器模拟终极指南

5分钟掌握ViGEmBus虚拟手柄驱动&#xff1a;Windows游戏控制器模拟终极指南 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 想要在Windows电脑上体验专业级的…...

js06----流程控制

目录 2.4.1、顺序流程控制 2.4.2、分支流程控制 &#xff08;1&#xff09;if分支语句&#xff08;条件判断语句&#xff09; &#xff08;2&#xff09;if....else...语句 需求1&#xff1a; 需求2&#xff1a; &#xff08;3&#xff09;if...else if...else语句&…...

Webots仿真实战:如何用C语言控制四轮小车实现自动行驶

Webots仿真实战&#xff1a;C语言控制四轮小车自动行驶全攻略 引言 在机器人开发领域&#xff0c;仿真环境的重要性不言而喻。它不仅能大幅降低硬件成本&#xff0c;还能加速开发周期&#xff0c;让开发者专注于算法和控制逻辑的优化。Webots作为一款专业的机器人仿真软件&…...

【STM32-HAL库】火焰传感器实战:从原理到智能火灾预警系统搭建(基于STM32F407ZGT6)

1. 火焰传感器原理与选型指南 火焰传感器作为火灾预警系统的"眼睛"&#xff0c;其核心原理是利用光电效应检测火焰特有的光谱特征。我经手过的工业项目中&#xff0c;90%的火灾误报都源于传感器选型不当。市面上常见的火焰传感器主要分为三类&#xff1a; 红外型&…...

探索Comsol在光子晶体光纤SPR - PCF传感器及光学仿真中的奇妙世界

Comsol光子晶体光纤spr pcf传感器comsol光 Comsol光子晶体光纤spr pcf传感器 comsol光学仿真spr。 利用几何相位缺陷态光子晶体实现谷自旋分离在光学领域&#xff0c;光子晶体光纤&#xff08;PCF&#xff09;以及表面等离子体共振&#xff08;SPR&#xff09;相关的研究一直热…...

SEO_从入门到精通,掌握SEO的核心操作步骤

<h2>SEO从入门到精通&#xff0c;掌握SEO的核心操作步骤</h2> <p>在当今的互联网时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;已经成为任何网站或网页希望获得高流量、高曝光的关键技能。无论你是一个初学者&#xff0c;还是已经有一些SEO基础的…...

ChatTTS在政务热线场景落地:拟真语音提升市民服务体验真实案例

ChatTTS在政务热线场景落地&#xff1a;拟真语音提升市民服务体验真实案例 1. 项目背景与价值 政务热线是政府与市民沟通的重要桥梁&#xff0c;但传统语音系统存在明显痛点&#xff1a;机械化的语音播报缺乏人情味&#xff0c;长时间等待的提示音让市民感到烦躁&#xff0c;…...