交通银行网站开发/seo关键词优化服务
Makefile基础使用和实战详解
- 一、基础
- 1.1、简单的Makefile
- 1.2、多文件编译
- 1.3、伪对象.PHONY
- 二、变量
- 2.1、自动变量
- 2.2、特殊变量
- 2.3、变量的类别
- 2.4、变量及其值的来源
- 2.5、变量引用的高级功能
- 2.6、override 指令
- 三、模式
- 四、函数
- 4.1、addprefix 函数
- 4.2、filter函数
- 4.3、filter-out函数
- 4.4、patsubst 函数
- 4.5、strip函数
- 4.6、wildcard 函数
- 总结
一、基础
Makefile 其实只是一个指示 make 程序如何为我们工作的命令文件,我们说 Makefile 其实是在说 make。而对于项目来说,Makefile 是指软件项目的编译环境。
Makefile 的好坏对于项目开发有些什么影响呢?设计得好的 Makefile,当我们重新编译时,只需编译那些上次编译成功后修改过的文件,也就是说编译的是一个 delta,而不是整个项目。反之,如果一个不好的 Makefile 环境,可能对于每一次的编译先要 clean,然后再重新编译整个项目。两种情况的差异是显然的,后者将耗费开发人员大量的时间用于编译,也就意味着低效率。
最为重要的是掌握二个概念,一个是目标(target),另一个就是依赖(dependency)。目标就是指要干什么,或说运行 make 后生成什么,而依赖是告诉 make 如何去做以实现目标。在 Makefile 中,目标和依赖是通过规则(rule)来表达的。我们最为熟悉的是采用make 来进行软件产品的代码编译,但它可以被用来做很多很多的事情。驾驭 Makefile,最为重要的是要学会采用目标和依赖关系来思考所需解决的问题。
Makefile三要素:
Makefile工作原理:
1.1、简单的Makefile
(1)示例一:
all:@echo "hello all"
test:@echo "hello test"
执行结果:
$ make
hello all
$ make test
hello test
$ make all
hello all
需要注意的是echo 前面必须只有 TAB(即键盘TAB键),且至少有一个 TAB,而不能用空格代替。对于很多初学者,最为容易犯的就是这种“低级”错误。 这种错误往往在对 Makefile 进行调试时,还不大容易发现,因为,从文本编辑器中看来,TAB 与空格有时没有太明显的区别。
Makefile 中的 all 就是目标,目标放在‘:’的前面,其名字可以是由字母和下划线‘_’组成 。echo “hello all”就是生成目标的命令,这些命令可以是任何你可以在你的环境中运行的命令以及 make 所定义的函数等等。all 目标在这里就是代表希望在终端上打印出“hello all”,有时目标会是一个比较抽象的概念。all 目标的定义,其实是定义了如何生成 all 目标,这我们也称之为规则。
(2)示例二:在示例一的基础上调换目标位置。
test:@echo "hello test"
all:@echo "hello all"
执行结果:
$ make
hello test
$ make test
hello test
$ make all
hello all
可知:
一个 Makefile 中可以定义多个目标。
调用 make 命令时,我们得告诉它我们的目标是什么,即要它干什么。当没有指明具体的目标是什么时,那么 make 以 Makefile 文件中定义的第一个目标作为这次运行的目标。这“第一个”目标也称之为默认目标(和是不是all没有关系)。
当 make 得到目标后,先找到定义目标的规则,然后运行规则中的命令来达到构建目标的目的。现在所示例的 Makefile 中,每一个规则中都只有一条命令,而实际的 Makefile,每一个规则可以包含很多条命令。
注意,命令前加了一个‘@’, 这一符号告诉 make,在运行时不要将这一行命令显示出来。
(3)示例三:
all:test@echo "hello all"
test:@echo "hello test"
执行结果:
$ make
hello test
hello all
$ make test
hello test
$ make all
hello test
hello all
会发现当运行 make 时,test 目标也被构建了。这里需要引入 Makefile 中依赖关系的概念,all 目标后面的 test 是告诉 make,all 目标依赖 test 目标,这一依赖目标在 Makefile 中又被称之为先决条件。出现这种目标依赖关系时,make工具会按从左到右的先后顺序先构建规则中所依赖的每一个目标。如果希望构建 all 目标,那么make 会在构建它之前得先构建 test 目标,这就是为什么我们称之为先决条件的原因。
1.2、多文件编译
目前有两个源文件,需要编译成一个应该程序:
foo.c
#include <stdio.h>
void foo()
{printf("This is foo() \n");
}
main.c
extern void foo();
int main()
{foo();return 0;
}
它们的依赖关系可总结为如下:
我们就可以根据依赖关系写Makefile了:
all:main.o foo.ogcc -o simple main.o foo.o
main.o:gcc -o main.o -c main.c
foo.o:gcc -o foo.o -c foo.c
clean:rm simple main.o foo.o
增加了一个 clean 目标用于删除所生成的文件,包括目标文件和 simple 可执行程序,这在现实的项目中很是常见。
值得注意的是,如果执行两次make会怎么样?执行效果如下:
$make
gcc -c main.c -o main.o
gcc -c foo.c -o foo.o
gcc -o simple main.o foo.o$make
gcc -o simple main.o foo.o
注意到第二次编译并没有构建目标文件的动作,但有构建simple可执行程序的动作,我们需要了解 make 是如何决定哪些目标(这里是文件)是需要重新编译的。为什么 make会知道我们并没有改变 main.c 和 foo.c 呢?通过文件的时间戳。当 make 在运行一个规则时,我们前面已经提到了目标和先决条件之间的依赖关系,make 在检查一个规则时,采用的方法是:如果先决条件中相关的文件的时间戳大于目标的时间戳,即先决条件中的文件比目标更新,则知道有变化,那么需要运行规则当中的命令重新构建目标。这条规则会运用到所有与我们在 make时指定的目标的依赖树中的每一个规则。比如,对于 simple 项目,其依赖树中包括三个规则,make 会检查所有三个规则当中的目标(文件)与先决条件(文件)之间的时间先后关系,从而来决定是否要重新创建规则中的目标。
那为什么会执行一次gcc -o simple main.o foo.o呢?因为all文件在我们的编译过程中并不生成,即 make 在第二次编译时找不到,所以又重新编译了一遍。如果把all改为simple,那就是我们所期望的结果:
simple:main.o foo.ogcc -o simple main.o foo.o
main.o:gcc -o main.o -c main.c
foo.o:gcc -o foo.o -c foo.c
clean:rm simple main.o foo.o
执行结果:
$make
gcc -c main.c -o main.o
gcc -c foo.c -o foo.o
gcc -o simple main.o foo.o$make
make: `simple` is up to date.
另外,对于make 工具,一个文件是否改动不是看文件大小,而是其时间戳。比如用 touch 命令来改变文件的时间戳就行了,这相当于模拟了对文件进行了一次编辑,而不需真正对其进行编辑。make 发现了 foo.c 需要重新被编译,而这,最终也导致了 simple 需要重新被编译。
$ls -l foo.c
-rw-rw-r-- 1 fly fly 65 1月 30 14:15 foo.c$touch foo.c
$ls -l foo.c
-rw-rw-r-- 1 fly fly 65 1月 30 15:42 foo.c$make
gcc -c foo.c -o foo.o
gcc -o simple main.o foo.o
1.3、伪对象.PHONY
在前面的示例项目中,现在假设在程序所在的目录下面有一个 clean 文件,这个文件也可以通过 touch 命令来创建。创建以后,运行 make clean 命令:
$ls -l clean
ls: cannot access clean: No such file or directory$touch clean
$ls -l clean
-rw-rw-r-- 1 fly fly 65 1月 30 16:42 clean$make clean
make: `clean' is up to date.
会发现 make 总是提示 clean 文件是最新的,而不是按我们所期望的那样进行文件删除操作。这是因为 make 将 clean 当作文件,且在当前目录找到了这个文件,加上 clean 目标没有任何先决条件,所以,当我们要求 make 为我们构建 clean 目标时,它就会认为 clean 是最新的。
对于这种情况,在现实中也难免存在所定义的目标与所存在的文件是同名的,采用 Makefile如何处理这种情况呢?Makefile 中的假目标(phony target)可以解决这个问题。假目标可以采用.PHONY 关键字来定义,需要注意的是其必须是大写字母。
.PHONY:clean
simple:main.o foo.ogcc -o simple main.o foo.o
main.o:gcc -o main.o -c main.c
foo.o:gcc -o foo.o -c foo.c
clean:rm simple main.o foo.o
将 clean 变为假目标后的Makefile,更改后运用 make clean 命令的结果:
$make clean
rm simple main.o foo.o
采用.PHONY 关键字声明一个目标后,make 并不会将其当作一个文件来处理,而只是当作一个概念上的目标。对于假目标,我们可以想像的是由于并不与文件关联,所以每一次 make 这个假目标时,其所在的规则中的命令都会被执行。
二、变量
在 Makefile 中通过使用变量来使得它更简洁、更具可维护性。
.PHONY:clean
CC=gcc
RM=rm
EXE=simple
OBJS=main.o foo.o$(EXE):$(OBJS)$(CC) -o $(EXE) $(OBJS)
main.o:$(CC) -o main.o -c main.c
foo.o:$(CC) -o foo.o -c foo.c
clean:$(RM) $(EXE) $(OBJS)
一个变量的定义很简单,就是一个名字(变量名)后面跟上一个等号,然后在等号的后面放这个变量所期望的值。对于变量的引用,则需要采用(变量名)或者(变量名)或者(变量名)或者{变量名}这种模式。采用变量的话,当我们需要更改编译器时,只需更改变量赋值的地方,非常方便,如果不采用变量,那我们得更改每一个使用编译器的地方,很是麻烦。显然,变量的引入增加了 Makefile 的可维护性。既然定义了一个 CC 变量,当然也可以将-o 或是-c 命令参数也定义成为一个变量,因为如果我们更改了一个编译器,那么很有可能其使用参数也得跟着改变。
2.1、自动变量
有时候目标和先决条件的名字会在规则的命令中多次出,如果改变了目标或是依赖的名,那得在命令中全部跟着改。这就需要用到 Makefile 中的自动变量,它们包括:
- $ @ 用于表示一个规则中的目标。当我们的一个规则中有多个目标时,$@所指的是其中任何造成命令被运行的目标。
- $^则表示的是规则中的所有先决条件。
- $<表示的是规则中的第一个先决条件。
除了上面的两个自动变量,在 Makefile 中还有其它的动变量。如下是测试上面三个自动变量的值的 Makefile:
.PHONY:all
all:first second thrid@echo "\$$@=$@"@echo "$$^=$^"@echo "$$<=$<"
first second thrid:
运行结果:
$ make$@=all
$^=first second thrid
$<=first
需要注意的是,在 Makefile 中‘’具有特殊的意思,因此,如果想采用echo输出‘’具有特殊的意思,因此,如果想采用 echo 输出‘’具有特殊的意思,因此,如果想采用echo输出‘’,则必需用两个连着的‘’。还有就是,’。还有就是,’。还有就是,@对于 Shell 也有特殊的意思,需要在“$$@”之前再加一个脱字符‘\’。
我们就可以将simple项目的Makefile改为如下:
.PHONY:clean
CC=gcc
RM=rm
EXE=simple
OBJS=main.o foo.o$(EXE):$(OBJS)$(CC) -o $@ $^
main.o:main.c$(CC) -o $@ -c $^
foo.o:foo.c$(CC) -o $@ -c $^
clean:$(RM) $(EXE) $(OBJS)
自动变量在对它们还不熟悉时,看起来可能有那么一点吃力,但熟悉了你就会觉得其简捷(洁),那时也会觉得它们好用。
2.2、特殊变量
在 Makefile 中有几个特殊变量,可能经常需要用到。
(1)第一个就是 MAKE 变量,它表示的是make 命令名是什么。当我们需要在 Makefile 中调用另一个 Makefile 时需要用到这个变量,采用这种方式,有利于写一个容易移植的 Makefile。
.PHONY: all
all:
@echo "MAKE = $(MAKE)"
执行:
$make
MAKE = make
(2)第二个特殊变量则是 MAKECMDGOALS,它表示的是当前用户所输入的 make 目标是什么。
.PHONY: all clean
all clean:
@echo "\$$@ = $@"
@echo "MAKECMDGOALS = $(MAKECMDGOALS)"
执行:
$make
$@ = all
MAKECMDGOALS =$make all
$@ = all
MAKECMDGOALS = all$make clean
$@ = clean
MAKECMDGOALS = clean$make all clean
$@ = all
MAKECMDGOALS = all clean
$@ = clean
MAKECMDGOALS = all clean
MAKECMDGOALS 指的是用户输入的目标,当只运行 make 命令时,虽然根据 Makefile 的语法,第一个目标将成为缺省目标,即 all 目标,但 MAKECMDGOALS 仍然是空,而不是 all,这一点需要注意。
2.3、变量的类别
(1)只用一个“=”符号定义的变量,称之为递归扩展变量(recursively expanded variable)。
.PHONY:all
foo=$(foo2)
foo2=$(foo3)
foo3= FLY.
all:@echo $(foo)
执行:
$ make
FLY.
递归扩展变量的引用是递归的。这种递归性有利也有弊。利的方面是最后foo将会被展开。但也存在弊,那就是我们不能对foo变量再采用赋值操作。如下的方式会出现一个死循环:
foo=$(foo) -O
(2)除了递归扩展变量还有一种变量称之为简单扩展变量(simply expanded variables),是用“:=”操作符来定义的。对于这种变量,make 只对其进行一次扫描和替换。
.PHONY:all
x=fly
y=$(x) FLY
x=later
xx:=fly
yy:=$(xx) FLY
xx:=fly
all:@echo "x=$(y),xx=$(yy)"
执行:
$ make
x=later FLY,xx=fly FLY
可以明显的看出 make 是如何处理递归扩展变量和简单扩展变量的。
(3)Makefile中还存在一种条件赋值符“?=”。
.PHONY:all
foo=x
foo?=y
bar?=y
all:@echo "foo=$(foo),bar=$(bar)"
执行:
$ make
foo=x,bar=y
条件赋值的意思是当变量以前没有定义时,就定义它并且将左边的值赋值给它,如果已经定义了那么就不再改变其值。条件赋值类似于提供了给变量赋缺省值的功能。
对于前面所说的变量类别,是针对一个赋值操作而言的。
2.4、变量及其值的来源
在 Makefile 中我们可以对变量进行定义。此外,还有其它的地方让 Makefile 获得变量及其值。比如:
(1)对于前面所说到的自动变量,其值是在每一个规则中根据规则的上下文自动获得变量值的。
(2)可以在运行 make 时,在 make 命令行上定义一个或多个变量。在 make 命令行中定义的变量及其值同样在 Makefile 中是可见的。其实,我们可以通过在 make 命令行中定义变量的方式从而覆盖 Makefile 中所定义的变量的值。
$ make bar=x
(3)变量还可以来自于 Shell 环境,例如采用 Shell 中的 export 命令定义了一个变量后再执行Makefile。
$ export bar=x
$ make
foo = x, bar = x
(4)Makefile 还可以采用“+=”操作符对变量进行赋值的方法。
.PHONY: all
objects = main.o foo.o bar.o utils.o
objects += another.o
all:@echo $(objects)
等价于
.PHONY:all
objects = main.o foo.o bar.o utils.o
objects:= $(objects) another.o
all:@echo $(objects)
2.5、变量引用的高级功能
在赋值的同时完成后缀替换操作。
.PHONY:all
foo= a.o b.o c.o
bar:=$(foo:.o=.c)
all:@echo "bar=$(bar)"
执行结果:
$ make
bar=a.c b.c c.c
bar 变量中的文件名从.o 后缀都变成了.c。这种功能也可以采用 patsubst 函数来实现,与函数相比,这种功能更加的简洁。当然,patsubst 功能更强,而不只是用于替换后缀。
2.6、override 指令
前面了解到,我们可以采用在 make 命令行上定义变量的方式,使得 Makefile 中定义的变量覆盖掉,从而不起作用。可能,在设计 Makefile 时,我们并不希望用户将我们在 Makefile 中定义的某个变量覆盖掉,那就得用 override 指令了。
.PHONY:all
override foo= a.o b.o c.o
bar:=$(foo:.o=.c)
all:@echo "bar=$(bar)"
执行:
$ make foo="bb.o cc.o"
bar=a.c b.c c.c
三、模式
对于前面的 Makefile,其中存在多个规则用于构建目标文件。比如,main.o 和 foo.o 都是采用不同的规则进行描述的。如果对于每一个目标文件都得写一个不同的规则来描述,太繁了!对于一个大型项目,就更不用说了。Makefile 中的模式就是用来解决这种烦恼的。我们可以把之前的simple项目的Makefile改成这样:
.PHONY:clean
CC=gcc
RM=rm
EXE=simple
OBJS=main.o foo.o$(EXE):$(OBJS)$(CC) -o $@ $^
%.o:%.c$(CC) -o $@ -c $^
clean:$(RM) $(EXE) $(OBJS)
与 前一版本的 Makefile 相比,最为直观的改变就是从二条构建目标文件的规则变成了一条。模式类似于 Windows 操作系统中所使用的通配符,当然是用“ % ”而不是“ * ”。采用了模式以后,不论有多少个源文件要编译,我们都是应用同一个模式规则的,很显然,这大大的简化了我们的工作。使用了模式规则以后,同样可以用这个 Makefile 来编译或是清除 simple 项目,这与前一版本在功能上是完全一样的。
四、函数
函数是 Makefile 中的另一个利器,现在看一看采用函数如何来简化 simple 项目的 Makefile。对于 simple 项目的 Makefile,尽管使用了模式规则,但还有一件比较恼人的事,得在这个Makefile 中指明每一个需要被编译的源程序。对于一个源程序文件比较多的项目,如果每增加或是删除一个文件都得更新 Makefile,其工作量也不可小视!
下面是采用了 wildcard 和 patsubst 两个函数后 simple 项目的 Makefile。需要注意的是函数的语法形式很特别,不过只要记住其形式就行了。
.PHONY:clean
CC=gcc
RM=rm
EXE=simple
SRCS=$(wildcard *.c)# 把.c替换为.o
OBJS=$(patsubst %.c,%.o,$(SRCS))$(EXE):$(OBJS)$(CC) -o $@ $^
%.o:%.c$(CC) -o $@ -c $^
clean:$(RM) $(EXE) $(OBJS)
现在,来模拟增加一个源文件的情形,看一看如果增加一个文件,在 Makefile 不做任何更改的情况下其是否仍能正常的工作。增加文件的方式仍然是采用 touch 命令,通过 touch 命令生成一个内容是空的 foo2.c 源文件,然后再运行 make 和 make clean。
$ touch foo2.c
$ make
gcc -o foo.o -c foo.c
gcc -o main.o -c main.c
gcc -o foo2.o -c foo2.c
gcc -o simple foo.o main.o foo2.o$ make clean
rm simple foo.o main.o foo2.o
从结果来看函数真的起作用了!这功能很酷!更多内容可以看一看《GUN make》以了解 Makefile 中到底有些什么函数,这样的话,当在碰到具体的问题时就会想到它们。
4.1、addprefix 函数
addprefix 函数是用来在给字符串中的每个子串前加上一个前缀,其形式是:
$(addprefix prefix, names...)
示例:
.PHONY:all
no_dir=foo.c foo2.c main.o
no_dir:=$(addprefix objs/,$(no_dir))
all:@echo $(no_dir)
执行:
$ make
objs/foo.c objs/foo2.c objs/main.o
4.2、filter函数
filter 函数用于从一个字符串中,根据模式得到满足模式的字符串,其形式是:
$(filter pattern..., text)
示例:
.PHONY:all
srcs=foo.c foo2.c main.s main.h
srcs:=$(filter %.c %.s,$(srcs))
all:@echo $(srcs)
执行:
$ make
foo.c foo2.c main.s
从结果来看,经过 filter 函数的调用以后,source变量中只存在.c 文件和.s 文件了,而.h 文件则被过滤掉了。
4.3、filter-out函数
filter-out 函数用于从一个字符串中根据模式滤除一部分字符串,其形式是:
$(filter-out pattern..., text)
示例:
.PHONY:all
srcs=foo.c foo2.c main1.c main2.c main.h
srcs:=$(filter-out main%.c,$(srcs))
all:@echo $(srcs)
执行:
$ make
foo.c foo2.c main.h
从结果来看,filter-out 函数将 main1.c 和 main2.c从 src变量中给滤除了。filter 与 filter-out 是互补的。
4.4、patsubst 函数
patsubst 函数是用来进行字符串替换的,其形式是:
$(patsubst pattern, replacement, text)
示例:
.PHONY:all
srcs=foo.c foo2.c main1.c main2.c
objs:=$(patsubst %.c,%.o,$(srcs))
all:@echo $(objs)
执行:
$ make
foo.o foo2.o main1.o main2.o
可以看出采用patsubst 函数进行字符串替换时,我们希望将所有的.c 文件都替换成.o 文件。当然,由于patsubst 函数可以使用模式,所以其也可以用于替换前缀等等,功能更加的强。
4.5、strip函数
strip 函数用于去除变量中的多余的空格,其形式是:
$(strip string)
示例:
.PHONY:all
srcs=foo.c foo2.c main1.c main2.c
objs:=$(strip $(srcs))
all:@echo $(srcs)@echo $(objs)
执行:
$ make
foo.c foo2.c main1.c main2.c
foo.c foo2.c main1.c main2.c
从结果来看,strip 函数将 foo.c 和 bar.c 之间的多余的空格给去除了。
4.6、wildcard 函数
wildcard 是通配符函数,通过它可以得到我们所需的文件,这个函数如果我们在 Windows 或是Linux 命令行中的“*”。其形式是:
$(wildcard pattern)
示例:
.PHONY:all
srcs=$(wildcard *.c)
all:@echo $(srcs)
执行:
$ make
foo.c main.c foo2.c
从当前 Makefile 所在的目录下通过 wildcard 函数得到所有的 C 程序源文件。
总结
- Makefile的一个规则是由目标(targets)、先决条件(prerequisites)以及命令(commands)所组成的。需要指出的是,目标和先决条件之间表达的就是依赖关系(dependency),这种依赖关系指明在构建目标之前,必须保证先决条件先满足(或构建)。而先决条件可以是其它的目标,当先决条件是目标时,其必须先被构建出来。还有就是一个规则中目标可以有多个,当存在多个目标,且这一规则是Makefile 中的第一个规则时,如果运行make 命令不带任何目标,那么规则中的第一个目标将被视为是缺省目标。
- 掌握如果在头脑中勾画出我们想让 make 做的事的“依赖树”是编写 Makefile 最为重要和关键的一步。
- 编译时出现“undefined reference to … ”时,有两个原因:第一种是源码没有被编译进去;第二种是对应库没有被引用。
相关文章:

Makefile基础使用和实战详解
Makefile基础使用和实战详解一、基础1.1、简单的Makefile1.2、多文件编译1.3、伪对象.PHONY二、变量2.1、自动变量2.2、特殊变量2.3、变量的类别2.4、变量及其值的来源2.5、变量引用的高级功能2.6、override 指令三、模式四、函数4.1、addprefix 函数4.2、filter函数4.3、filte…...

Go基础-变量
文章目录1 Go中的变量2 声明一个变量3 声明变量并初始化4 变量推断5 声明多个变量5.1 多个变量相同类型5.2 多个变量不同类型6 简短声明7 Go语言变量不能把一种类型赋值给其他类型1 Go中的变量 Go中变量指定了某存储单元的名称,该存储单元会存储特定类型的值&#…...

【算法】三道算法题目单词拆分,填充每个节点的下一个右侧节点指针以及组合总和
算法第一道算法题:单词拆分java解答参考第二道算法题:填充每个节点的下一个右侧节点指针java 解答参考第三道算法题:组合总和java解答参考大家好,我是小冷。 今天还是继续学习算法技术知识吧 第一道算法题:单词拆分 …...

【算法】刷题路线(系统+全面)
本系列基于当前各大公司对大公司的考察情况,给大家规划一条可行的算法刷题路线,大概会规划 200 道自认为有用的题,并且争取让初学者,能够刷起来更加丝滑,而且每个阶段都会进行相对应的说明。 当然,无论是面…...

Fiddler的报文分析
目录 1.Statistics请求性能数据 2.检测器(Inspectors) 3.自定义响应(AutoResponder) 1.Statistics请求性能数据 报文分析: Request Count: 1 请求数,该session总共发的请求数 Bytes …...

Spring 中,有两个 id 相同的 bean,会报错吗
我们知道,spring容器里面的bean默认是单例的,所以id是唯一的。但是需要注意,同一类型的bean可以有不同的id,比如有id1->bean,也可以有id2->bean。 下面再来详细回答一下文章的问题。 首先,在同一个…...

Mysql数据库的时间(4)一查询数据库时间注意点
一.select根据时间段查询 1.原始的sql根据时间段查询 select * from stu where time between "1998-09-01" and "1999-09-01"; //查询从1998-09-01到1999-09-01时间段的数据 等同于select * from stu where time >"1998-09-01" and time &l…...

一起学 pixijs(2):修改图形属性
大家好,我是前端西瓜哥。 我们做动画、游戏、编辑器,需要根据用户的交互等操作,去实时地改变图形的属性,比如位置,颜色等信息。今天西瓜哥带大家来看看在 pixijs 怎么修改图形的属性。 因为 pixijs 的底层维护了图形…...

LeetCode 121. 买卖股票的最佳时机
原题链接 难度:easy\color{Green}{easy}easy 题目描述 给定一个数组 pricespricesprices ,它的第 iii 个元素 prices[i]prices[i]prices[i] 表示一支给定股票第 iii 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同…...

shell脚本内调用另外一个shell脚本的几种方法
有时会在一个shell脚本(如test_call_other_shell.sh)中调用另外一个shell脚本(如parameter_usage.sh),这里总结几种可行的方法,这些方法在linux上和windows上(通过Git Bash)均适用: 1.通过source: 运行在相同的进程,在test_…...

Linux C++ 多进程下write写日志问题思考
文章目录多个进程(父子)同时通过write像日志文件中写,是否会出现数据混乱情况?需要满足以下条件: 1、通过open打开文件,子进程都是复制父进程的文件描述符去操作这个文件,不会造成文件混乱&…...

MySQL的四种事务隔离级别
目录一、事务的基本要素(ACID)1、原子性(Atomicity):2、一致性(Consistency):3、隔离性(Isolation):4、持久性(Durability)…...

方法区和元空间有什么关系?
一.什么是方法区? 方法区属于是 JVM 运行时数据区域的一块逻辑区域,是各个线程共享的内存区域。 《Java 虚拟机规范》只是规定了有方法区这么个概念和它的作用,方法区到底要如何实现那就是虚拟机自己要考虑的事情了。也就是说,在…...

2023VNCTF的两道(暂时)
from http://v2ish1yan.top/2023/02/19/%E6%AF%94%E8%B5%9Bwp/2023vnctf/ 比赛的时候在回学校的路上,所以没有打,听说质量挺高,赛后做一下 象棋王子 一个普通的js游戏,玩过关了就给flag,所以flag肯定在前端源码里 这…...

JDK版本区别
1. 泛型 ArrayList listnew ArrayList()------>ArrayList<Integer>listnew ArrayList<Integer>(); 2 自动装箱/拆箱 nt ilist.get(0).parseInt();-------->int ilist.get(0);原始类型与对应的包装类不用显式转换 3 for-each i0;i<a.length;i------------&…...

Android 基础知识4-2.8 TableLayout(表格布局)详解
一、TableLayout的概述 表格布局是以行数和列数来确定位置进行排列。就像一间教室,确定好行数与列数就能让同学有序入座。 注意:我们需要先添加<TableRow容器,每添加一个就会多一行,然后再往<TableRow容器中添加其它组件。…...

SQL代码编码原则和规范
目录1、先了解MySQL的执行过程2、数据库常见规范3、所有表必须使用Innodb存储引擎4、每个Innodb表必须有个主键5、数据库和表的字符集统一使用UTF86、查询SQL尽量不要使用select *,而是具体字段7、避免在where子句中使用 or 来连接条件8、尽量使用数值替代字符串类型…...

【博客627】gobgp服务无损变更:graceful restart特性
gobgp服务无损变更:graceful restart特性 场景 当我们的bgp网关在对外宣告bgp路由的时候,如果我们网关有新的特性要发布,那么此时如果把网关停止再启动新版本,此时bgp路由会有短暂撤回再播出的过程,会有网络抖动 期待…...

一起学 pixijs(1):常见图形的绘制
大家好,我是前端西瓜哥。 pixijs 是一个强大的 Web Canvas 2D 库,以其强大性能而著称。其底层使用了 WebGL 实现了硬件加速,当然如果不支持的话,也能回退为 Canvas。 本文使用的 pixijs 版本为 7.1.2。 Application Applicati…...

2023年PMP考试教材有哪些?(含pmp资料)
PMP考试教材是《PMBOK指南》,但这次的考试因为大纲的更新,而需要另外的敏捷书籍来备考。且官方发了通知,3、5月还是第六版指南,8月及8月之后,使用第七版教材。 新版考纲将专注于以下三个新领域: 人 – 强调与有效领导项…...

centos7防火墙工具firewall-cmd使用
centos7防火墙工具firewall-cmd使用防火墙概述centos7防火墙工具firewall-cmd使用介绍firewalld的基本使用服务管理工具相关指令配置firewalld-cmd防火墙概述 防火墙是可以帮助计算机在内部网络和外部网络之间构建一道相对隔绝的保护屏障,从而保护数据信息的一种技…...

js html过滤所有标签格式并清除所有nbsp;
var odiv document.getElementsByTagName("*"); for(var i 0; i<odiv.length; i){ if(odiv[i].className newDetail){ let obj odiv[i].childNodes[3]; let oldHtml odiv[i].childNodes[3].innerText;//获取html中不带标签内容 //console.log(odiv[i].childN…...

「技术选型」深度学习软件如何选择?
深度学习(DL, Deep Learning)是机器学习(ML, Machine Learning)领域中一个新的研究方向,它被引入机器学习使其更接近于最初的目标——人工智能(AI, Artificial Intelligence)。 深度学习是学习样本数据的内在规律和表示层次,这些学习过程中获得的信息对…...

加油站会员管理小程序实战开发教程13
我们上一篇讲解了会员注册的功能,本篇我们介绍一下会员开卡的功能。 会员注册之后,可以进行开卡的动作。一个会员可以有多张会员卡,在微搭中用来描述这种一对多的关系的,我们用关联关系来表达。 登录微搭的控制台,点击数据模型,点击新建数据模型 输入数据源的名称会员卡…...

Go语言Web入门之浅谈Gin框架
Gin框架Gin简介第一个Gin示例HelloworldRESTful APIGin返回数据的几种格式Gin 获取参数HTTP重定向Gin路由&路由组Gin框架当中的中间件Gin简介 Gin 是一个用 Go (Golang) 编写的 web 框架。它是一个类似于 martini 但拥有更好性能的 API 框架,由于 httprouter&a…...

《MySQL学习》 MySQL优化器选择如何选择索引
一.优化器的选择逻辑 建表语句 CREATE TABLE t (id int(11) NOT NULL AUTO_INCREMENT,a int(11) DEFAULT NULL,b int(11) DEFAULT NULL,PRIMARY KEY (id),KEY a (a),KEY b (b) ) ENGINEInnoDB;往表中插入10W条数据 delimiter ;; create procedure idata() begindeclare i in…...

uniapp 悬浮窗(应用内、无需授权) Ba-FloatWindow2
简介(下载地址) Ba-FloatWindow2 是一款应用内并且无需授权的悬浮窗插件。支持多种拖动;自定义位置、大小;支持动态修改。 支持自动定义起始位置支持自定义悬浮窗大小支持贴边显示支持多种拖动方效果:不可拖动、任意…...

MMKV与mmap:全方位解析
概述 MMKV 是基于 mmap 内存映射的移动端通用 key-value 组件,底层序列化/反序列化使用 protobuf 实现,性能高,稳定性强。从 2015 年中至今,在 iOS 微信上使用已有近 3 年,其性能和稳定性经过了时间的验证。近期已移植…...

【信息系统项目管理师】项目管理十大知识领域记忆敲出(整体范围进度)
【信息系统项目管理师】项目管理十大知识领域记忆敲出(整体范围进度) 【信息系统项目管理师】项目管理十大知识领域记忆敲出(整体范围进度)【信息系统项目管理师】项目管理十大知识领域记忆敲出(整体范围进度ÿ…...

一起学 pixijs(3):Sprite
大家好,我是前端西瓜哥。今天来学习 pixijs 的 Sprite。 Sprite pixijs 的 Sprite 类用于将一些纹理(Texture)渲染到屏幕上。 Sprite 直译为 “精灵”,是游戏开发中常见的术语,就是将一个角色的多个动作放到一个图片…...