当前位置: 首页 > 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…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...