Java面对对象3

Angular框架

  返回  

makefile编写总结

2021/8/21 8:12:43 浏览:

最近在看google开源项目中,发现有部分makefile语法不是很清楚,想想要对make语法规则做一下梳理,以后好查问题,由于本人能力有限,可能有些纰漏。

makefile文件是告诉make如何去编译和链接程序语言文件

make的概念

make是一个工具程序,经由读取叫做makefile的文件,自动话构建软件

make a.txt

makefile的文件格式

构建规则都写在makefile文件里面,所以需要学会如何编写makefile

概述

makefile文件有一系列规则构成,每个规则结构如下:

target ... : prerequistes ...
 command
 ...
 ...

target可以是一个object file,也可以是一个执行文件,还可以是一个标签。
prerequisites就是要生成那个target所需要的文件或者目标(即为素材)。
command是make需要执行的命令(任意的shell命令)。
这是一个文件的依赖关系,也就是说,target这个或者多个的明白文件依赖于prerequisites中的文件,其生成规则定义在command。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要更新的话,command所定义的命令就会被执行。

target

一个target就构成一条规则。目标通常是文件名称,指明make命令所要构建的对象,比如a.txt。明白可以是一个文件名,也可以是多个文件名,之间用空格分割。
除了文件名,目标还可以是某个操作名称,这里称作为“伪目标”

clean:
 rm *.o

上面代码的目标是clean,它不是文件名,而是一个操作名称,属于“伪目标”,作用是删除对象文件。

make clean


但是,如果当前目录中,正好有一个文件叫做clean的话,那么命令不会执行,因为make发现clean文件已经存在,就任务没有必要重新构建了,但不会执行指定的rm操作。
为了避免类似的情况,可以明确clean是“伪目标”

.PHONY: clean
clean:
 rm *.o


声明clean是“伪目标”之后,make就不会检测是否存在一个叫做clean的文件,而是每次运行都会执行对应的命令。
像.PHONY这样的内置目标名还有不少,可以参考make手册(后面我会去总结)

如果make命令运行是没有指定目标,默认会执行makefile文件的第一个目标。


prerequisites

prerequisites同城是一组文件名,之间用空格分隔。它指定了“target”是否重新构建的判断标准:只要有一个前缀文件不存在,或者有更新,“target”就需要重新构建

result.txt: source.txt
 cp source.txt result.txt

上面代码中,构建result.txt的前缀条件是source.txt。如果当前目录中,source.txt已经存在,那么make result.txt可以正常运行,否则必须再写一条规则,来生成source.txt。

source.txt
 echo "this is the source" > source.txt

上面代码中,source.txt后面没有前置条件,就意味着它跟其他文件没有关系,只要这个文件不存在,每次调用make source.txt,它都会有生成

make result.txt
make result.txt

上面命令连续执行两次make result.txt。第一次执行会先新建source.txt,然后在新建result.txt。第二次执行,make发现source.txt没有变动,就不会执行任何操作。如果需要生成多个文件,往往采用想的写法

source: file1 file2 file3

上面代码中,source是一个伪目标,只有三个前置文件,没有任何对应的命令。

make source

执行make source命令后,就会一次生成file1,file2,file3。这样写法比较方便


command

command表示如何更新目标文件,有一行或多行shell命令组成。它是构建"target"的具体指令,他的运行结果同城是生成目标文件。
每行命令之前必须用一个tab键。如果想用其他键,可以用内置变量.RECIPEPREFIX声明。

.RECIPEPREFIX - >
all:
>echo Hello, world

上面代码用.RECIPEPREFIX指定大于号(>)替代tab键。所以,每行命令的起首编程了大于号,而不是tab键。需要注意的是,每行命令的在一个单独的shell中执行。这些shell之间没有继承关系。

var-lost:
 export foo-bar
 echo "foo-[$$foo]"

上面代码执行后(make var-lost),取不到foo的值。因为两行命令在两个不同的进程执行。一个解决办法是将两行命令写在一行,中间用分号隔开。

var-kept:
 export foo-bar; echo "foo=[$$foo]"

另外一个解决办法是在换行符钱加反斜杠转义。

var-kept:
 export foo-bar; \
 echo "foo=[$$foo]"

最后一个方法是加上.ONESHELL:命令。

.ONESHELL
var-kept:
 export foo-bar;
 echo "foo=[$$foo]"

makefile文件的语法

注释

井号(#)在makefile中表示注释。

# 这是注释
result.txt: source.txt
 # 这是注释
 cp source.txt result.txt # 这是注释

回声(echoing)

正常情况下,make会打印每条命令,然后再执行,这叫做回声(echoing)

test:
 # 这是测试

执行上面规则,会得到下面输出结果。

make test
# 这是测试

在命令的前面加上@,就可以关闭回声。

test:
 @#这是测试

现在在执行make test,就不会有任何输出。
由于在构建过程中,需要了解当前执行哪条质量,所以同城只在注释和纯显示的echo命令前加上@。

模式匹配

make命令运行对文件名,进行类似正则运算的匹配,主要用到的匹配符是%。比如,假定当前目录下有f1.c和f2.c两个源码文件,需要将他们编译为对应的对象文件。

$.o: %.c

等同于下面写法

f1.o: f1.c
f2.o: f2.c

使用匹配符%,可以将大量同类文件,只用一条规则就可以完成构建。

变量和赋值符

makefile允许使用等号自定义变量

txt = Hello World
test:
 @echo $$(txt)

上面代码中,变量txt等于Hello World。调用时,变量需要放在$()中。
调用shell变量,需要在美元符号前,再加一个美元符号,这是因为make命令会对美元符号转义。

test:
 @echo $$HOME

有时,变量的值可能指向另外一个变量。

v1 = $(v2)

上面代码中,变量v1的值是另一个变量v2。这时会产生一个问题,v1的值到底在定义是扩展(静态扩展),还是在运行时扩展(动态扩展)?如果v2的值是动态的,这两中扩展方式的结果可能会差异很大。
为了解决这类问题,makefile提供了四种赋值运算符(= := ?= +=),它们的区别请查看(StackOverflow)。

VARIABLE = value
# 在执行时扩展,运行递归扩展。
VARIABLE := value
# 在定义时扩展。
VARIABLE ?= value
# 只有在该变量为空时才设置值。
VARIABLE += value
# 将值追加到变量的尾端

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号