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 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。