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

使用Makefile笔记总结

文章目录

    • 一、简单了解Makefile
      • 1.1 Makefile示例
      • 1.2 基本规则
      • 1.3 make是如何工作的
      • 1.4 使用变量
      • 1.5 make自动推导
    • 二、变量
      • 2.1 变量的定义和引用
      • 2.2 变量的两种高级用法
      • 2.3 override 和 define 关键字
      • 2.4 环境变量与目标变量
      • 2.5 自动变量
    • 三、Makefile规则
      • 3.1 通配符
      • 3.2 目标依赖
    • 四、条件判断
      • 4.1 ifeq、ifneq 判断条件是否相等
      • 4.2 ifdef、ifndef 判断变量值是否为空
    • 五、函数
      • 5.1 字符串处理函数
      • 5.2 文件名处理函数
      • 5.3 foreach 函数
      • 5.4 if 函数
      • 5.5 call 函数
      • 5.6 origin 函数
      • 5.7 shell 函数
      • 5.8 error 和 warning 函数

一、简单了解Makefile

1.1 Makefile示例

使用Makefile编写规则编写一个输出Hello world的程序,程序文件如下:

$ cat print.h 
#include<stdio.h>
void printhello();$ cat print.c
#include"print.h"
void printhello(){printf("Hello, world\n");
}$ cat main.c 
#include "print.h"
int main(void){printhello();return 0;
}

编写的Makefile文件如下:

helloworld : main.o print.occ -o helloworld main.o print.o
mian.o : mian.c print.hcc -c main.c
print.o : print.c print.hcc -c print.cclean :rm helloworld main.o print.o

1.2 基本规则

make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。以下是Makefile最基本的规则:

target ... : prerequisites ...command......
  1. target就是一个目标,可以是Object File,也可以是执行文件,还可以是一个标签(Label)。
  2. prerequisites就是要生成那个target所需要的文件或是target。如果是target,则该target在后面会有一个对应的规则(eg:print.o)。
  3. command就是make需要执行的命令。command前必须使用[Tab]键,使用空格会报错。

make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。

1.3 make是如何工作的

下文所说的helloworld目标,指的是Makefile中的target,helloworld文件 指的是项目中名为helloworld的文件,注意区分。在默认的方式下,也就是我们只输入make命令,那么:

  1. make会在当前目录下找名字叫 Makefile 或 makefile 的文件。
  2. 如果找到,它会找文件中的第一个目标target。如上例中,会找到helloworld目标,并将其作为最终目标文件的文件名。然后从helloworld目标开始依次寻找依赖关系。
  3. 如果helloworld文件存在(条件1),且helloworld目标文件比其所依赖的.o目标文件的文件修改时间新(条件2),且.o目标文件比其所依赖的.c.h文件的文件修改时间新(条件3),则make啥也不做
  4. 条件1不成立,条件2和3成立,则只会执行helloworld目标定义的命令。
  5. 条件2不成立,条件3成立,则不管条件1是否成立,只会执行helloworld目标定义的命令。
  6. 如果条件3不成立,不管条件1和2是否成立,helloworld目标以及.o目标中定义的命令,都会执行。.o目标有两个,哪个不满足条件就执行哪个目标定义的命令,满足的那个不执行。

这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。

1.4 使用变量

在Makefile示例中,main.oprint.o在prerequisites和command总共出现了3次,如果再有新的xxx.o规则,在这三个地方都要加。所以,为了makefile的易维护,在makefile中我们可以使用变量。如下就是对变量OBJECTS的定义和使用:

OBJECTS = main.o print.ohelloworld: $(OBJECTS)cc -o helloworld $(OBJECTS)
mian.o: mian.c print.hcc -c main.c
print.o: print.c print.hcc -c print.cclean:rm helloworld $(OBJECTS)

1.5 make自动推导

GNU的make很强大,它具有一些隐晦规则,可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个.o文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。

只要make看到一个.o文件,它就会自动的把.c.h文件加在依赖关系中,如make找到一个print.o,那么print.cprint.h,就会是print.o的依赖文件,并且 cc -c print.c 也会被推导出来。

OBJECTS = main.o print.ohelloworld: $(OBJECTS)cc -o helloworld $(OBJECTS)
mian.o:
print.o:clean:rm helloworld $(OBJECTS)

