Makefile从入门到上手

news2024/11/22 9:29:49

文章目录

  • 前言
  • 一、Makefile 介绍
  • 二、示例源码
    • 1、hello.c
    • 2、add.c
    • 3、sub.c
    • 4、mul.c
    • 5、div.c
    • 6、head.h
  • 三、Makefile 基础规则
    • 1、一个规则
    • 2、两个函数和 clean
      • ①、2 个函数:
      • ②、clean
    • 3、三个自动变量和模式规则
      • ①、三个自动变量
      • ②、模式规则
        • <1>、模式规则
        • <2>、静态模式规则
    • 4、伪目标
    • 5、编译时的参数
    • 6、make 的参数
  • 四、工程源码优化
  • 五、Makefile 语法
    • 1、两种变量
    • 2、赋值方法
      • ①、+=(附加) 使用案例
      • ②、?= 使用案例
  • 六、Makefile 函数
    • 1、foreach 函数
    • 2、filter 和 filter-out 函数
    • 3、patsubst


前言

makefile 关系到了整个工程的编译规则。一个工程中的源文件不计其数,并且按类型、功能、模块分别放在若干个目录中,makefile 定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile 就像一个 Shell 脚本一样,其中也可以执行操作系统的命令。

本文记录了 Makefile 的使用。


一、Makefile 介绍

Makefile 是一个名为 GNU-Make 软件所需要的脚本文件,该脚本文件可以指导 Make 软件控制 arm-gcc 等工具链去编译工程文件最终得到可执行文件,几乎所有的 Linux 发行版都内置了 GNU-Make 软件,VScode 等多种 IDE 也内置了 Make 程序。说白了,Makefile 就是用来管理项目的。

你见到的 xxx.mk 文件或者 Makefile 都统称为 Makefile 脚本文件。

命名只能为 makefile 或者是 Makefile,因为只有这两种命名方式才能被 make 命令识别。

Makefile 脚本文件的语法学习可以参考:跟我一起写Makefile 陈皓

二、示例源码

这里放出供下面 Makefile 基础规则中用来测试的源码。

1、hello.c

#include <stdio.h>
#include "head.h"

int main(int argc, char *argv[])
{
    int a = 10; int b = 5;

    printf("%d+%d=%d\n", a, b, add(a, b));
    printf("%d-%d=%d\n", a, b, sub(a, b));
    printf("%d/%d=%d\n", a, b, div(a, b));
    printf("%dx%d=%d\n", a, b, mul(a, b));

	return 0;
}

2、add.c

int add(int a, int b)
{
	return a+b;
}

3、sub.c

int sub(int a, int b)
{
	return a-b;
}

4、mul.c

int mul(int a, int b)
{
	return a*b;
}

5、div.c

int div(int a, int b)
{
	return a/b;
}

6、head.h

#ifndef _HEAD_H_
#define _HEAD_H_

int add(int , int );
int sub(int , int );
int div(int , int );
int mul(int , int );

#endif

三、Makefile 基础规则

想要掌握 makefile,首先需要了解两个概念,⼀个是目标(target),另⼀个就是依赖(dependency)。目标就是指要干什么,或说运行 make 后生成什么,而依赖是告诉 make 如何去做以实现目标。在 Makefile 中,目标和依赖是通过规则(rule)来表达的。

makefile 的依赖是从上至下的,换句话说就是目标文件是第一句里的目标, 如果不满足执行依赖,就会继续向下执行。如果满足了生成目标的依赖,就不会再继续向下执行了。make 会自动寻找规则里需要的材料文件,执行规则下面的行为生成规则中的目标。

Makefile 三要素:
在这里插入图片描述
工作原理:
在这里插入图片描述
在这里插入图片描述

1、一个规则

1个规则

目标:依赖条件
(一个 tab 缩进)命令

①、目标的时间必须晚于依赖条件的时间,否则,更新目标。
②、依赖条件如果不存在,找寻新的规则去产生依赖条件。

下面来一步一步升级 makefile

利用上述代码实现第一个版本的 Makefile

Makefile 第一版

a.out : hello.c add.c sub.c mul.c div.c
	gcc hello.c add.c sub.c mul.c div.c -o a.out -I ./

