Makefile 从入门到精通:自动化构建的艺术

引入

在软件开发的世界里,“编译” 是绕不开的环节,但手动编译大型项目时,重复输入编译命令的痛苦,相信每个开发者都深有体会。Makefile 作为自动化构建的基石,能让编译过程“一键完成”,甚至智能判断文件变化,只重新编译修改的部分。本文将从基础到进阶,带你吃透 Makefile 的核心逻辑与实战技巧。

一、基础认知:Make 和 Makefile 是什么?

1.1 核心角色分工

  • make:是一个 命令行 工具,负责解释执行 Makefile 中的规则,判断哪些文件需要编译、如何编译。
  • Makefile:是一个 文本文件 ,定义了 “目标 → 依赖 → 命令” 的规则,描述项目的构建逻辑(哪些文件先编译、哪些后编译)。

类比:make 是“工人”,Makefile 是“施工图纸”,两者配合完成自动化构建。

1.2 为什么需要 Makefile?

想象一个场景:项目有 100 个 .c 文件,每次修改一个文件,都要手动输入 gcc -o app a.c b.c ... z.c,效率极低。而 Makefile 能做到:

  • 自动化:只需 make 命令,自动完成编译、链接。
  • 增量编译:仅重新编译修改过的文件(通过比较文件的**修改时间(Modify Time)**判断)。
  • 可扩展:支持清理、测试、打包等自定义操作(如 make clean)。

1.3 Make的核心工作逻辑

Make的核心任务是**“维护目标的最新状态”**,它判断是否执行命令的依据是:
比较“目标”和“依赖”的“最后修改时间”

  • 如果“目标不存在” → 必须执行命令生成目标;
  • 如果“目标存在,但依赖的修改时间比目标更新” → 必须执行命令更新目标;
  • 如果“目标存在,且依赖没更新(比目标旧)” → 认为执行命令(认为目标已最新)。

二、初体验:单文件项目的 Makefile