甚至还可以按照下面方式写,不过这样Makefile文件依赖关系就显得有点凌乱了,可以根据实际情况选择,别人写了要能看懂。

OBJECTS = main.o print.ohelloworld: $(OBJECTS)cc -o helloworld $(OBJECTS)
$(OBJECTS):clean:rm helloworld $(OBJECTS)

二、变量

在 Makefile 中的定义的变量,就像是 C/C++语言中的宏一样,他代表了一个文本字符串,在 Makefile 中执行的时候其会自动原模原样地展开在所使用的地方。其与 C/C++所不同的是,你可以在 Makefile 中改变其值。

变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有:#=或是空字符(空格、回车等)。变量是大小写敏感的, fooFooFOO是三个不同的变量名。

2.1 变量的定义和引用

定义或改变一个变量常用以下4种等号:

  • :=:立即变量。对于右边引用的变量,在定义左边变量时就会展开,且只有到目前为止定义过的变量才会得到展开。
  • =:延迟变量。对于右边引用的变量,在执行含有左边变量的命令时才会展开,而不是在定义左边变量时展开。
  • ?=:如果左边变量之前没有被定义过,那么变量的值就是右边值,如果变量先前被定义过,那么这条语将什么也不做。
  • +=:将等号右边的值追加到左边变量中。如果变量之前没有定义过,那么,+=会自动变成=;如果前面有变量定义,那么+=会继承于前次操作的赋值符;如果前一次的是:=,那么+=会以:=作为其赋值符。

变量可以使用在许多地方,如规则中的“目标”、“依赖”、“命令”以及“变量的值”中。引用一个变量可使用$()${}这两个符号,使用第一个居多。

one = hello
#不允许将变量自己的值赋给自己,因为one会递归引用自身
#one = ${one} world
#这样写就允许,不会递归引用
one := ${one} world #这里加注释后,one的值为"hello world ",后面多一个空格all:echo $(one)

2.2 变量的两种高级用法

第一种是变量值的替换,其格式为$(var:a=b)或是${var:a=b},意思是,把变量var中所有以a子串结尾a替换成b子串。这里的结尾意思是空格或是结束符

OBJECTS = main.o print.o
SOURCE = $(OBJECTS:.o=.c)
all:echo $(SOURCE)

第二种是把变量的值再当成变量,其格式为$($(var)),意思是,把变量var的值作为变量名并对其引用。

x = y
y = z
z = value
a := $($($(x)))

2.3 override 和 define 关键字

make是可以通过命令行设置变量和值的,使用override定义一个变量,则通过命令行对这个变量的赋值会被忽略。

# 执行make one=boy会输出boy
one = hello
all:echo $(one)# 执行make one=boy会输出hello,override会忽略命令行对one的赋值
override one = hello
all:echo $(one) 

define后面跟的是变量的名字,而重起一行定义变量的值或执行命令,定义是以endef关键字结束。

define实际上只是一个命令列表,这与命令之间的分号有所不同,因为列表的每个命令都在单独的shell中运行。Linux命令行在shell脚本和Makefile会有些不一样的差别,一个shell是一个进程,shell脚本的命令都是在shell一个进程进行,前后命令会有所影响;而makefile里的每一行命令是一个单独的进程,只在单行里有影响,不对上下文影响。

one = export blah="I was set!"; echo $$blahdefine two
export blah=set
echo $$blah
endefall: @echo "这会打印 'I was set'"@$(one)@echo "这不会打印 'I was set' 因为每个command都在单独的shell中运行"@$(two)

2.4 环境变量与目标变量

除了用户自定义的一些变量,make在解析Makefile中还会引入一些系统环境变量,如编译参数CFLAGS、SHELL、MAKE等。这些变量在make开始运行时被载入到Makefile文件中,因为是全局性的系统环境变量,所以这些变量对所有的Makefile都有效。若Makefile中有用户自定义的同名变量,系统环境变量将会被用户自定义的变量覆盖。若用户在命令行中传递跟系统环境变量同名的变量,系统环境变量也会被传递的同名变量覆盖。(如果make指定了-e参数,那么,系统环境变量将覆盖Makefile中定义的变量)

one = hello
all:@echo $(one)$ export one=boy
$ make
hello
$ make -e
boy

