GNUmake(二)makefile介绍

GNUmake(二)makefile介绍



前言


我们需要一个文件来指导make如何运行,makefile正是这样的文件。makefile告诉make怎样去编译和链接一个程序。还可以通过一些定义去实现其它的功能。当make对程序进行重编译时,任何发生改动的C源文件需要被重新编译,任何引用了改动的头文件的C源程序需要被重新编译,每次对源文件的编译会产生相应的目标文件。当任意源文件被重新编译时,所有的目标文件需要被重新链接产生新的程序。本章使用一个包含8个C源文件和3个头文件的文本编辑器程序的例子,来说明一个简单的makefile文件的用法

一、规则初瞰(重点)

前面总是在说makefile指导文件的编译链接,那么到底怎么实现的呢?其实这些编译链接的过程就是通过makefile的规则来定义的。
makefile的规则包括三个部分。三个部分包括目标(target)、先决条件(prerequisites)和命令集(recipe)。具体格式见下图,其中省略号表示可以为一个或多个。
makefile规则格式

目标

目标名指定了该条规则的名字,可以是该条规则生成文件的名字,也可以是规则中一系列指令操作的名字。在终端中使用make [target],(target处换为相应目标名),可以执行该条规则。

先决条件

一个先决条件是一个生成目标的输入文件,一个目标的生成通常依赖多个输入文件。

命令集

命令集是make执行的操作,一个命令集可以包括一条或多条命令,这些命令可以写在一行或多行上。注意命令集的每一行前都需要一个制表符作为前缀。如果有需要的话,可以通过修改.RECIPEPREFIX变量来改变命令前缀。

目标、先决条件和命令集的关系

当先决条件发生改变时,命令集中的命令作用在先决条件中的文件上,重新生成目标文件。(这一过程可以递归调用,比如先决条件的先决条件发生变化时,会先更新先决条件,然后更新当前目标文件)

规则类型

从用途来分,规则通常有两种类型。

1. 生成指定文件
hello.o : hello.c
	gcc -o hello.o -c hello.c

当hello.c源文件改变或者hello.c依赖的文件改变时,执行命令集中的命令重新生成hello.o目标文件。

2. 执行一系列命令
clean : 
	rm -f *.o

当调用make clean时,删除当前目录下的所有.o文件。通常这种目标不作为其他目标的先决条件,规则中不包含先决条件,也没有目标文件生成。
makefile允许使用.PHONY来指定一个伪目标

.PHONY : clean
clean : 
	rm -f *.o

指定伪目标的作用是,如果目录中存在与伪目标相同名字的文件,make仍会执行命令集中的命令(make的具体执行逻辑见第三节)。

makefile中除了规则还可以包括其他一些文本,但是一个简单的makefile文件可以只由规则组成。

二、一个简单的makefile

这里有一个makefile的例子,该makefile描述了一个可执行文件edit,edit依赖于8个目标文件,而这8个目标文件依赖于8个C源文件和3个头文件。
具体来说,所有的C源文件依赖defs.h头文件,但只有定义了编辑命令的C源文件依赖于command.h,只有较为底层的改变编辑器缓存空间的源文件依赖于buffer.h头文件。

edit : main.o kbd.o command.o display.o \
		insert.o search.o files.o utils.o
	cc -o edit main.o kbd.o command.o display.o \
					insert.o search.o files.o utils.o
main.o : main.c defs.h
	cc -c main.c
kbd.o : kbd.c defs.h command.h
	cc -c kbd.c
command.o : command.c defs.h command.h
	cc -c command.c
display.o : display.c defs.h buffer.h
	cc -c display.c
insert.o : insert .c defs .h buffer .h
	cc -c insert.c
search.o : search.c defs .h buffer .h
	cc -c search.c
files.o : files.c defs.h buffer.h command.h
	cc c files.c
utils.o : utils.c defs.h
	cc -c utils.c
clean :
	rm edit main.o kbd.o command.o display.o \
	insert.o search.o files .o utils .o