2.1 代码示例(myproc.c

#include <stdio.h>
int main() {printf("Hello Makefile!\n");return 0;
}

2.2 最简 Makefile 编写

#  目标    :   依赖
myproc.exe: myproc.c  # 命令gcc -o myproc.exe myproc.c  #(必须以 Tab 开头!)# 清理操作(伪目标)
.PHONY: clean  # 声明 clean 是伪目标
clean:   #依赖可以为空,这就意味着不需要任何依赖rm -f myproc.exe  #(必须以 Tab 开头!)

2.3 关键概念解析

  1. 目标(Target)
    • 可以是 实际文件(如 myproc.exe,需要生成的产物),也可以是 伪目标(如 clean,代表一个动作)。
    • Make 默认执行 第一个目标(这里是 myproc.exe),也可以通过 make clean 显式指定目标。
  2. 依赖(Prerequisites)
    • 生成目标所需的文件(如 myproc.c 是编译 myproc.exe 的依赖)。
    • Make 会比较 目标和依赖的修改时间:如果依赖的修改时间更晚(比如修改了 myproc.c),就会重新执行命令。
  3. 命令(Recipe)
    • 生成目标的具体操作(如 gcc 编译、rm 删除)。
    • 必须以 Tab 开头:这是 Makefile 的语法要求,用空格代替会导致语法错误。
  4. 伪目标(.PHONY)
    • 作用:告诉 Make,clean 不是一个实际文件,而是一个“动作”。
    • 场景:如果当前目录有一个叫 clean 的文件,没有 .PHONY 声明时make clean 会认为“目标已存在,无需执行”;.PHONY 声明时,即使存在 clean 文件,也会执行 rm 命令。

2.4 常见的问题

问题1: 声明.PHONY和不声明的核心区别 ?

关键区别在于:Make是否会检查“目标名是否对应一个实际存在的文件”

我们用同一个clean目标对比:

场景1:不声明.PHONY: clean
# 没有.PHONY声明
clean:rm -f myproc.exe

当一个目标没有被.PHONY声明时,Make会默认把它当作一个“需要生成的文件”,执行以下严格检查:

检查步骤:
  1. 检查“目标是否对应实际文件”
    • 比如目标是clean,Make会先看当前目录有没有叫clean的文件。
  2. 检查“依赖是否比目标更新”
    • 如果目标文件存在,再看它的依赖(如果有)的修改时间是否比目标文件晚。
执行逻辑:

只有满足以下任一条件,才会执行命令:

  • 目标文件不存在
  • 目标文件存在,但依赖的修改时间比目标更新
场景2:声明.PHONY: clean
.PHONY: clean  # 有声明
clean:rm -f myproc.exe

当目标.PHONY声明后,Make会明确:“这不是一个需要生成的文件,而是一个动作”,因此跳过所有“文件相关的检查”

跳过的检查:
  1. 不检查目录中是否存在同名文件(哪怕有clean文件,也假装没看见);
  2. 不比较依赖的修改时间(即使有依赖,也默认“需要执行命令”)。
执行逻辑:

只要你调用make 伪目标(如make clean),就一定会执行下面的命令,无论任何情况。

一句话结论

.PHONY的作用是给目标“去文件化”

  • 不声明:Make把目标当文件,用“存在性+时间戳”判断是否执行命令(可能被同名文件卡住);
  • 声明后:Make把目标当动作,跳过所有文件检查,每次调用必执行命令(永远生效)。

问题2: 为什么make执行时只运行前面的代码,后面的不运行?

因为Make的默认行为是:只执行第一个目标(称为“默认目标”),其他目标需要“显式指定”才会运行。

比如你的Makefile:

# 第一个目标(默认目标)
myproc.exe: myproc.c  gcc -o myproc.exe myproc.c  # 第二个目标(非默认)
.PHONY: clean  
clean:  rm -f myproc  
  • 当你直接输入 make 时,Make只会找第一个目标myproc.exe,执行它的编译命令,后面的clean目标完全不碰。
  • 如果你想运行后面的clean,必须显式指定:make clean(此时才会执行rm命令)。

总结概括

  1. “忽略同名文件”:伪目标的命令是否执行,和有没有同名文件没关系,一定执行。
  2. .PHONY的作用:给目标打“动作标签”,避免被同名文件干扰,保证命令100%执行。
  3. Make默认只跑第一个目标,其他目标需要用make 目标名(如make clean)显式调用。

2.5 实验:理解“增量编译”

  1. 执行 make:生成 myproc.exe,首次编译所有代码。
  2. 修改 myproc.c 后,再次执行 make:仅重新编译 myproc.c(因为它的修改时间比 myproc.exe 新)。
  3. 执行 make clean:删除 myproc.exe,为下次编译做准备。

背后逻辑make 通过比较 文件修改时间(Modify Time) 判断是否需要重新编译。可用 stat myproc.c 查看文件时间戳。

三、深入:编译过程的分解与依赖链

实际编译分为 4 个阶段:预处理(.i)→ 编译(.s)→ 汇编(.o)→ 链接(可执行文件)。我们可以在 Makefile 中分解每个阶段,观察依赖链的递归处理。

3.1 分解编译步骤的 Makefile

#最终目标
myproc.exe:myproc.ogcc myproc.o -o myproc.exe  # 链接阶段# 汇编 → 目标文件myproc.o:myproc.sgcc -c myproc.s -o myproc.o  # 汇编阶段# 编译 → 汇编代码myproc.s:myproc.igcc -S myproc.i -o myproc.s  # 编译阶段# 预处理 → 展开头文件myproc.i:myproc.cgcc -E myproc.c -o myproc.i  # 预处理阶段

在这里插入图片描述

3.2 Make 的依赖解析流程

当执行 make 时,make 会:

  1. 找到第一个目标 myproc.exe,检查它是否存在,或依赖的 myproc.o 是否更新。
  2. myproc.o 不存在,递归查找 myproc.o 的依赖 myproc.s,继续递归直到最底层的 myproc.c
  3. myproc.c 开始,依次执行预处理、编译、汇编、链接,最终生成 myproc.exe

类比:像“剥洋葱”一样,从终极目标层层拆解,直到最基础的源文件,再反向构建。

四、Make 的工作原理:规则与时间戳

4.1 核心机制:文件时间戳比较

每个文件有三个关键时间戳(可通过 stat 命令查看):

  • Modify Time(Mtime):文件内容修改时更新(决定编译是否触发)。

  • Change Time(Ctime):文件属性(如权限)修改时更新。

  • Access Time(Atime):文件被访问时更新(Linux 早期版本会频繁更新,现在默认关闭)。
    在这里插入图片描述
    make 只关注 Mtime:如果目标文件的 Mtime 比依赖的 Mtime 新,就不会进行编译,反观就会执行。

    在这里插入图片描述

4.2 执行流程详解

  1. 找规则:在当前目录找 Makefilemakefile
  2. 定目标:以第一个目标为“终极目标”(如 myproc.exe)。
  3. 查依赖:检查目标是否存在,或依赖的文件 Mtime.exe 是否更新。
  4. 递归处理:若依赖不存在,递归查找依赖的依赖(如 myproc.exemyproc.omyproc.s → … → myproc.c)。
  5. 执行命令:按规则执行命令,生成目标。
  6. 错误处理:依赖缺失直接报错;命令执行失败(如编译出错),默认继续执行后续命令(可通过 .DELETE_ON_ERROR 改变)。

4.3 常见问题:为什么修改了文件,make 没反应?

  • 原因 1:依赖没写对(比如头文件修改了,但 Makefile 没声明头文件为依赖)。
  • 原因 2:文件时间戳没更新(比如通过网络复制文件,Mtime 可能被覆盖)。
  • 解决
    • touch 文件名 强制更新 Mtime。
    • 显式声明头文件依赖(后续会讲自动生成依赖的方法)。

五、扩展语法:高效管理多文件项目

当项目有多个 .c 文件时,手动写每个文件的规则效率极低。利用 变量、模式规则、自动变量 可大幅简化 Makefile。

综合案例:

BIN=NJ.exe
#SRC=$(shell ls *.c)
SRC=$(wildcard *.c) # wildcard函数,获取当前目录下的所有的原文件
OBJ=$(SRC:.c=.o)
CC=gcc
Echo=echo
Rm=rm -rf$(BIN):$(OBJ)@$(CC) -o $@ $^@$(Echo) "linking $^ to $@ ... done"
%.o:%.c@$(CC) -c $<@$(Echo) "compling $< to $@ ... done".PHONY:clean
clean:$(Rm) $(OBJ) $(BIN).PHONY:test
test:@echo "Debug-------"@echo $(SRC);@echo "Debug-------"@echo $(OBJ);@echo "Debug-------"

1、变量定义:给文件/命令起“外号”

BIN=NJ.exe  
#SRC=$(shell ls *.c)  
SRC=$(wildcard *.c)  
OBJ=$(SRC:.c=.o)  
CC=gcc  
Echo=echo  
Rm=rm -rf  
代码行符号/语法解析实际作用
BIN=NJ.exe定义变量 BIN,值为 NJ.exe(最终生成的可执行文件名)。后续用 $(BIN) 代替 NJ.exe,修改文件名只需改这里。
#SRC=$(shell ls *.c)(注释行)使用 shell 函数执行 ls *.c 获取 .c 文件,不推荐(依赖系统 Shell,兼容性差)。被更安全的 wildcard 替代。
SRC=$(wildcard *.c)- wildcard:Make 内置函数,获取当前目录所有 .c 文件(如 a.c b.c)。自动识别所有 .c 文件,新增文件无需修改 Makefile。
OBJ=$(SRC:.c=.o)- 变量替换:把 SRC 中每个字符串的 .c 后缀替换为 .o(如 a.c→a.o)。自动生成目标文件列表(.o),无需手动写 a.o b.o
CC=gcc定义编译器为 gcc(可改为 clang 等,统一修改)。方便切换编译器,避免遍历命令修改。
Echo=echo定义 echo 命令(统一管理输出)。后续用 $(Echo) 代替 echo,修改输出行为更方便。
Rm=rm -rf定义删除命令(带 -rf 参数,强制递归删除)。后续用 $(Rm) 代替 rm -rf,统一控制删除逻辑。

2、链接规则:把 .o 拼成可执行文件

$(BIN):$(OBJ)  @$(CC) -o $@ $^  @$(Echo) "linking $^ to $@ ... done"  
代码行符号/语法解析实际作用
$(BIN):$(OBJ)- 目标:$(BIN)(可执行文件,如 NJ.exe);
- 依赖:$(OBJ)(所有 .o 文件)。
只有当 .o 文件存在且最新时,才会触发链接操作
@$(CC) -o $@ $^- @抑制命令回显(执行时不打印 gcc ...,只显示结果);
- $@:当前规则的目标文件$(BIN),如 NJ.exe);
- $^:当前规则的所有依赖文件$(OBJ),如 a.o b.o)。
调用 gcc,将所有 .o 文件链接成可执行文件(如 gcc -o bite.exe a.o b.o)。
@$(Echo) "linking $^ to $@ ... done"- $^ 替换为 .o 文件列表,$@ 替换为可执行文件名。打印链接完成提示(如 linking a.o b.o to NJ.exe ... done)。