为特定的目标定义变量,该变量的作用域只在特定目标下,且在作用域内是被最先匹配的,即先于文件变量和环境变量(前提make执行时没加-e参数)。

one = boy
all: one = coolall:	# 输出coll@echo $(one)other:	# 输出boy@echo $(one)

2.5 自动变量

自动变量是局部变量,作用域范围在当前的规则内,它们分别代表不同的含义:

  • -:告诉make在编译时忽略所有的错误
  • @:告诉make在执行命令前不要显示命令
  • $@:所有目标文件
  • $^:所有目标依赖
  • $<:目标依赖列表中的第一个依赖
  • $?:所有目标依赖中被修改过的文件
  • $%:当规则的目标是一个静态库文件时,$%代表静态库的一个成员名
  • $+:类似$^,但是保留了依赖文件中重复出现的文件
  • $*:在模式匹配和静态模式规则中,代表目标模式中%的部分。比如hello.c,当匹配模式为%.c时,$*表示hello
  • $(@D):表示目标文件的目录部分
  • $(@F):表示目标文件的文件名部分
  • $(*D):在模式匹配中,表示目标模式中%的目录部分
  • $(*F):在模式匹配中,表示目标模式中%的文件名部分

三、Makefile规则

3.1 通配符

在Makefile中,常用的通配符是*%。两者的共同点是都代表任意长度的字符;两者的区别在于,*是应用在当前目录中来匹配文件或目录,%是应用在当前文件中来匹配Makefile相应规则。两者的应用场合为:

  • *主要应用在规则的依赖中、规则的命令中、以及变量的值中。除了命令中,在其他地方都不建议直接使用通配符,而是用一些函数,如想列举当前目录下的所有C文件,可用$(wildcard *.c)
  • %主要应用在规则的目标中、规则的依赖中、以及一些函数中(字符串查找替换等)。

用在规则的目标和依赖中,make在读取Makefile时会自动对其进行匹配处理(通配符展开)。用在规则的命令中,通配符的通配处理在shell执行命令时完成。

# 找到当前目录下所有以.c为后缀的文件,将后缀.c替换成.o,如:main.c => main.o,然后作为依赖
all: $(subst .c,.o,$(wildcard *.c))
# 上面的依赖会在这里匹配,如main.o与%.o匹配,所以%.c就成了main.c,相当于main.o: main.c
%.o: %.cgcc -c $<
# 删除当前目录下所有以.o结尾的文件
clean:rm -f *.o

3.2 目标依赖

默认目标:一个Makefile文件里通常会有多个目标,一般会选择第一个作为默认目标。

多目标:一个规则中也可以有多个目标,多个目标具有相同的生成命令和依赖文件。如一个目标文件%.o都是由其对应的源文件%.c编译生成的,生成命令也是相同的。

%.o: %.cgcc -o %.o %.c

多规则目标:多个规则可能是同一个目标,make在解析Makefile文件时,会将具有相同目标的规则的依赖文件合并。如果每个相同目标后跟一个冒号:,则多个目标只能有一个目标有执行命令,否则会报错;如果每个相同目标后跟双冒号::,则多个目标能有多个执行命令。

# 单冒号,只能一个目标有命令
helloworld: main.occ -o helloworld $(OBJECTS)
helloworld: print.o# 双冒号,多个目标可以有命令
blah::@echo "hello"
blah::@echo "hello again"

伪目标:使用.PHONY表示目标是一个伪目标。伪目标一般没有依赖关系,也不会生成对应的目标文件,可以无条件执行,纯粹是为了执行某一个命令,如clean执行清理工作。

.PHONY : clean
clean:-rm helloworld $(OBJECTS)

头文件依赖

make会根据时间戳来判断一个规则中的目标依赖文件是否有更新。make在编译程序时,会依次检查依赖关系树中的所有源文件的时间戳,如果发现某个文件的时间戳有更新,会认为这个文件有改动过,会重新编译这个源文件。如果发现文件的时间戳没有更新,就不会再重新编译一次。

在Makefile的规则中,一般不会把头文件添加到目标依赖中。当一个.c文件中包含多个头文件时,如果对应的头文件发生了变化,因为头文件没有包含在依赖关系树中,所以这个.c文件就不会重新编译。如我们的 1.5 的Makefile,修改print.h文件,并不会重新helloworld。有两种方式解决这个问题:

  1. 手动将头文件添加到规则中,一般不采取。
  2. 一个更高效的解决方法是:使用gcc -M命令自动生成头文件依赖关系。

