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/BuildKernel和Image/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打印(默认ÿ…...

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>二:自定义字段翻译注解。(修改功能时,需要显示如…...

【深度学习】Pytorch 系列教程(二):PyTorch数据结构:1、Tensor(张量): GPU加速(GPU Acceleration)
目录 一、前言 二、实验环境 三、PyTorch数据结构 0、分类 1、张量(Tensor) 1. 维度(Dimensions) 2. 数据类型(Data Types) 3. GPU加速(GPU Acceleration) 一、前言 ChatGP…...

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

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

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

小白学Unity03-太空漫游游戏脚本,控制飞船移动旋转
首先搭建好太阳系以及飞机的场景 需要用到3个脚本 1.控制飞机移动旋转 2.控制摄像机LookAt朝向飞机和差值平滑跟踪飞机 3.控制各个星球自转以及围绕太阳旋转(rotate()和RotateAround()) 1.控制飞机移动旋转的脚本 using System.Collections; using…...

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

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

【Linix-Day12-线程同步和线程安全】
线程同步 和 线程安全 线程同步 除了信号量和互斥锁(互斥锁和条件变量上次介绍过),还有两种方式同步 1.读写锁 当同时对一块内存读写时,会出现下列问题,故而引入读写锁 接口介绍: 1.int pthread_rwloc…...

IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

MySQL 8.0 OCP 英文题库解析(十三)
Oracle 为庆祝 MySQL 30 周年,截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...

Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...

FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...