关于Makefile中的include命令,网上有很多介绍,比较普遍的说法是:Makefile中的include命令与C语言中的include命令类似,命令include file.dep,即把file.dep文件在当前Makefile文件中展开,亦即把file.dep文件的内容包含进当前Makefile文件;如果Makefile中有以file.dep为目标的规则,make会先使用规则对file.dep文件进行更新,然后将更新后的file.dep文件包含进当前Makefile文件。[网上描述]
这种关于include命令功能的描述只是大体正确,但还不够清楚和准确,下面将我认为的对include命令的功能更清楚和准确的描述(以include file.dep为例)表述如下,不妥之处请读者指正。
Makefile中的include命令先将文件file.dep包含进当前Makefile文件(第一次包含),这样Makefile文件中就有了file.dep文件的内容;[断点A]
然后在集合U(特别注意,这里是集合U)中检查是否有以file.dep为目标的规则。如果U中没有以file.dep为目标的规则,或者虽然有以file.dep为目标的规则,但根据依赖关系(即便在规则中的命令执行后也)不能使file.dep文件发生更新,则Makefile文件最终包含的就是file.dep文件的当前内容,include命令执行结束;[断点B]
如果集合U中有以file.dep为目标的规则,并且该规则使得file.dep文件发生了更新,则include命令会将更新后的file.dep文件再次包含进当前Makefile文件(再次包含),跳转到断点A往下继续执行。
这里需要澄清的有几点:
第一,多数情况下,U中没有规则能使file.dep文件发生更新,这就给我们这样一个假象:Makefile的include命令和C语言的include命令一样,只是简单的把file.dep文件的内容包含进当前Makefile文件,即include命令执行到断点A就执行完毕了,甚至都没有执行到断点B。
第二,很多情况下,file.dep文件中并不包含以file.dep为目标的规则,这就给我们另外一个假象:include file.dep后,检查是否有规则对file.dep文件进行更新时,检查的范围仅仅是集合U1,而不是集合U。
第三,由于多数情况下include命令会在第一次执行到断点B后结束,这就给我们第三个假象:include命令只会把file.dep文件包含一次,不会将其再次包含甚至多次包含。
以上三点就是[网上描述]不清楚,不准确,含糊之处。
为了验证以上表述,我们来设计几个小的Makefile实验。
实验一 首先,在一个文件夹中用touch命令新建如下几个文件;
$touch a.h
$touch b.h
$touch c.h
$touch Makefile
修改Makefile文件为以下内容:
all:test
test:a.h
test:b.h
test:c.h
@echo "hello world";
touch test;
执行make命令;
由于test文件不存在,所以,命令行输出以下内容:
$ make
make: Nothing to be done for `all'.
这是因为当前test文件是最新生成的,比a.h,b.h和c.h都要新,所以根据规则不会再更新test文件。
下面我们分别在更新a.h,b.h和c.h文件后执行make命令,命令行输出以下内容:
$ touch a.h
$ make
hello world
touch test;
$ touch b.h
$ make
hello world
touch test;
$ touch c.h
$ make
hello world
touch test;
从命令行输出可知,每次都输出了“hello world”并且更新了test文件。
以上实验说明:在同一个Makefile文件中,如果两个或两个以上规则具有相同的目标,则在这些规则中,任一规则中的依赖文件的更新都会导致规则中的命令被执行。
从命令行输出可知,每次都输出了“hello world”并且更新了test文件。
实验二 下面我们对Makefile文件做一些改动,改动后的Makefile文件内容如下;
all:test
test:a.h
@echo "this is a.h";
test:b.h
@echo "this is b.h";
test:c.h
@echo "this is c.h";
touch test;
下面我们分别在更新a.h,b.h和c.h文件后执行make命令,命令行输出以下内容:
$ touch a.h(b.h,c.h,由于输出结果一样,这里为节省篇幅写在一行)
$ make
Makefile:6: warning: overriding commands for target `test'
Makefile:4: warning: ignoring old commands for target `test'
Makefile:8: warning: overriding commands for target `test'
Makefile:6: warning: ignoring old commands for target `test'
this is c.h
touch test;
从执行结果可以看出,只有最后一条规则的命令得到了执行。
以上实验说明:在同一Makefile文件中,如果有两个或两个以上规则具有相同的目标,则在这些规则中,任一规则中的依赖文件的更新都会且仅会导致最后一个规则中的命令被执行,前面规则的命令被忽略。
实验三 下面我们再对Makefile文件做一些改动,并且新建file.dep文件。把Makefile文件中以test为目标的第一条规则抠出来放在文件file.dep中,并在原位置使用include命令把file.dep文件包含进来,修改后的Makefile文件和file.dep文件的内容分别如下:
file.dep
test:a.h
@echo "this is a.h";
Makefile
all:test
include file.dep
test:b.h
@echo "this is b.h";
test:c.h
@echo "this is c.h";
touch test;
下面我们分别在更新a.h,b.h和c.h文件后执行make命令,命令行输出以下内容:
$ touch a.h(b.h,c.h,由于输出结果一样,这里为节省篇幅写在一行)
$ make
Makefile:5: warning: overriding commands for target `test'
file.dep:2: warning: ignoring old commands for target `test'
Makefile:7: warning: overriding commands for target `test'
Makefile:5: warning: ignoring old commands for target `test'
this is c.h
touch test;
从命令行输出可知,执行结果与实验二的非常相似,不同的只是第四行的警告信息发生在了file.dep文件中。
以上实验说明:include命令的确把file.dep文件包含进了Makefile文件,并且include命令至少执行到了断点A。
实验四 下面我们继续对Makefile文件和file.dep文件进行修改,并新建d.h文件;
$touch d.h
修改后的file.dep文件和Makefile文件的内容分别如下:
file.dep
file.dep:a.h
Makefile
all:test
include file.dep
file.dep:b.h
@echo "test:d.h" > file.dep;
test:c.h
touch test;
我们依次输入以下命令:
$touch file.dep
$touch test
$make
命令行结果如下:
make: Nothing to be done for `all'.
分析一下该结果的产生过程:首先include命令先把file.dep 文件包含进Makefile文件,包含进Makefile文件的内容为file.dep:a.h。然后,在集合U中检查是否有能使得file.dep文件发生更新的规则,此时,规则
file.dep:a.h
和规则
file.dep:b.h
@echo “test:d.h” > file.dep;
都不能使file.dep文件发生更新,include命令在包含一次file.dep文件后执行结束。Makefile接着去执行all目标的规则,由于all依赖于test并且test文件比c.h文件新,所以会出现命令行所示的结果。
下面接着依次输入以下命令:
$touch b.h
$touch d.h
$make
命令行输出:
touch test;
然后我们查看file.dep文件的内容,发现其内容已变为:
test:d.h
依据命令行的输出结果和file.dep文件的内容,我们同样来分析一下该结果的产生过程:
首先include命令先把file.dep文件包含进Makefile文件,包含进Makefile文件的内容为file.dep:a.h。然后,在集合U中检查是否有能使得file.dep文件发生更新的规则,此时,规则
file.dep:a.h
不能使file.dep文件发生更新,但是规则
file.dep:b.h
@echo “test:d.h” > file.dep;
却可以使file.dep文件发生更新,所以include命令会将更新后的file.dep文件再次包含进Makefile文件,而更新后的file.dep文件的内容也变为test:d.h。然后继续在U中检查是否有规则能使file.dep文件发生更新,此时U中以file.dep为目标的规则只有
file.dep:b.h
@echo “test:d.h” > file.dep;
并且此时的file.dep比b.h新,所以该规则中的命令不会被执行且该规则也不能使file.dep文件发生更新,include命令到此执行结束,最终包含在Makefile文件的内容为test:d.h。
接下来就是去执行all目标的规则了,all依赖于test,此时Makefile文件中有两条以test为目标的规则:
test:d.h和
test:c.h
touch test;
此时test比c.h新,而d.h比test新,根据文件的新旧关系以及实验一可知,最后会输出“touch test;”,并且该命令的执行是由依赖关系test:d.h触发的。
以上实验说明:如果在集合U(这里是U1)中存在以file.dep为目标的规则,并且该规则使得file.dep发生了更新,则file.dep文件会被再次包含进Makefile文件。
转载文章,更多请看:https://www.cnblogs.com/cuckoos/articles/5049984.html