四、条件判断

4.1 ifeq、ifneq 判断条件是否相等

ifeq关键字用来判断两个参数是够相等,相等时条件成立为true,不相等为false。ifeq一般和变量结合使用:

mode = debugall:
ifeq ($(mode),debug)@echo "debug mode" 
else@echo "release mode"
endif

ifneq 关键字和ifeq关键字恰恰相反,用来判断参数是否不相等。当比较的参数不相等时,条件语句才成立,值为true,否则为false。

4.2 ifdef、ifndef 判断变量值是否为空

ifdef关键字用来判断一个变量是否已经定义,如果变量的值非空(在Makefile中,没有定义的变量的值为空),表达式为true。

mode = debugall:
ifdef mode@echo "def mode" 
else@echo "ndef mode"
endif

ifndef关键字和ifdef相反,如果一个变量没有定义,表达式为true。ifdefifndef后面直接跟变量名,不用引用符号。

五、函数

关于函数的使用格式,有以下需要注意的地方:

  • 函数主要分为两类:make内嵌函数和用户自定义函数。对于 GNU make内嵌的函数,直接引用就可以了;对于用户自定义的函数,要通过make的call函数来间接调用。
  • 函数和参数列表之间要用空格隔开,多个参数之间使用逗号隔开(没有空格)。
  • 如果在参数中引用了变量,变量的引用建议和函数引用使用统一格式:要么是一对小括号,要么是一对大括号。

make内嵌的函数调用语法如下:

$(<function> <arg1>,<arg2>,...)
# 或者
${<function> <arg1>,<arg2>,...}

5.1 字符串处理函数

GNU make提供了一系列文本处理函数:

  1. $(subst old,new,text)
    subst函数用来实现字符串的替换,将字符串text中的old替换为new
  2. $(patsubst pattern,replacement,text)
    patsubst函数用来做模式替换:查找text中的单词(单词以"空格",“tab”,"换行"来分割)是否符合pattern,符合的话,用replacement替代。
  3. $(strip text)
    strip函数用来将多个连续的空字符合并成一个,包括字符串开头、末尾的空字符。空字符包括:空格、多个空格、tab等不可显示的字符。
  4. $(findstring find,text)
    findstring函数会在字符串text中查找"find"字符串,如果找到,则返回字符串find,否则,返回空。
  5. $(filter pattern…,text)
    filter函数用来过滤掉字符串text中所有不符合pattern模式的单词,只留下符合pattern格式的单词。
  6. $(filer-out pattern…,text)
    filer-out函数是一个反过滤函数,功能和filter函数恰恰相反:该函数会过滤掉所有符合pattern模式的单词,保留所有不符合此模式的单词
  7. $(sort text)
    sort函数对字符串LIST中的单词以首字母为准进行排序,并删除重复的单词。
  8. $(word n,text)
    word函数从字符串text中,取出第n个单词。n大于字符串中单词的个数,返回空;如果n为0,则出错。
  9. $(wordlist n,m,text)
    wordlist函数用来从一个字符串text中取出第[n,m]个单词之间的一个单词串,n和m都是从1开始的一个数字。
  10. $(words text)
    words函数用来统计一个字符串text中单词的个数。
  11. $(firstword text)
    firstword函数用来取一个字符串中的首个单词,相当于$(word 1,text)
STR = a.c b.h c.s d.cpp
.PHONY: all
all:@echo $(subst not,totally,I am not superman)@echo $(patsubst %.c,%.o,$(wildcard *.c))@echo $(strip      hello	world  )@echo $(findstring hello,hello world)@echo $(filter %.c,$(STR))@echo $(filter-out %.c,$(STR))@echo $(sort $(STR))@echo $(word 2,$(STR))@echo $(wordlist 2,4,$(STR))@echo $(wordlist 2,4,$(STR))@echo $(words $(STR))@echo $(firstword $(STR))

5.2 文件名处理函数