执行 make :
在这里插入图片描述
此时,修改 add.c 为下面

add.c

int add(int a, int b)
{
	return a+b+1;
}

此时,再使用 make,发现了问题
在这里插入图片描述
可以看到,只修改 add.c,但是编译的时候,其他.c 文件也重新编译了,这不太科学。明明只改了一个,全部都重新编译了。

于是将 makefile 改写如下:

Makefile 第二版

a.out : hello.o add.o sub.o mul.o div.o
	gcc hello.o add.o sub.o mul.o div.o -o a.out 

hello.o : hello.c
	gcc -c hello.c -o hello.o -I ./

add.o : add.c
	gcc -c add.c -o add.o

sub.o : sub.c
	gcc -c sub.c -o sub.o

mul.o : mul.c
	gcc -c mul.c -o mul.o

div.o : div.c
	gcc -c div.c -o div.o

执行 make 指令如下:
在这里插入图片描述
此时,再将 add.c 改为最开始的代码:

add.c

int add(int a, int b)
{
	return a+b;
}

执行 make 指令如下:
在这里插入图片描述
可以看到,只重新编译了修改过的 add.c 和最终目标

makefile 检测原理:修改文件后,文件的修改时间发生变化,会出现目标文件的时间早于作为依赖材料的时间,出现这种情况的文件会重新编译。修改 add.c 后, add.o 的时间就早于 add.c , a.out 的时间也早于 add.o 的时间了,于是重新编译这俩文件了。

关于 makefile 指定目标问题,先修改 makefile 如下:

Makefile 第三版

hello.o : hello.c
	gcc -c hello.c -o hello.o -I ./

add.o : add.c
	gcc -c add.c -o add.o

sub.o : sub.c
	gcc -c sub.c -o sub.o

mul.o : mul.c
	gcc -c mul.c -o mul.o

div.o : div.c
	gcc -c div.c -o div.o

a.out : hello.o add.o sub.o mul.o div.o
	gcc hello.o add.o sub.o mul.o div.o -o a.out 

只是将 a.out 放在了文件末尾
执行 make,如下:
在这里插入图片描述
这是因为, makefile 默认第一个目标文件为终极目标,生成就跑路,这时候可以用 ALL 来指定终极目标。

ALL:指定 makefile 的终极目标。

指定目标的 makefile 如下:

Makefile 第四版

ALL : a.out

hello.o : hello.c
	gcc -c hello.c -o hello.o -I ./

add.o : add.c
	gcc -c add.c -o add.o

sub.o : sub.c
	gcc -c sub.c -o sub.o

mul.o : mul.c
	gcc -c mul.c -o mul.o

div.o : div.c
	gcc -c div.c -o div.o

a.out : hello.o add.o sub.o mul.o div.o
	gcc hello.o add.o sub.o mul.o div.o -o a.out

执行:
在这里插入图片描述

2、两个函数和 clean

①、2 个函数:

找到当前目录下所有后缀为 .c 的文件,赋值给 src

