@phper
2019-05-17T14:44:21.000000Z
字数 3949
阅读 2709
linux
Makefile 是Linux系统中用来生成文件、整理和管理命令的配置文件。你可以这样理解,它就是一个key:value 的shell 命令(系统或者软件的命令)集合。你通过执行和管理key,来执行 value (shell命令)。
一般我们会在项目跟目录下,直接新建一个名字叫做 Makefile 的文件,它没有文件后缀类型。
这样就生成了1个文Makefile配置文件。
Makefile 文件里的命令书写方式,类似于yaml。每一个命令规则,单独用一个区块表示,比如下面,就有好几个命令。
result.txt: source.txt
@echo "building result.txt from source.txt"
cp source.txt result.txt
source.txt:
@echo "touch source.txt"
echo '1222222' > source.txt
txt = hello world
test:
@echo ${txt}
@echo 11223
Makefile中每一个命令格式如下:
<target>: <prerequisites...>
<commands>
目标:前置条件(依赖)
TAB 命令
需要注意的是,命令前面必须加个Tab
键,不能用多个空格替代,不然会报错:
Makefile:2: *** missing separator. Stop.
另外有些编辑器,比如phpstrom
或者goland
等JB的编辑器,默认的Tab是有问题的,如果用来编写Makefile文件,会报错。所以,你可以直接用Vim来编辑,或者安装Makefile插件来解决Tab的问题。
"目标"是必需要申明的,不能省略;"前置条件"和"命令"都是可选的,但是两者之中必须至少存在一个。
我们写好了Markfile文件,我们想去执行或者运行其中的一个target,如何运行呢?用make target
这样子来运行,比如:
make result.txt
make source.txt
make test
如果只是用make
关键字,后面不加target,它会默认去执行第一个target,比如:下面是等价的。
make
make result.txt
下面来一个一个来讲一下这3个如何搭配使用。
这个相当于key:value
的key。一个目标(target)就构成一条规则,它代表你需要执行的目标或者需要生成的文件。目标通常是文件名,指明Make命令所要构建的对象,比如上文的 result.txt,则表示:"我需要创建result.txt文件"
。
目标可以是一个文件名,也可以是多个文件名,之间用空格分隔。
比如:
result.txt: source.txt
@echo "building result.txt from source.txt"
cp source.txt result.txt
目标还可以是某个操作的名字,这称为"伪目标"(phony target)。比如:
tutorial:
@echo "Please read the 'Makefile' file to go through this tutorial"
如果这个伪目标的名字和文件系统中的文件名一样,那么make执行,则会不生效,并且会报错: " 这个文件已经生成了,并比较新,没必要再生成了"。
Mrakfile文件如下:
list:
echo 123456
查看文件列表,有一个名字也为list的文件:
$ ll
total 2
-rw-r--r-- 1 yangyi staff 152B 5 15 20:06 Makefile
-rw-r--r-- 1 yangyi staff 0B 5 15 20:05 list
make 执行一下,报错了:
$ make list
make: `list' is up to date.
所以,我们得把list
加入到伪目标名单里,通过.PHONY
关键字来添加,告诉make命令,别去文件系统中找文件是都存在了,直接执行吧:
list:
echo 123456
.PHONY:list install
再执行一下:
$ make list
123456
成功了。
前置条件,通常是一组文件名,之间用空格分隔。它指定了"目标"是否重新构建("命令"被执行)的判断标准:
prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。
这是makefile 的核心。我们还是用例子来分别说明下。
result.txt: source.txt
@echo "building result.txt from source.txt"
cp source.txt result.txt
上面这个例子,我们的目的是想生成result.txt
文件,它是通过拷贝source.txt
的内容来生成的。
通过prerequisites 前置条件(依赖)
的定义,我们可以知道,result.txt
是依赖于 source.txt
。需要满足下面2条规则其一,才会生效,cp
命令才会被执行:
source.txt存在,source.txt 的最近一次修改时间,比 result.txt 要新。
source.txt文件不存在,但是存在一个命令规则,名子就叫source.txt
那么就根据这2种情况,来分析。
假设 source.txt 文件在目录里不存在。它会自动去寻找 规则中,是否有source.txt
规则是否存在,如果不存在,那么直接报错:
make: *** No rule to make target `source.txt', needed by `result.txt'. Stop.
如果,我们有有一条规则是source.txt
,是创建者文件。
source.txt:
echo 1111 > source.txt
那么就会被自动执行。再接着回到result
流程去执行命令,然后整个流程就走完了。2个target都会执行成功,并输出:
echo 1111 > source.txt
building result.txt from source.txt
cp source.txt result.txt
假设 source.txt 文件在目录里存在。就会去对比 目标和依赖文件的更新时间,如果 source.txt 的最近一次修改时间,比 result.txt 要新。那么就会执行cp命令成功,否则就会报错:
make: `result.txt' is up to date.
下面这张流程图就会看的很清楚了:
如果前置条件为空,只有target 和 commend。那如何对比更新时间呢?
比如下面这个规则:
source.txt:
echo 1111 > source.txt
上面代码中,source.txt后面没有前置条件,就意味着它跟其他文件都无关,只要这个文件还不存在,每次调用make source.txt,它都会生成。
我们执行一下:
$ make source.txt
echo 1111 > source.txt
$ make source.txt
make: `source.txt' is up to date.
他对比的是自身的文件是否存在,来作为是否去执行命令的依据
还有一种情况,target 不是文件名,是一个伪目标。比如:
help:
@echo 'help'
.PHONY help
那么,就不会去对比任何时间以及文件是否存在,每次都会往下执行。
$ make help
help
$ make help
help
$ make help
help
$ make help
help
这个命令就是普通的shell命令。规则通过后,会执行这里的命令。
每行命令之前必须有一个tab键。如果想用其他键,可以用内置变量.RECIPEPREFIX声明。
.RECIPEPREFIX = >
hello:
> echo world
make 输出的时候,会把命令也会原封不动的输出出来,再去执行,这就叫做回声(echoing)。
如果我们想屏蔽掉,可以在前面加个@
hello:
echo world
hello2:
@echo world
我们执行一下:
➜ make hello
echo 'world'
world
➜ make hello2
world
可以看出,加了@
就会屏蔽了这条命令自生的输出,而只会去执行命令。
注释是用#
来表示。但是注释在 命令里,也会被输出,可以在前面加 #
来屏蔽回声。
#list:
# ehco 'list'
install:
@#doing something
@echo 122
看一下golang 编译的例子,把golang的各个环节,用Makefile来管理和执行
all: gotool
@go build -v .
clean:
rm -f apiserver
find . -name "[._]*.s[a-w][a-z]" | xargs -i rm -f {}
gotool:
gofmt -w .
go tool vet . |& grep -v vendor;true
ca:
openssl req -new -nodes -x509 -out conf/server.crt -keyout conf/server.key -days 3650 -subj "/C=DE/ST=NRW/L=Earth/O=Random Company/OU=IT/CN=127.0.0.1/emailAddress=xxxxx@qq.com"
help:
@echo "make - compile the source code"
@echo "make clean - remove binary file and vim swp files"
@echo "make gotool - run go tool 'fmt' and 'vet'"
@echo "make ca - generate ca files"
.PHONY: clean gotool ca help