GNU make提供了一系列对文件名进行各种操作的函数:文件名替换、加前缀、去目录等。

  1. $(dir NAMES…)
    dir函数:取路径名的目录。dir函数会从NAMES文件名序列中,取出各个文件路径名中的目录部分并返回。
  2. $(notdir NAMES…)
    notdir函数:取文件名。
  3. $(suffix NAMES…)
    suffix函数:取文件名后缀。文件名的后缀是文件名中以点号.开始(包括点号)的部分。若文件名没有后缀,suffix函数则返回空。
  4. $(basename NAMES…)
    basename函数:取文件名前缀。
  5. $(addsuffix SUFFIX,NAMES…)
    addsuffix函数:给文件名加后缀。给文件列表中的每个文件名添加后缀SUFFIX。
  6. $(addprefix PREFIX,NAMES…)
    addprefix函数:给文件名加前缀
  7. $(join LIST1,LIST2)
    join函数的作用是:将字符串LIST1和字符串LIST2的各个单词依次连接,合并为新的单词构成的字符串。这是将字符串中每个对应位置上的单词连接,而不是连接字符串。
  8. $(wildcard PATTERN)
    wildcard函数的作用是:列出当前目录下所有符合PATTREN模式的文件名。
FILE_PATH := /home/loongson/workspace/makefile-test/main.c 
FILE_PATH += $(FILE_PATH).PHONY: all
all:@echo $(dir $(FILE_PATH))@echo $(notdir $(FILE_PATH))@echo $(suffix $(FILE_PATH))@echo $(basename $(notdir $(FILE_PATH)))@echo $(addsuffix .o,$(basename $(notdir $(FILE_PATH))))@echo $(addprefix test,$(suffix $(notdir $(FILE_PATH))))@echo $(join $(basename $(notdir $(FILE_PATH))),$(suffix $(FILE_PATH)))@echo $(wildcard *.c)

5.3 foreach 函数

如果想做一些循环或遍历操作时,可以使用foreach函数:

$(foreach var,list,test)

foreach函数的工作过程是:把list中使用空格分割的单词依次取出并赋值给变量var,然后执行text表达式。重复这个过程,直到遍历完list中的最后一个单词。函数的返回值是text多次计算的结果。

