makefile那些事儿

本文介绍了Make工具的一些高级用法,包括Make的推理能力、伪目标、注释、Makefile命名约定、路径变量VPATH的使用、静态模式规则、命令显示控制、命令执行顺序以及依赖文件的自动生成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

Make工具的基本用法是很简单的,但是其强大功能的一面却为很多人所不知。本文不是以讲解make入门为目的,而是指出编译链接大型项目所不能不知道的make知识。

(1)make有强大的推理能力。只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c, 就会是whatever.o的依赖文件。并且 cc -c whatever.c 也会被推导出来

于是whatever.o:whatever.c

cc -c whatever.c

是没必要的,可以不用写在makefile中。

但是需要指出的是,make不会讲whatever.h作为whatever.o的依赖项。

(2

 .PHONY : clean
 clean :
  -rm edit $(objects)

.PHONY意思表示clean是一个伪目标,向make说明,不管是否有一个文件和clean同名,这个目标就是伪目标,不是文件。

每当命令运行完后,make会检测每个命令的返回码,如果命令返回成功,那么make会执行下一条命令,当规则中所有的命令成功返回后,这个规则就算是成 功完成了。如果一个规则中的某个命令出错了(命令退出码非零),那么make就会终止执行当前规则,这将有可能终止所有规则的执行。 而在rm命令前面加了一个小减号的意思就是,不管命令出没出错,继续后面的事儿。

(3Makefile中只有行注释,和UNIXShell脚本一样,其注释是用#字符,这个就像C/C++中的//一样。如果你要在你的Makefile中使用#字符,可以用反斜框进行转义,如:/#
 

(4你可以使用别的文件名来书写Makefile,比如:Make.LinuxMake.SolarisMake.AIX等,如果要指 定特定的Makefile,你可以使用make-f--file参数,如:make -f Make.Linuxmake --file Make.AIX
 

(5在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。
Makefile文件中的特殊变量VPATH就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。

    VPATH = src:../headers

上面的的定义指定两个目录,src../headersmake会按照这个顺序进行搜索。目录由冒号分隔。(当然,当前目录永远是最高优先搜索的地方) 

(6

$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
上面的例子中,指明了我们的目标从$object中获取,%.o表明要所有以.o结尾的目标,也就是foo.o bar.o,也就是变量$object集合的模式,而依赖模式%.c则取模式%.o%,也就是foo bar,并为其加下.c的后缀,于是,我们的依赖目标就是foo.c bar.c。而命令中的$<$@则是自动化变量,$<表示所有的依赖目标集(也就是foo.c bar.c),$@表示目标集(也就是foo.o bar.o)。于是,上面的规则展开后等价于下面的规则:

    foo.o : foo.c
            $(CC) -c $(CFLAGS) foo.c -o foo.o
    bar.o : bar.c
            $(CC) -c $(CFLAGS) bar.c -o bar.o

试想,如果我们的%.o有几百个,那种我们只要用这种很简单的静态模式规则就可以写完一堆规则,实在是太有效率了。 

(7当我们用@字符在命令行前,那么,这个命令将不被make显示出来,最具代表性的例子是,我们用这个功能来像屏幕显示一些信息。如
    @echo 正在编译XXX模块......

make执行时,会输出正在编译XXX模块......字串,但不会输出命令 

(8)当依赖目标新于目标时,也就是当规则的目标需要被更新时,make会一条一条的执行其后的命令。需要注意的是,如果你要让上一条命令的结果应用在下一条命 令时,你应该使用分号分隔这两条命令。 

(9

下面这段功能异常强大,很多时候都需要,可以直接复制到自己的makefile中。

%.d: %.c
            @set -e; rm -f $@; /
             $(CC) -M $(CPPFLAGS) $< >; $@.$$$$; /
             sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ >; $@; /
             rm -f $@.$$$$ 

第一行;使用c编译器自自动生成依赖文件($<)的头文件的依赖关系,并输出成为一个临时文件,$$$$表示当前进程号。如果$(CC)为 GNUC编译工具,产生的依赖关系的规则中,依赖头文件包括了所有的使用的系统头文件和用户定义的头文件。如果需要生成的依赖描述文件不包含系统头文件,可使用-MM代替-M

第二行;使用sed处理第二行已产生的那个临时文件并生成此规则的目标文件。这里sed完成了如下的转换过程。例如对已一个.c源文件。将编译器产生的依赖关系:

main.o : main.c defs.h

转成:

main.o main.d : main.c defs.h



这样就将.d加入到了规则的目标中,其和对应的.o文件文件一样依赖于对应的.c源文件和源文件所包含的头文件。当.c源文件或者头文件被改变之后规则将会被执行,相应的.d文件同样会被更新。

第三行;删除临时文件。 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值