3、模式规则:批量编译 .c→.o

%.o:%.c  @$(CC) -c $<  @$(Echo) "compiling $< to $@ ... done"  
代码行符号/语法解析实际作用
%.o:%.c- %通配符,匹配任意字符串(如 a.o 匹配 a.cb.o 匹配 b.c)。批量处理所有 .c 文件,无需为每个 .c 写单独规则。
@$(CC) -c $<- $<:当前规则的第一个依赖文件(即匹配的 .c 文件,如 a.c);
- -c:只编译,不链接(生成 .o 中间文件)。
调用 gcc,将单个 .c 文件编译.o(如 gcc -c a.c)。
@$(Echo) "compiling $< to $@ ... done"- $< 替换为 .c 文件名,$@ 替换为 .o 文件名。打印编译完成提示(如 compiling a.c to a.o ... done)。

4、伪目标 clean:删除编译产物

.PHONY:clean  
clean:  $(Rm) $(OBJ) $(BIN)  
代码行符号/语法解析实际作用
.PHONY:clean声明 clean伪目标(不是实际文件,而是“动作”)。即使目录有 clean 文件,make clean 仍会执行(否则会因“文件已存在”跳过)。
$(Rm) $(OBJ) $(BIN)- $(Rm)rm -rf$(OBJ) 是所有 .o 文件,$(BIN) 是可执行文件。删除编译中间产物(.o)和最终可执行文件(如 rm -rf a.o b.o NJ.exe)。