# 找出dirs所有目录下的所有.c文件
.PHONY: all
dirs = hello-demo test
srcs = $(foreach dir, $(dirs), $(wildcard $(dir)/*.c))
all:@echo $(srcs)

5.4 if 函数

if函数提供了在一个函数上下文中实现条件判断的功能,类似于ifeq关键字,if函数的使用格式如下:

$(if CONDITION,THEN-PART)
$(if CONDITION,THEN-PART[,ELSE-PART])

if 函数的第一个参数 CONDITION表示条件判断,展开后如果非空,则条件为真,执行 THEN-PART部分;否则,如果有ELSE-PART部分,则执行ELSE-PART部分。

if函数的返回值即执行分支(THEN-PARTELSE-PART)的表达式值。如果没有ELSE-PART,则返回一个空字符串。

# 指定安装路径,默认则是/usr/local
.PHONY: all
install_path =
all:@echo $(if $(install_path),$(install_path),/usr/local)

5.5 call 函数

用户自定义函以define开头,endef结束,给函数传递的参数在函数中使用$(0)$(1)引用,分别表示第1个参数、第2个参数…

使用call函数可以用来间接调用用户自定义函数,各个参数之间使用空格隔开:

.PHONY: all
define func@echo "pram1 = $(0)"@echo "pram2 = $(1)"
endef
all:$(call func, hello zhaixue.cc)

call函数不仅可以用来调用一个用户自定义函数并传参,还可以向一个表达式传参:$(call <expression>,<parm1>,<parm2>,<parm3>...)

.PHONY: all
param = $(1) $(2)
str1 = $(call param, hello, zhaixue.cc)
all:@echo $(str1)

5.6 origin 函数

origin函数的使用格式为:$(origin <variable>)

如果变量没有定义,origin函数的返回值为:undefined,不同的返回值代表变量的类型不同。常见的返回值如下:

  • default:变量是一个默认的定义,比如 CC 这个变量。
  • file:这个变量被定义在Makefile中。
  • command line:这个变量是被命令行定义的。
  • override:这个变量是被override指示符重新定义过的。
  • automatic:一个命令运行中的自动化变量。
.PHONY: all
WEB = www.zhaixue.cc
web_type = $(origin WEB)
all:@echo $(origin WEB)@echo $(origin CC)@echo $(origin CMD)# make
# make CMD=pwd

5.7 shell 函数

如果你想在Makefile中运行shell命令,可以使用shell函数来完成这个功能。shell函数的参数是shell命令,它和反引号具有相同的功能。shell命令的运行结果即为shell函数的返回值。

.PHONY: all
all:@echo $(shell pwd)@echo $(shell ls -m)

5.8 error 和 warning 函数

make提供了两个可以控制make运行方式的函数:errorwarning。两个函数都会产生错误提示信息,但是error会终止make的运行,而warning则不会。

.PHONY: all
all:@echo "make command start..."$(warning find a error)#只发出提示信息$(error find a error)#发出提示信息,并终止make运行@echo "make command end..."

相关文章:

使用Makefile笔记总结

文章目录 一、简单了解Makefile1.1 Makefile示例1.2 基本规则1.3 make是如何工作的1.4 使用变量1.5 make自动推导 二、变量2.1 变量的定义和引用2.2 变量的两种高级用法2.3 override 和 define 关键字2.4 环境变量与目标变量2.5 自动变量 三、Makefile规则3.1 通配符3.2 目标依…...

npm下载依赖项目跑不起来--解决方案

code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: vue-element-admin4.4.0 npm ERR! Found: webpack4.46.0 npm ERR! node_modules/webpack npm ERR! webpack“^4.23.0” from the root project npm ERR! npm ERR! Coul…...

SolVES模型生态系统服务功能社会价值评估

查看原文>>>SolVES 模型生态系统服务功能社会价值评估&#xff08;基于多源环境QGIS、PostgreSQL、ArcGIS、Maxent、R语言&#xff09; 目录 第一章、理论基础与研究热点 第二章、SolVES 4.0 模型运行环境配置 第三章、SolVES 4.0 模型运行 第四章、数据获取与入…...

Godot引擎 4.0 文档 - 入门介绍 - 学习新功能

本文为Google Translate英译中结果&#xff0c;DrGraph在此基础上加了一些校正。英文原版页面&#xff1a; Learning new features — Godot Engine (stable) documentation in English 学习新功能 Godot 是一个功能丰富的游戏引擎。有很多关于它的知识。本页介绍了如何使用…...

如何进行MySQL漏洞扫描

MySQL是一款广泛使用的关系型数据库管理系统&#xff0c;但由于其复杂的结构和功能&#xff0c;也存在不少安全漏洞&#xff0c;容易被黑客攻击。为了解决这些安全问题&#xff0c;进行MySQL漏洞扫描是必要的。那么MySQL怎么进行漏洞扫描?如何进行漏洞扫描?接下来就让小编带大…...

C语言函数大全-- x 开头的函数(3)

C语言函数大全 本篇介绍C语言函数大全-- x 开头的函数 1. xdr_opaque 1.1 函数说明 函数声明函数功能bool_t xdr_opaque(XDR *xdrs, char *buf, u_int len);用于编码或解码任意长度的二进制数据 参数&#xff1a; xdrs &#xff1a; 指向 XDR 数据结构的指针&#xff0c;表…...

计算机图形学-GAMES101-12阴影

Shadow mapping 问题的提出 我们之前在进行着色时&#xff0c;对于每个物体仅考虑自己&#xff0c;而不考虑其他物体对它的影响。限定在光栅化中&#xff0c;如何解决阴影问题呢&#xff1f;阴影能被摄像机看到&#xff0c;但不能被光源所照亮。经典的Shadow mapping只能处理…...

iOS_Swift高阶函数

iOS_Swift高阶函数 #mermaid-svg-NxX1czIESDq47OQw {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-NxX1czIESDq47OQw .error-icon{fill:#552222;}#mermaid-svg-NxX1czIESDq47OQw .error-text{fill:#552222;stroke:#…...

探索Vue的组件世界-组件复用

目录 Mixin【混入】 缺陷 HOC&#xff08;higher order component&#xff09;【高阶组件】 相比较Mixin的优点&#xff1a; 不足&#xff1a; Renderless组件【函数式组件&#xff0c;无渲染组件&#xff0c;Vue社区使用比较多的一种业务复用模式】 优点&#xff1a; M…...

OMA通道-2

1 简介 本文档中指定的 API 使移动应用程序能够访问移动设备中的不同 SE&#xff0c;例如 SIM 或嵌入式 SE。 本规范提供了接口定义和 UML 图&#xff0c;以允许在各种移动平台和不同的编程语言中实现。 如果编程语言支持命名空间&#xff0c;则它应为 org.simalliance.openmob…...

SAP 用CO13冲销工序报工,但是没有产生货物移动(TCODE:CO1P 、 SE38 :CORUPROC,CORUAFWP)

前言 通常情况下&#xff0c;对PPO做GI或GR的时候&#xff0c;出现的异常可以在COGI中间被列出&#xff1b;在这些数据进入COGI之前&#xff0c;系统会把这些数据记录在CO1P中&#xff1b;换句话说&#xff0c;系统有时会出现DB的更新延时&#xff0c;当延时发生的时候&#xf…...

信息收集-服务器信息

服务器上面可以运行大量的系统服务和第三方应用服务&#xff0c;如果操作系统或者第三方软件没有及时升级打补丁&#xff0c;攻击者就有可能直接通过服务器上运行的服务进行攻击。 服务器需要收集的信息包含三个方面&#xff1a; 操作系统信息等识别waf&#xff08;Web应用程…...

连续签到积分兑换试用流量主小程序开发

每日签到积分兑换试用流量主小程序开发 打卡兑奖小程序。用户签到活得积分。积分可以兑换商品。观看激励视频广告可以积分翻倍。 用户可以参加试用商品活动参加试用需要提交信息。可以通过分享方式直接获取试用资格。 以下是流量主小程序的功能列表&#xff1a; 广告位管理&a…...

C语言—自定义类型(结构体、枚举、联合)

自定义类型 结构体结构体的声明特殊的声明结构的自引用结构体变量的定义和初始化结构体内存对齐修改默认对齐数offsetof宏 结构体传参 位段位段的定义&#xff08;声明&#xff09;位段的内存分配位段的跨平台问题位段的应用 枚举枚举类型的定义及使用枚举的优点 联合&#xff…...

Node.js博客项目开发思路笔记

博客项目介绍 1. 目标 开发一个博客系统&#xff0c;具备博客基本功能只开发 server 端&#xff0c;不关心前端 2. 需求 首页、作者页、博客详情页登陆页管理中心、新建页、编辑页 3. 技术方案 数据如何存储 博客 idtitlecontentcreatetimeauthor1标题 1内容 11111112z…...

python 之 shutil 文件的复制、删除、移动文件以及目录,并支持文件的归档、压缩和解压

一、shutil shutil 模块于文件和文件集合的高级操作&#xff0c;包括&#xff1a;复制、删除、移动文件以及目录&#xff0c;并支持文件的归档、压缩和解压等 二、使用例子 复制文件及权限 shutil.copy(src, dst)复制文件及权限&#xff1b;src 和 dst 文件路径。dst 文件名或…...

jface

JFace 是建立在 SWT 之上的 UI 部件&#xff0c;它是 SWT 的扩展并能和SWT交互。 ApplicationWindow和Action org.eclipse.jface.window.ApplicationWindow; JFace为了简化窗口的设计特别设计了类&#xff0c;比如ApplicationWindow这一个类&#xff0c;它里面包含了六个默认…...

六级备考28天|CET-6|听力第一讲|基本做题步骤与方法|13:30~14:30

目录 1. 重点词汇 proofread / ˈpruːfriːd / v.校对&#xff0c;校阅 autonomous adj.独立的 obsession n. 喜好 ample …...

系统设计 - 设计一个速率限制器

实施速率限制器的位置主要取决于我们的应用程序、技术栈、技术团队等因素。通常有三个位置可供选择&#xff1a;客户端、服务器端或中间件。 客户端是不可靠的地方来执行速率限制&#xff0c;因为恶意行为者可以轻易伪造客户端请求。 比将速率限制器放在服务器端更好的方法是使…...

[技术分享]Android平台实时音视频录像模块设计之道

实现背景 录像有什么难的&#xff1f;无非就是数据过来&#xff0c;编码保存mp4而已&#xff0c;这可能是好多开发者在做录像模块的时候的思考输出。是的&#xff0c;确实不难&#xff0c;但是做好&#xff0c;或者和其他模块有非常好的逻辑配合&#xff0c;确实不容易。 好多…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...