工程管理器make的使用
代码编程可执行文件,叫做编译(compile);在一个项目中,先编译这个,还是先编译那个(即编译的安排),叫做构建(build)。
make是最常用的构建工具,诞生于1977年,主要用于C语言想项目。
实际上,任何只要某个文件发生变化,就要重现构建的项目都可以用make构建。
make的概念
make: 制作。比如,要做出文件a.txt,就可以执行:
make a.txt
make本身不知道如何做出a.txt,需要告知make如何调用其它命令完成这个目标。
比如,假设文件a.txt依赖于b.txt和c.txt,是后面两个文件连接(cat命令)的产物。那么,make需要知道下面的规则:
这种规则make本身是不知道的,需要人为地区定义一些规则来进行一系列的操作。
a.txt: b.txt c.txt
cat b.txt c.txt > a.txt
也就是,make a.txt这条命令的背后实际分为两步:
确认b.txt和c.txt必须已经存在;
使用cat命令将两个文件进行合并,输出为新的文件。
像这样的规则,需要写在一个名为Makefile的文件中,make命令依赖这个文件进行构建。
Makefile也可以写成makefile,或者用命令行参数指定为其它文件名:
make -f rules.txt [命令]
make --file=rules.txt [命令]
当把文件写入到Makefile中的时候不需要加上述的参数,所以常规用的时候都要写到Makefile中。
make [命令] //就可以进行使用
make只是一个根据指定的Shell命令进行构建的工具。
Makefile的文件格式
Makefile文件由一系列规则构成。每条规则的形式如下:
<target>: <prerequisites>
[tab] <command> // 这里的tab键必须是tab键,不可以用相等长度的空格进行替代。
目标: 前置条件
[必须有个table键] <命令>
“目标”是必须的;“前置条件”和“命令”是可选的,但两者必存其一。可以没有前置条件或者没有命令,但是至少要有其中的一个。
明确:构建目标的前置条件是什么,以及如何构建。当前置条件和目标都存在的时候,在执行命令之前要保证前置条件必须成立。
目标(target)
一个目标(target)构成一个规则。目标通常是文件名,指明命令所要构建的对象,比如a.txt。
目标可以是一个文件名,也可以是多个文件名,之间用空格分隔。
除了文件名,目标还可以是某个操作的名字,这称之为“伪目标”(phony target)。
clean://这里的clean就是目标。
rm *.o
上面代码的目标是clean,不是一个文件名,是一个操作的名字,属于“伪目标”,作用是删除文件。
make clean
在当前目录下有文件名为clean的文件的时候,该命令会又二义性,为了避免这种情况,可以声明clean是“伪目标”:
.PHONY: clean
clean:
rm *.o
声明clean是“伪目标”之后,make不会去检查是否存在一个叫做clean的文件,而是每次运行都执行对应的命令。
如果make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标。
前置条件
前置条件通常是一组文件名,之间用空格分开,它指定了目标是否重新构建的判断标准:只要有其中的任何一个文件不存在,或者更新过,目标就需要重新构建。
result: source.txt
cp source.txt result.txt
构建result.txt文件的前提就是source.txt文件已经存在,make才可以正常运行,否则,就必须要写一条规则用来生成source.txt文件。
当没有source.txt的时候运行报错
source.txt:
echo “this is the source” > source.txt
当前置条件中的source.txt不存在的时候就先创建一个source.txt。
source.txt没有前置条件,意味着跟其它文件无关,只要source.txt不存在,每次调用make source.txt,都会生成source.txt。
如果连续执行两次make result.txt。
第一次会先创建source.txt,再创建result.txt。
第二次执行,make发现source.txt没有更新,就会不执行任何操作。
命令(command)
表示如何更新目标文件,由一行或多行Shell命令组成;
是构建“目标”的具体指令;
结果通常是生成目标文件。
每行命令之前必须有一个tab键。如果想用其它键,可以用内置变量.RECIPEPREFIX声明。(注意是每一行命令之前都要有一个tab)一般情况下用不到,用tab键即可。
.RECIPEPREFIX=>
all:
>echo 123
//用.RECIPEPREFIX指定大于号(>)替代tab键。
每行命令都是在一个单独运行的Shell中执行的,这些Shell间没有继承关系。
var:
export foo=bar
echo “foo=[$$foo]” // 美元符号在Makefile中是一个转义符。
可以看出来在前一句定义的变量在后一句没有继承。
解决方法:
;
将多行shell命令写到同一行内,每一条的命令之间都用;进行分割。
\
在每一行的shell命令的下面都加上;以示改行命令的结束,之后再在每一行的命令的最后加上\以示之后的命令与该命令之间的继承关系。“\”只是起到了转意的作用。
相对于第一种方法来说就是可读性比较强。
.ONESHELL
在之前用.ONESHELL:
声明一下