代码中过长的行,使用了\进行换行。换行前后实际为一行,第二行前可加任意空白符。

三、 make如何处理makefile

默认目标

默认情况下,make会处理makefile中的第一条规则,但是以.开头的目标不会被作为默认目标。
例如:

hello : hello.o\
	print.o
	gcc -o hello  hello.o  print.o

hello.o : hello.c
	gcc -c hello.c -o hello.o

print.o : print.c
	gcc -c print.c -o print.o

clean : 
	rm -f *.o hello

此时调用make后默认会执行hello规则

.hello : hello.o\
	print.o
	gcc -o hello  hello.o  print.o

hello.o : hello.c
	gcc -c hello.c -o hello.o

print.o : print.c
	gcc -c print.c -o print.o

clean : 
	rm -f *.o hello

此时调用make后默认会执行hello.o规则
也可以通过.DEFAULT_GOAL变量自己指定默认目标

注意只有显式指定的目标可以作为默认目标,诸如%.o : %.c这种模式规则不能作为默认目标

处理过程

当调用make时,make会读取当前目录下的makefile文件,并处理第一条规则。以上面edit的makefile文件为例,make会处理重新链接edit程序的规则。这里介绍三条原则。

  1. 若当前目录中不存在与当前处理的规则的目标名同名的文件时,当前规则的指令集被执行。
  2. 若存在同名文件,但是先决条件文件(或其依赖的文件)的更新时间晚于目标文件,即目标文件生成后,先决条件文件又发生了改变,则当前规则的指令集被执行。
  3. 先检查后执行,即从上至下检查到源头的更改文件后,从下向上依次执行。

比如,当我们更改了insert.c文件并执行make,会重新编译insert文件,链接edit程序
而当更改了command.h文件并执行make,会重新编译kbd.o, command.ofiles.o文件,然后链接edit程序。

四、变量

edit : main.o kbd.o command.o display.o \
		insert.o search.o files.o utils.o
	cc -o edit main.o kbd.o command.o display.o \
					insert.o search.o files.o utils.o

我们在定义edit规则时,在先决条件和命令集里,两次罗列了目标文件名,这很容易出错也不易于维护,所以我们可以通过定义变量来进行优化。

objects = main.o kbd.o command.o display.o \ 
insert.o search.o files.o utils.o 
edit : $(objects) 
	cc -o edit $(objects)

变量无需额外定义,可以通过=对变量进行赋值,通过$()${}引用变量,变量更多用法即注意细节见之后的章节。这里有一个大致印象即可。

五、隐式规则

当编译一个单独的C源文件时,我们不需要把C源文件全部打出来,可以让make来自动推断补全C源文件的依赖以及相关编译命令。这种缩略的规则称为隐式规则。

objects = main.o kbd.o command.o display.o \ 
				insert.o search.o files.o utils.o 
edit : $(objects) 
	cc -o edit $(objects) 
main.o : defs.h 
kbd.o : defs.h command.h
command.o : defs.h command.h 
display.o : defs.h buffer.h 
insert.o : defs.h buffer.h 
search.o : defs.h buffer.h 
files.o : defs.h buffer.h command.h 
utils.o : defs.h 
.PHONY : clean 
clean : 
	rm edit $(objects)

其中针对单一源文件的编译进行了相应的缺省。

六、makefile的另一种风格

objects = main.o kbd.o command.o display.o \ 
	insert.o search.o files.o utils.o 
edit : $(objects) 
	cc -o edit $(objects) 
$(objects) : defs.h 
kbd.o command.o files.o : command.h 
display.o insert.o search.o files.o : buffer.h

充分利用隐式规则,但是不够直观

七、 clean规则

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

命令前的-表示执行时忽略出错。.PHONY伪目标在之前介绍过,指定为伪目标后,即使目录中有同名文件,仍会执行命令。由于clean不是任何目标的先决条件,也不适合作为默认目标,所以调用clean时,需要键入make clean


总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值