src = $(wildcard ./*.c) # 匹配当前工作目录下的所有.c 文件。将文件名组成列表,赋值给变量 src。 src = add.c sub.c mul.c div1.c

把 src 变量所有后缀为 .c 的文件替换成 .o

obj = $(patsubst %.c, %.o, $(src)) # 将参数 3 中,包含参数 1 的部分,替换为参数 2。 obj = add.o sub.o mul.c div1.o

用这两个函数修改 makefile 如下:

Makefile 第五版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c

obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o

ALL : a.out

hello.o : hello.c
	gcc -c hello.c -o hello.o -I ./

add.o : add.c
	gcc -c add.c -o add.o

sub.o : sub.c
	gcc -c sub.c -o sub.o

mul.o : mul.c
	gcc -c mul.c -o mul.o

div.o : div.c
	gcc -c div.c -o div.o

a.out : $(obj)
	gcc $(obj) -o a.out

执行 make 指令,如下所示:
在这里插入图片描述

②、clean

-rm -rf $(obj) a.out # “-” :作用是,删除不存在文件时,不报错。顺序执行结束。

每次要删除 .o 文件,很恶心,于是改写 makefile 如下:
加了 clean 部分

Makefile 第六版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c

obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o

ALL : a.out

hello.o : hello.c
	gcc -c hello.c -o hello.o -I ./

add.o : add.c
	gcc -c add.c -o add.o

sub.o : sub.c
	gcc -c sub.c -o sub.o

mul.o : mul.c
	gcc -c mul.c -o mul.o

div.o : div.c
	gcc -c div.c -o div.o

a.out : $(obj)
	gcc $(obj) -o a.out 

clean :
	-rm -rf $(obj) a.out

rm 前面的 - ,代表出错依然执行。比如,待删除文件集合是 5 个,已经手动删除了 1 个,就只剩下 4 个,然而删除命令里面还是 5 个的集合,就会有删除不存在文件的问题,不加这 - ,就会报错,告诉你有一个文件找不到。加了-就不会因为这个报错。

执行 make
在这里插入图片描述
由于没有文件变动, a.out 的时间戳晚于所有依赖文件,这里 make 就没干活

于是,执行时加新指令,先模拟执行 clean 部分:
在这里插入图片描述
确定没有问题,执行
在这里插入图片描述

3、三个自动变量和模式规则

①、三个自动变量

$@	# 在规则的命令中,表示规则中的目标。
$^	# 在规则的命令中,表示所有依赖条件。组成一个列表,以空格隔开,如果这个列表中有重复项,则去重
$<	# 在规则的命令中,表示第一个依赖条件。如果将该变量应用在模式规则中,它可将依赖条件列表中的依赖依次取出,套用模式规则。

用自动变量修改 makefile,如下:

Makefile 第七版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c

obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o

ALL : a.out

hello.o : hello.c
	gcc -c $< -o $@ -I ./

add.o : add.c
	gcc -c $< -o $@

sub.o : sub.c
	gcc -c $< -o $@

mul.o : mul.c
	gcc -c $< -o $@

div.o : div.c
	gcc -c $< -o $@

a.out : $(obj)
	gcc $^ -o $@

clean :
	-rm -rf $(obj) a.out

sub, add 这些指令中使用 $< 和 $^ 都能达到效果,但是为了模式规则,所以使用的 $<
执行 make,如下:
在这里插入图片描述
再来,**上面这个 makefile,可扩展性不行。**比如,要添加一个平方函数,就需要在 makefile 里面增加平方函数的部分。不科学, 所以,模式规则就来了

②、模式规则

<1>、模式规则

%.o : %.c
	gcc -c $< -o %@

修改 makefile,如下:

Makefile 第八版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c

obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o

ALL : a.out

%.o : %.c
	gcc -c $< -o $@

a.out : $(obj)
	gcc $^ -o $@

clean :
	-rm -rf $(obj) a.out

执行 make,如下:
在这里插入图片描述
这时,增加一个 square 函数, 并添加 square.c 文件如下:

square.c

int suqare(int a)
{
    return a*a;
}

head.h 做如下修改:
head.h

#ifndef _HEAD_H_
#define _HEAD_H_

int add(int , int );
int sub(int , int );
int div(int , int );
int mul(int , int );
int square(int );

#endif

hello.c 做如下修改:
hello.c

#include <stdio.h>
#include "head.h"

int main(int argc, char *argv[])
{
    int a = 10; int b = 5;

    printf("%d+%d=%d\n", a, b, add(a, b));
    printf("%d-%d=%d\n", a, b, sub(a, b));
    printf("%d/%d=%d\n", a, b, div(a, b));
    printf("%dx%d=%d\n", a, b, mul(a, b));
    printf("%d*%d=%d\n", a, a, mul(a, a));

	return 0;
}

直接执行 make:
在这里插入图片描述
增加函数的时候,不用改 makefile,只需要增加.c 文件,改一下源码,就行。很强势。

<2>、静态模式规则

继续优化 makefile,使用静态模式规则,就是指定模式规则给谁用,这里指定模式规则给 obj 用,以后文件多了,文件集合会有很多个,就需要指定哪个文件集合用什么规则

$(obj) : %.o : %.c
	gcc -c $< -o %@

修改后 makefile 如下:

Makefile 第八版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c

obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o

ALL : a.out

$(obj) : %.o : %.c
	gcc -c $< -o $@

a.out : $(obj)
	gcc $^ -o $@

clean :
	-rm -rf $(obj) a.out

运行如下:
在这里插入图片描述

4、伪目标

.PHONY: clean ALL

再来一个扩展,当前文件夹下有 ALL 文件或者 clean 文件时,会导致 makefile 瘫痪,如下所示, make clean 没有工作
在这里插入图片描述
用伪目标来解决, 添加一行 .PHONY: clean ALL

makefile 如下所示:

Makefile 第九版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c

obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o

ALL : a.out

$(obj) : %.o : %.c
	gcc -c $< -o $@

a.out : $(obj)
	gcc $^ -o $@

clean :
	-rm -rf $(obj) a.out

.PHONY : clean ALL

再来执行 make clean,就不会受到干扰了
在这里插入图片描述

5、编译时的参数

还有一个扩展就是,编译时的参数, -g,-Wall 这些,可以放在 makefile 里面
修改后 makefile 如下:

Makefile 第十版

src = $(wildcard *.c) # hello.c add.c sub.c mul.c  div.c

obj = $(patsubst %.c, %.o, $(src)) # hello.o add.o sub.o mul.o div.o

myArgs = -Wall -g

ALL : a.out

$(obj) : %.o : %.c
	gcc -c $< -o $@ $(myArgs)

a.out : $(obj)
	gcc $^ -o $@ $(myArgs)

clean :
	-rm -rf $(obj) a.out

.PHONY : clean ALL

执行 make,如下:
在这里插入图片描述

6、make 的参数

参数:

  • -n:模拟执行 make、 make clean 命令。
  • -f:指定文件执行 make 命令。 xxxx.mk

如果 makefile 的名字变化一下,比如,叫 m6
用 m6 执行 makefile, make -f m6
用 m6 执行 clean make -f m6 clean

四、工程源码优化

将上述 .c 文件都放到 src 目录中,.h 文件都放在 inc 目录中,所生成的 .o 文件产物都放在 obj 目录中
在这里插入图片描述
使用 tree 命令查看树形结构拓扑
在这里插入图片描述
修改 makefile 如下,主要是注意 % 的匹配理解,只匹配文件名,目录位置要手动添加

Makefile 第十一版

src = $(wildcard ./src/*.c) # ./src/hello.c ./src/add.c ...

obj = $(patsubst ./src/%.c, ./obj/%.o, $(src)) # ./obj/hello.o ./obj/add.o ...

inc_path = ./inc

myArgs = -Wall -g

ALL : a.out

$(obj) : ./obj/%.o : ./src/%.c
	gcc -c $< -o $@ $(myArgs) -I $(inc_path)

a.out : $(obj)
	gcc $^ -o $@ $(myArgs)

clean :
	-rm -rf $(obj) a.out

.PHONY : clean ALL

执行 make 和 make clean,效果如下
在这里插入图片描述
如果 makefile 的名字变化一下,比如,叫 m6

用 m6 执行 makefile, make -f m6
用 m6 执行 clean make -f m6 clean
在这里插入图片描述

五、Makefile 语法

1、两种变量

在 Makefile 中有两种变量,一种称为即时变量(简单变量),另一种称为延时变量

  • 即时变量(简单变量)
    • A := xxx # A 的值即刻确定,在定义时即确定
  • 延时变量
    • B = xxx # B 的值使用到时才确定

编写下面一个 Makefile

A := abc
B = 123

all :
	@echo $(A)
	@echo $(B)

执行 make
在这里插入图片描述
从上面我们看不出即时变量和延时变量的差别,我们再对 Makefile 进行如下修改:

A := $(C)
B = $(C)
C = abc

all :
	@echo A = $(A)
	@echo B = $(B)

执行 make
在这里插入图片描述
可以看到 A 的值为空,B 的值为 abc,因为 A 为即时变量,在定义时即确定,所以为空

修改 Makefile 将 C 的赋值放在最后:

A := $(C)
B = $(C)
#C = abc

all :
	@echo A = $(A)
	@echo B = $(B)

C = abc

执行 make,可以发现结果并不受影响
在这里插入图片描述
因为当我们执行 make 的时候,会把 Makefile 整个文件读进来进行分析,然后解析里面的变量,所以变量 C 的赋值放在哪里并不受影响

2、赋值方法

:=		# 即时变量
= 		# 延时变量
?= 		# 延时变量,如果是第 1 次定义才起效,如果在前面该变量已定义则忽略这句
+= 		# 附加,他是即时变量还是延时变量取决于前面的定义

①、+=(附加) 使用案例

如下 Makefile

A := $(C)
B = $(C)
C = 123

all :
	@echo A = $(A)
	@echo B = $(B)

C += abc

执行 make
在这里插入图片描述

②、?= 使用案例

修改 Makefile 如下:

A := $(C)
B = $(C)
C = 123

D = 777
D ?= 888

all :
	@echo A = $(A)
	@echo B = $(B)
	@echo D = $(D)

C += abc

执行 make
在这里插入图片描述

六、Makefile 函数

函数调用,很像变量的使用,也是以 $ 来标识的,其语法如下:

$(<function> <arguments>)

或是:

${<function> <arguments>}

这里, 就是函数名,make支持的函数不多。 为函数的参数,参数间以逗号 , 分隔,而函数名和参数之间以“空格”分隔。函数调用以 $ 开头,以圆括号或花括号把函数名和参数括起。

1、foreach 函数

foreach 函数和别的函数非常的不一样。因为这个函数是用来做循环用的,Makefile 中的 foreach 函数几乎是仿照于 Unix 标准 Shell(/bin/sh)中的 for 语句,或是 C-Shell(/bin/csh)中的 foreach 语句而构建的。它的语法是:

$(foreach <var>,<list>,<text>)

这个函数的意思是,把参数 <list> 中的单词逐一取出放到参数 <var> 所指定的变量中,然后再执行 <text> 所包含的表达式。每一次 <text> 会返回一个字符串,循环过程中, <text> 的所返回的每个字符串会以空格分隔,最后当整个循环结束时, <text> 所返回的每个字符串所组成的整个字符串(以空格分隔)将会是 foreach 函数的返回值。

所以, <var> 最好是一个变量名, <list> 可以是一个表达式,而 <text> 中一般会使用 <var> 这个参数来依次枚举 <list> 中的单词。举个例子:
如下 Makefile

names := a b c d

files := $(foreach n,$(names),$(n).o)

ALL:
	@echo $(files)

执行 make
在这里插入图片描述
上面的例子中, $(name) 中的单词会被挨个取出,并存到变量 n 中, $(n).o 每次根据 $(n) 计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以, $(files) 的值是 a.o b.o c.o d.o 。

注意,foreach中的 <var> 参数是一个临时的局部变量,foreach函数执行完后,参数 <var> 的变量将不在作用,其作用域只在 foreach 函数当中。

2、filter 和 filter-out 函数

$(filter <pattern...>,<text>)
  • 名称:过滤函数
  • 功能:以 <pattern> 模式过滤 <text> 字符串中的单词,保留符合模式 <pattern> 的单词。可以有多个模式。
  • 返回:返回符合模式 <pattern> 的字串。
$(filter-out <pattern...>,<text>)
  • 名称:反过滤函数
  • 功能:以 <pattern> 模式过滤 <text> 字符串中的单词,去除符合模式 <pattern> 的单词。可以有多个模式。
  • 返回:返回不符合模式 <pattern> 的字串。

示例 Makefile 如下:

C = a b b d/

D = $(filter %/, $(C))
E = $(filter-out %/, $(C))

ALL:
	@echo D = $(D)
	@echo E = $(E)

执行 make
在这里插入图片描述

3、patsubst

$(patsubst <pattern>,<replacement>,<text>)
  • 名称:模式字符串替换函数。
  • 功能:查找 <text> 中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式 <pattern> ,如果匹配的话,则以 <replacement> 替换。这里, <pattern> 可以包括通配符 % ,表示任意长度的字串。如果 <replacement> 中也包含 % ,那么, <replacement> 中的这个 % 将是 <pattern> 中的那个 % 所代表的字串。(可以用 \ 来转义,以 % 来表示真实含义的 % 字符)
  • 返回:函数返回被替换过后的字符串。
  • 示例:$(patsubst %.c,%.o,x.c.c bar.c),把字串 x.c.c bar.c 符合模式 %.c 的单词替换成 %.o ,返回结果是 x.c.o bar.o

我的qq:2442391036,欢迎交流!


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

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

相关文章

ARM【day2】

思维导图&#xff1a; 作业1&#xff1a; 作业2&#xff1a;

每日一题——圆圈中最后剩下的数字(约瑟夫环问题)

圆圈中最后剩下的数字&#xff08;约瑟夫环问题&#xff09; 题目链接 约瑟夫环 这是一道典型的约瑟夫环问题&#xff0c;而约瑟夫问题的一般形式是这样的&#xff1a; 约瑟夫问题是个有名的问题&#xff1a;N个人围成一圈&#xff0c;从第一个开始报数&#xff0c;第M个将被…

目前最流行的GenAI框架、工具和服务初创公司一览表

目前最流行的GenAI框架、工具和服务初创公司一览表 框架与相关技术&#xff08;Frameworks & Technologies) LangChain BerriAl Outerbounds DUST Llamalndex Pinecone chroma{eature{orm LanceDB activeloop drant Baseplate beam agenta pyq Meru griptape BentoML pyq 数…

实验二十八、三角波发生电路参数的确认

一、题目 利用 Multisim 确定图1所示电路中各元件的参数&#xff0c;使输出电压的频率为 500 Hz 500\,\textrm{Hz} 500Hz、幅值为 6 V 6\,\textrm{V} 6V 的三角波。 图 1 三角波发生电路 图1\,\,三角波发生电路 图1三角波发生电路 2、仿真电路 A 1 \textrm A_1 A1​ 采用…

qtcreator编译报错cannot find -lGL

编译报错cannot find -lGL 是因为找不到openGL的库。 打开终端&#xff0c;输入”locate libGL.so”查找系统中是否有openGL的库&#xff0c;没有的话先安装&#xff0c;有的话可以看到&#xff1a; #locate libGL.so 或 #find / -name libGL.so 系统中存在openGL库&#xff0…

黑马项目一阶段面试 项目介绍篇

我完成了一个外卖项目&#xff0c;名叫苍穹外卖&#xff0c;是跟着黑马程序员的课程来自己动手写的。 项目基本实现了外卖客户端、商家端的后端完整业务。 商家端分为员工管理、文件上传、菜品管理、分类管理、套餐管理、店铺营业状态、订单下单派送等的管理、数据统计等&…

提升车间生产效率,这些做法很关键!

生产效率是制造生产企业的重要属性&#xff0c;对于影响生产效率的问题点&#xff0c;应当引起重视并规避&#xff0c;积极协调资源去改善&#xff0c;让企业能够有序、有章地运行。 一、影响生产效率的因素 1、产品加工工艺变更频繁 产品的加工工艺标准应在一段时间内不变…

小说网站第二章-关于文章的上传的实现

简述 因为最近比较忙&#xff0c;所以只有时间把以前的东西整理一下。前端方面&#xff0c;我使用了既存md5框架语法来保存数据&#xff0c;原谅我展示没找到好的方法。后端的话&#xff0c;我使用nodemongodb来保存数据。下面我就来简单介绍一下我的东西。 前端的实现 前端的…

半导体芯片介质膜层膜层膜厚测量仪

镀膜是半导体芯片制备过程中的重要步骤。在一个完整的CMOS工艺流程中&#xff0c;介质膜层(保护层、外延层、光刻胶和栅极氧化物等)与金属沉积层交替出现。随着芯片工艺节点不断进步&#xff0c;介质膜层也变得越来越复杂&#xff0c;在7nm工艺中&#xff0c;所需测量的介质膜堆…

如何保护员工安全、公司财产?劝你一定要试试这个技能!

在现代办公环境中&#xff0c;办公室视频监控正逐渐成为维护安全、管理风险和提升工作效率的重要工具。 办公室视频监控成为许多组织的一部分&#xff0c;它不仅有助于保护员工和财产&#xff0c;还能提供实时的信息和记录&#xff0c;以应对安全挑战和法规合规性要求。 客户案…

手机的发展历史

目录 一.人类的通信方式变化 二.手机对人类通信的影响 三.手机的发展过程 四.手机对现代人的影响 一.人类的通信方式变化 人类通信方式的变化是一个非常广泛和复杂的话题&#xff0c;随着技术的进步和社会的发展&#xff0c;人类通信方式发生了许多重大的变化。下面是一些主…

dubbo之原理

RPC原理 RPC就是远程过程调用&#xff0c;它是一种通过网络从远程计算机程序上请求服务&#xff0c;而不需要了解底层网络技术的思想。 原理 一个完整的RPC主要包括三部分: 1.服务注册中心(Registry):负责将本地服务发布成远程服务&#xff0c;并进行管理&#xff0c;提供给消…

基于Echarts的数据可视化大屏

本项目学习于b站up主&#xff08;视频链接&#xff09; up主分享的资料&#xff0c;gitee仓库&#xff1a; 其中有笔记&#xff0c;笔记链接 项目总结 项目主要分为前端页面的布局和Echarts图表的嵌入&#xff0c;页面主要就是css较为繁琐&#xff0c;图表毕竟官网有模板&…

elementUI时间选择器el-time-picker的坑

//开始时间<el-time-pickerplaceholder"选择时间":format"HH:mm:ss" //显示的时间样式value-format"HH:mm:ss" //绑定值的样式 //不给默认为 Date 对象值&#xff1a;"2023-07-31T16:00:00.000Z"v-model"FormData.startTime&…

【JAVA】我们常常谈到的方法是指什么?

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️初识JAVA】 文章目录 前言方法方法的分类方法的定义方法调用方法重载 前言 在之前的文章中我们总是会介绍到类中的各式各样的方法&#xff0c;也许在应用中我们对它已经有了初步的了解&#xff0c;今…

(三) 搞定SOME/IP通信之CommonAPI库

本章主要介绍在SOME/IP通信过程中的另外一个IPC通信利剑,CommonAPI库,文章将从如下几个角度让读者了解什么是CommonAPI, 以及库在实际工作中的作用 SOME/IP通信之CommonAPI CommonAPI库是什么CommonAPI库的编译写个Demo实战一下CommonAPI库是什么 CommonAPI是GENIVI组织开发…

linux系统服务学习(二)linux下yum源配置实战

文章目录 Linux下yum源配置实战一、Linux下软件包的管理1、软件安装方式2、源码安装的配置过程3、详解源码安装的配置过程&#xff08;定制&#xff09;4、详解编译过程5、安装过程6、axel多线程下载软件源码安装7、使用软链接解决command not found8、使用环境变量解决command…

JavaScript进阶 第一天

作用域函数进阶解构赋值 一.作用域 局部作用域全局作用域作用域链JS垃圾回收机制闭包变量提升 1.1 作用域 ① 概念&#xff1a;规定了变量能够被访问的“范围”&#xff0c;离开了这个"范围"&#xff0c;变量不能被访问 ② 分类 局部作用域 &#xff08;1&…

END-TO-END、SCALE HYPERPRIOR、Checkerboard梳理总结

8.9-8.15学习汇报 阅读《END-TO-END OPTIMIZED IMAGE COMPRESSION》、《VARIATIONAL IMAGE COMPRESSION WITH A SCALE HYPERPRIOR》、《Checkerboard Context Model for Efficient Learned Image Compression》 传统的图像或视频压缩方法通常分为多个步骤&#xff0c;包括变换…

android设置竖屏仍然跟随屏幕旋转怎么办

如题所问&#xff0c;我最近遇到一个bug&#xff0c;就是设置了摇感&#xff0c;然后有用户反馈说设置了手机下拉的系统设置-屏幕旋转-关闭。然后屏幕还是会旋转的问题。 首先&#xff0c;我们先从如何设置横竖屏了解下好了 设置横屏和竖屏的方法&#xff1a; 方法一&#x…