5、逐个拆符号:像学“暗号”一样记

1. $(变量名) → “引用外号”
  • 作用:用一个简单的名字代替长内容(类似给文件起外号)。
  • 例子:
    前面定义了 BIN = myprog.exe,后面写 $(BIN) 就等于写 myprog.exe
    比如规则1的目标 $(BIN) 其实就是 myprog.exe
2. $@ → “当前规则的目标”
  • 作用:在命令里代替“当前要生成的文件”(规则中冒号左边的内容)。
  • 例子:
    规则1中,目标是 $(BIN)(也就是 myprog.exe),所以命令里的 $@ 就代表 myprog.exe
    命令 gcc -o $@ $^ 其实就是 gcc -o myprog.exe main.o
3. $^ → “当前规则的所有依赖”
  • 作用:在命令里代替“当前规则中冒号右边的所有文件”。
  • 例子:
    规则1的依赖是 main.o,所以 $^ 就代表 main.o
    (如果依赖有多个,比如 a.o b.o$^ 就代表 a.o b.o
4. $< → “当前规则的第一个依赖”
  • 作用:在命令里代替“当前规则中冒号右边的第一个文件”。
  • 例子:
    规则2的依赖是 main.c(只有一个),所以 $< 就代表 main.c
    命令 gcc -c $< 其实就是 gcc -c main.c
5. % → “通配符(任意名字)”
  • 作用:写“通用规则”,不用为每个文件单独写规则(省事儿)。
  • 例子:
    如果有 a.cb.c 多个源文件,不用写 a.o:a.cb.o:b.c,直接写:
    %.o: %.c  # 意思是:所有的 .o 文件,都由对应的 .c 文件生成gcc -c $<  # $< 会自动换成 a.c、b.c 等
    
    这里的 % 就像“占位符”,a.o 对应 a.cb.o 对应 b.c
6. @ → “命令前加@,不显示命令本身”
  • 作用:让终端只显示命令的结果,不显示命令本身(看起来干净)。
  • 例子:
    规则1里的 @echo "搞定了!",执行时终端只显示 搞定了!
    如果不加 @,会显示 echo "搞定了!" 再显示 搞定了!
7. wildcard → “找文件的工具”
  • 作用:自动找出所有符合条件的文件(比如所有 .c 文件)。
  • 例子:
    SRC = $(wildcard *.c) 意思是“把当前目录下所有 .c 文件的名字都找出来,存到变量 SRC 里”。
    如果有 a.cb.cSRC 就等于 a.c b.c
8. $(变量名:旧后缀=新后缀) → “批量改后缀”
  • 作用:把变量里的文件名批量改后缀(比如 .c 全改成 .o)。
  • 例子:
    已知 SRC = a.c b.c,那么 OBJ = $(SRC:.c=.o) 就会把 a.c 改成 a.ob.c 改成 b.o,所以 OBJ = a.o b.o

6、伪目标 test:调试变量值

.PHONY:test  
test:  @echo "Debug---------"  @echo $(SRC);  @echo "Debug---------"  @echo $(OBJ);  @echo "Debug---------"  
代码行符号/语法解析实际作用
.PHONY:test声明 test 是伪目标。标记为“动作”,确保 make test 必执行。
@echo $(SRC);- @:抑制命令回显;
- $(SRC):输出 .c 文件列表(如 a.c b.c)。
调试:检查 SRC 是否正确识别了所有 .c 文件。
@echo $(OBJ);- $(OBJ):输出 .o 文件列表(如 a.o b.o)。调试:检查 OBJ 是否正确生成了目标文件列表。

核心符号速记表(简易)

符号/语法通俗解释记忆法
$(变量)引用变量(外号)$(BIN) 就是 NJ.exe
wildcard *.c找所有 .c 文件(内置放大镜)ls *.c 但更安全
$(SRC:.c=.o)批量改后缀(.c→.o).c 全换成 .o
%通配符(任意名字)匹配任意文件名,如 a 匹配 a
$@当前规则的目标(要生成的文件)“目标”的拼音首字母
$^当前规则的所有依赖(需要的文件)“所有”的拼音首字母
$<当前规则的第一个依赖(最关键的)“第一个”的拼音首字母
@命令执行命令但不显示命令本身“安静模式”
.PHONY:xxx标记xxx是动作(不是文件)“假目标”,只做事不生成文件

7、为什么这样写?(设计逻辑)

  1. 自动化
    • 通过 wildcard 和模式规则,自动识别所有 .c 文件,新增文件无需修改 Makefile。
  2. 高效性
    • Make 会对比文件修改时间,只重新编译修改过的 .c 文件(增量编译),提升速度。
  3. 可维护性
    • 变量集中定义(如 CCBIN),修改编译器或文件名只需改变量,无需遍历命令。

掌握这些后,这份 Makefile 就像一个 “智能编译管家”:自动找文件、自动编译、自动链接、支持清理和调试,完美适配多文件项目 ✨。

六、进阶实践:多目录与库编译

6.1 多目录项目结构

project/
├── src/      # 源码目录(.c 文件)
├── include/  # 头文件目录(.h 文件)
├── build/    # 中间文件目录(.o、.d 等)
└── Makefile  # 主构建文件

6.2 多目录 Makefile 示例

# 目录变量
SRC_DIR = src
BUILD_DIR = build
INC_DIR = include# 生成文件路径
SRC = $(wildcard $(SRC_DIR)/*.c)
OBJ = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SRC))  # 替换路径
DEP = $(OBJ:.o=.d)# 编译选项(添加头文件路径)
CFLAGS = -I$(INC_DIR) -Wall -g# 创建构建目录(若不存在)
$(shell mkdir -p $(BUILD_DIR))# 模式规则:编译 .c → .o(输出到 build 目录)
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c  $(CC) $(CFLAGS) -c $< -o $@  $(CC) -MM $(CFLAGS) $< > $(@:.o=.d)  # 生成依赖文件# 终极目标
myproc: $(OBJ)  $(CC) $^ -o $@  # 清理(删除 build 目录和可执行文件)
.PHONY: clean  
clean:  $(RM) -r $(BUILD_DIR) myproc  # 包含依赖文件
-include $(DEP)  

6.3 静态库与动态库编译

# 生成静态库(libmylib.a)
libmylib.a: $(OBJ)  ar rcs $@ $^  # 生成动态库(libmylib.so)
libmylib.so: $(OBJ)  gcc -shared -o $@ $^  # 链接库(示例)
myproc: $(OBJ) libmylib.a  $(CC) $^ -L. -lmylib -o $@  

七、避坑指南:常见错误与解决

7.1 语法错误:Tab 键问题

  • 错误:命令行前用了空格(而非 Tab),make 会报错:Makefile:xx: *** missing separator. Stop.
  • 解决:确保所有命令行以 Tab 开头(编辑器可设置“将空格转换为 Tab”)。

7.2 依赖遗漏:头文件没声明

  • 现象:修改头文件后,make 不重新编译。
  • 解决:用 gcc -MM 自动生成依赖(见 5.4 节)。

7.3 伪目标未声明

  • 现象:若存在名为 clean 的文件,make clean 会提示“clean 已是最新”。
  • 解决:必须用 .PHONY: clean 声明伪目标。

7.4 变量作用域问题

  • 问题A = helloB = $(A) worldA = hiB 会变成 hi world(递归展开)。
  • 解决:用 := 定义“简单展开变量”:A := helloB := $(A) worldA 后续修改不影响 B

八、工具链扩展:Make 与 CMake、Autotools

  • Makefile:适合小型、Linux 专属项目,灵活但语法复杂。
  • CMake:跨平台(生成 Makefile、Visual Studio 工程等),语法更简洁,适合大型项目。
  • Autotools:生成可移植的 configure 脚本,适合开源项目(如 GNU 软件)。

选择建议

  • 快速迭代的小项目 → 直接写 Makefile。
  • 跨平台或复杂项目 → 用 CMake。
  • 开源项目需高度可配置 → 用 Autotools。

结语:掌握 Makefile,解放生产力

Makefile 是 Linux 下自动化构建的“基石”,从单文件到多目录项目,从简单规则到复杂依赖,它都能高效应对。学习时,建议:

  1. 从简到繁:先写单文件示例,再扩展多文件、多目录。
  2. 善用工具:用 make -n 预览命令,make -d 调试依赖。
  3. 拥抱实践:遇到问题时,通过 touch 修改文件时间、故意写错误规则,观察 make 的反应。

掌握 Makefile 后,你会发现编译不再是负担,而是一种“一键启动”的享受。让自动化成为你的生产力工具,把精力聚焦在更有价值的代码逻辑上吧!

(欢迎在评论区分享你的 Makefile 踩坑经历或优化技巧 😊)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/94065.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/94065.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

利用DeepSeek将Rust程序的缓冲输出改写为C语言实现提高输出效率

在前面多语言测试中&#xff0c;遇到一个难以置信的问题&#xff0c;rust的输出到文件比c语言还快&#xff0c;这是不合情理的&#xff0c;通过对两者输出语句的比较&#xff0c;发现了不同。 rust程序在输出到stdout前有这么一句 let mut writer BufWriter::with_capacity(6…

Java Optional 类教程详解

一、Optional 类核心定位Optional 是 Java 8 引入的函数式容器类&#xff08;java.util.Optional&#xff09;&#xff0c;专为​​显式空值处理​​设计。其核心价值在于&#xff1a;消除 60% 以上的传统 null 检查代码通过类型系统强制空值声明&#xff0c;降低 NPE 风险支持…

Agent X MCP 把想法编译成现实

多模态GUI智能体协作型AI魔搭社区MCPMCP 硬件

cv快速input

效果<view class"miniWhether-box-lss"><view class"content-inp-text">快递单号</view><input class"content-inp-input" type"text"v-model"expressInfo.expressNo" placeholder"填写快递单号&…

[AI8051U入门第十二步]W5500-Modbus TCP从机

学习目标: 1、了解Modbus Tcp协议 2、学习Modbus Tcp 从机程序驱动 3、使用 Modbus Pull调试一、Modbus TCP介绍? Modbus TCP 是一种基于 TCP/IP 网络的工业通信协议,是 Modbus 协议家族中的一员,专门为以太网环境设计。它是 Modbus RTU(串行通信)协议的扩展,将 Modbus…

Python编程基础与实践:Python循环结构基础

循环结构 学习目标 通过本课程的学习&#xff0c;学员可以掌握Python中for循环和while循环的基本使用方法&#xff0c;了解如何利用循环结构来重复执行代码块&#xff0c;以及如何使用break和continue语句来控制循环的执行流程。 相关知识点 循环结构 学习内容 1 循环结构 1.1 …

趣谈设计模式之模板方法模式-老板,你的数字咖啡制作好了,请享用!

模板方法模式 定义了一套算法的骨架&#xff0c;讲某些具体的步骤延迟到子类中实现。 主要用于不改变算法结构的情况下重新定义算法的某些步骤&#xff0c;以适应新的需求。 模板方法的角色 抽象类&#xff1a; 作为算法的骨架&#xff0c;该抽象类中包含了算法的核心部分和…

技术栈:基于Java语言的搭子_搭子社交_圈子_圈子社交_搭子小程序_搭子APP平台

一、市场背景1、社会发展与生活方式转变城市化进程加快&#xff1a;随着城市化不断推进&#xff0c;大量人口涌入城市&#xff0c;人们生活的物理空间距离拉近了&#xff0c;但人际关系却在一定程度上变得疏离。传统的基于血缘、地缘建立起的紧密社交关系难以满足城市生活中的多…

字典在VBA与VB.NET的区别,举例说明

简述&#xff1a;在VBA中&#xff0c;字典通常使用Scripting.Dictionary对象&#xff0c;通过CreateObject("Scripting.Dictionary")创建。它需要引用Microsoft Scripting Runtime库&#xff08;scrrun.dll&#xff09;。VBA字典的方法包括Exists、Add、Remove等&…

2024年网络安全案例

以下是2024年造成严重损失的网络安全典型案例&#xff0c;涵盖市政系统、金融交易、区块链平台、国家级攻击及全球性IT故障五大领域&#xff0c;按损失规模和技术危害性综合排序&#xff1a;---一、市政基础设施攻击 1. 加拿大汉密尔顿市勒索软件事件 - 损失&#xff1a;183…

PINN+贝叶斯:深度学习中的魔改新思路

2025深度学习发论文&模型涨点之——PINN贝叶斯PINN通过将物理定律&#xff08;如偏微分方程PDEs&#xff09;嵌入神经网络的损失函数中&#xff0c;使得模型能够利用已知的物理规律来指导学习过程&#xff0c;从而在数据有限或噪声较多的情况下实现更高的准确性。然而&…

零基础-动手学深度学习-8.3. 语言模型和数据集

很至关重要的一章: 8.3.1. 学习语言模型 8.3.2. 马尔可夫模型与n元语法 n元语法看的序列长度是固定的&#xff0c; 存储的序列长是有限且可控的&#xff0c;使用统计方法的时候通常使用这个模型&#xff01;&#xff01;&#xff01;统计方法&#xff01;&#xff01;&#x…

C++ 模板初阶

什么是模板&#xff1f; 模板&#xff08;Template&#xff09;是 C 中实现泛型编程的核心工具。它允许我们编写与具体数据类型无关的代码&#xff0c;从而实现代码复用和类型安全。为什么需要模板&#xff1f; 举个生活中的例子&#xff1a;如果你要造一个能装水的杯子&#x…

DockerFile文件执行docker bulid自动构建镜像

文章目录一、Dockerfile介绍二、Dockerfile镜像制作和流程使用三、Dockerfile文件的制作镜像的分层结构四、Dockerfile文件格式五、Dockerfile相关指令5.1 FROML&#xff1a;指定基础镜像5.2 LABEL&#xff1a;指定镜像元数据5.3 RUN&#xff1a;执行shell指令5.4 ENV&#xff…

osloader!DoGlobalInitialization函数分析之HW_CURSOR--NTLDR源代码分析之设置光标

第一部分&#xff1a; VOID DoGlobalInitialization(IN PBOOT_CONTEXT BootContextRecord){//// Turn the cursor off//HW_CURSOR(0,127);D:\srv03rtm\base\boot/inc/bldrx86.h:258:#define HW_CURSOR (*ExternalServicesTable->HardwareCursor)第二部分&#xff…

Elasticsearch 索引及节点级别增删改查技术

以下是针对 Elasticsearch 索引及节点级别增删改查技术做的简短总结&#xff1a; 一、索引操作创建索引 功能&#xff1a;指定分片、副本数及映射规则[2][4]。示例&#xff1a;PUT /<index_name>​&#xff0c;可定义 settings&#xff08;如分片数&#xff09;和 mappin…

烽火HG680-KD_海思MV320处理器-安卓9-原厂系统升级包-针对解决烧录不进系统的问题

烽火HG680-KD_海思MV320处理器-安卓9-原厂系统升级包&#xff08;注意是&#xff08;原机系统&#xff09;&#xff09;-主要是针对解决TTL烧录后仍然不进系统使用。HG680-KD&#xff0f;HG680-KE&#xff0f;HG680-KF&#xff0f;HG680-KX 均通用。 说明&#xff1a; 前一个…

VS2019安装HoloLens 没有设备选项

第一步先检查VS有没有安装C组件第二步把VS工程最后一个设置为启动项

【云计算】云主机的亲和性策略(二):集群节点组

《云主机的亲和性策略》系列&#xff0c;共包含以下文章&#xff1a; 1️⃣ 云主机的亲和性策略&#xff08;一&#xff09;&#xff1a;快乐旅行团2️⃣ 云主机的亲和性策略&#xff08;二&#xff09;&#xff1a;集群节点组3️⃣ 云主机的亲和性策略&#xff08;三&#xf…

【人工智能】AI代理在零售业的崛起:从草莓订购到全流程购物体验

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在零售业快速演变的格局中,AI代理正作为变革力量崛起,连接消费者需求与无缝履行。本文深入探讨AI代理在零售中的兴起,从通过对话界面订购…