Makefile详解

什么是makefile?

makefile是一个文本文件,是GNU make程序在执行的时候默认读取的配置文件。其关系到了整个工程的编译规则。一个工程中的源文件按类型、功能、模块分别放在若干个目录中,makefile定义了一系列规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作。
其好处在于:写好makefile之后,只需要一个“make”命令,整个工程就能完全自动编译,极大地提高了软件开发的效率。

Makefile的书写规则

粗略上看下Makefile的规则:
target … :prerequisites …
         command
         …
         …

target是一个目标文件,可以是Object File,也可以是执行文件。
prerequisites是要生成那个target所需要的文件或是目标。
command是make需要执行的命令(任意的shell命令)。
target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。
定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。
一个工程包含了头文件和C文件,我们将这些文件保存在文件名为"Makefile"或"makefile"的文件中,然后在该目录下输入命令"make"就可以生成执行文件。如果是要删除执行文件和所有的中间目标文件,那么简单执行下"make clean"就ok。

make的工作原理

当我们输入make命令时:
1.make会在当前目录下找名字为"Makefile"或"makefile"的文件。
2.如果找到,它会找文件中的第一个目标文件,并把这个文件作为最终的目标文件。
3.如果执行文件edit不存在,或是edit所依赖的后面的.o文件的文件修改时间比edit新,那么就会执行后面所定义的命令来生成edit这个文件。
4.如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。
5.当然c文件和h文件是存在的,于是make会生成.o文件,然后用.o文件生成执行文件edit。

使用变量

makefile的变量也就是一个字符串,可以理解为C语言中的宏
在makefile的一开始可以这样定义:
objects = main.o a.o b.o c.o
d.o e.o f.o
那么我们可以很方便地在makefile中以"$(objects)"的方式来使用这个变量。
如果有新的.o文件加入,只需要简单地修改下objects变量就可以了。

一些相关的细节

Makefile的文件名

大多数的make都支持“makefile”和“Makefile”这两种默认文件名。
当然也可使用其他文件名来书写Makefile,比如:“Make.Linux”,如果指定特定的Makefile,可以使用make的“-f”和“–file”参数,如:make -f Make.Linux或make --file Make.AIX

引用其他的Makefile

在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。
举个例子,你有这样几个Makefile:a.mk、b.mk、c.mk,还有一个文件叫foo.make,以及一个变量$(bar),其包含了e.mk和f.mk,那么,下面的语句:
include foo.make *.mk $(bar)
等价于:
include foo.make a.mk b.mk c.mk e.mk f.mk
如果没有指定绝对路径或是相对路径的话,make
会在当前目录下首先寻找,如果当前目录下没有找到,那么,make还会在下面的几个目录下找:
1、如果make执行时,有“-I”或“–include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。
2、如果目录;/include(一是:/usr/local/bin或/usr/include)存在的话,make也会去找。
如果你想让make不理那些无法读取的文件,而继续执行,你可以在include前加一个减号“-”。如:
-include ;

make的工作方式

GNU的make工作时的执行步骤如下:
1、读入所有的Makefile。
2、读入被include的其它Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。

文件搜寻

在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。
1、如果定义了“VPATH”这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src:…/headers
上面的的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当前目录还是最高优先搜索的地方)
2、还可以使用make的“vpath”关键字,使用方法:
vpath < pattern >; < directories >;
为符合模式< pattern >;的文件指定搜索目录< directories >
vpath < pattern >;
清除符合模式< pattern >; 的文件的搜索目录
vpath
清除所有已被设置好了的文件搜索目录
注:vapth使用方法中的;需要包含“%”字符。“%”的意思是匹配零或若干字符,例如,“%.h”表示所有以“.h”结尾的文件

伪目标

伪目标不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显示地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了。
当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。
.PHONY : clean
只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样。

双冒号规则

双冒号规则和普通规则的不同

1、双冒号规则中,对于一个没有依赖而只有命令行的双冒号规则,当引用此目标时,规则的命令将会被无条件执行。而普通规则,当规则的目标文件存在时,此规则的命令永远不会被执行(目 标文件永远是最新的)
2、当同一个文件作为多个双冒号规则的目标时。这些不同的规则会被独立的处理,而不是像普通规则那样合并所有的依赖到一个目标文件
举个例子:

Newprog :: foo.c
[Tab]$(CC) $(CFLAGS) $< -o $@
Newprog :: bar.c
[Tab]$(CC) $(CFLAGS) $< -o $@

如果“foo.c”文件被修改,执行make以后将根据“foo.c”文件重建目标“Newprog”。 而如果“bar.c”被修改那么“Newprog”将根据“bar.c”被重建
当同一个目标出现在多个双冒号规则中时,规则的执行顺序和普通规则的执行顺序 一样,按照其在 Makefile 中的书写顺序执行
 
 
 

参考:《跟我一起写Makefile》

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值