Makefile简介
Makefile文件告诉make如何编译和链接一个程序。
make编译3条规则:
- 如果源文件发生改变,那么该源文件必须重新编译。
- 如果头文件发生改变,那么包含该头文件的源文件必须重新编译。每次编译都会产生一个源文件对应的目标文件。
- 如果源文件重新编译,那么所有目标文件,无论是之前编译保留的还是新编译的,都必须重新链接生成新的可执行文件。
规则介绍
makefile由规则rules组成,rules模式如下所示:
target... : prerequisites...
recipe
...
...
target通常是程序生成文件名,比如可执行文件或目标文件,也可以是要执行操作的名,比如clean。prerequisite通常作为生成target的输入文件。target通常依赖于多个文件。recipe是make要执行的动作。recipe可以有一行或多行命令。recipe的每行命令必须以tab开头。
通常recipe存在于拥有prerequisites的规则中,并且当prerequisites发生变化时重新生成target。然而recipe有时也存在于没有prerequisites的规则中,比如clean。
规则rule诠释了合适以及如何执行命令来生成目标文件。make根据prerequisites执行recipe来生成或更新target。
一个makefile也可以包含规制之外的文本,但是简单的makefile仅需要包含规则即可。
简单的Makefile
下面是一个简单的makefile文件,描述了一个由8个目标文件生成的可执行文件edit,这8个目标文件依赖于8个C源文件和3个头文件。
在这个例子中,每个C源文件都包含头文件defs.h,只有定义编辑命令的源文件包含头文件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
可以使用“\”将过长的行分为两行,以便于阅读。
在这个例子中,target包括可执行文件edit和所有目标文件。
prerequisites是类似于main.c和defs.h的文件。每个*.o文件既是target也是prerequisites。
recipes包含cc -c main.c等。
没有任何prerequisites的动作名的target被称为伪目标.phony target,例如clean。
make如何执行Makefile
默认情况下,make从第一个非“.”开头的target来处理。这个target被称为默认target。可以通过变量.DEFAULT_GOAL来指定默认target。
在上节的例子中,默认的target就是可执行文件edit。
当执行命令make时,make就会读取当前目录下的makefile并执行第一条规则。在上节的例子中,第一条规则时链接生成可执行文件edit,但是make在执行这条规则之前,必须执行其prerequisites的规则,这儿是目标文件。这些目标文件都有各自的规则,都是通过编译源文件来生成的目标文件。
如果prerequisites中的任何源文件或头文件比目标文件新,或者目标文件不存在,都需要重新编译生成目标文件。
执行其他规则的原因是这些规则是最终目标的prerequisites,如果这些规则不是最终目标的prerequisites,那么这些规则不会被执行,除非告诉make执行的目标,例如make clean。
变量会使Makefile简化
在之前的例子中,有两次在规则中将所有的*.o目标文件列出来,这种重复很容易出错。可以定义字符串变量来替换这些目标文件。
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
在标准的Makefile中都会有一个名为objects、OBJECTS、objs、OBJS、obj或OBJ的变量,这是所有目标文件名的列表。例如,
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
在需要使用目标文件列表的地方可以使用$(objects)来代替。
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 : 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 $(objects)
make自动推断recipes
没有必要详细写出编译每个C源文件的方法,因为make能够自动推断出:make有一条隐含规则即使用cc -c命令从相应名称的.c文件生成对应的.o文件。例如,recipe会使用命令cc -c main.c -o main.o编译main.c生成main.o。因此我们可以省略生成目标文件规则中的recipe。
当使用这种方式自动生成.o文件时,相应名称的.c文件会自动被添加到prerequisites中,因此我们可以在prerequisites中省略掉相应的.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的另一种风格
当makefile中的目标文件都是通过隐含规则生成的,那么该makefile可以采用另一种风格。即可以通过prerequisites进行分组,而不是通过target。
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
清理目录的规则
Makefile除了编译程序还可以做一些其他事情,比如删除所有目标文件和可执行文件,以使目录干净。
.PHONY : clean
clean :
-rm edit $(objects)
.PHONY可以防止和名为clean的文件产生混淆,因为clean不是edit的prerequisites,因此make不携带任何参数时是不会执行clean的,只有当make指定具体target,会在.PHONY中进行查找。
这种规则不能放在Makefile的头部,因为这种规则不能作为默认规则被执行。
- 原文作者:生如夏花
- 原文链接:https://blduan.top/post/%E5%B7%A5%E5%85%B7%E4%BD%BF%E7%94%A8/%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7/makefile/makefile%E7%AE%80%E4%BB%8B/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。