一、makefile简介
在Linux中,Makefile是一种用于自动化构建和编译软件项目的工具。它通常用于管理大型项目中的源代码文件,以及定义项目的编译、链接和其他构建过程
Makefile是一种文本文件,其中包含了一系列的规则,这些规则定义了如何从源代码文件生成目标文件(如可执行文件或库文件),它用于自动化编译过程,提高开发效率,减少手动编译的繁琐和出错率
我们在一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率
可以说,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
二、使用
1.规则
Makefile的核心是规则,每个规则都描述了如何生成一个或多个目标文件。规则的基本格式如下:
目标: 依赖文件
<tab>命令
其中,目标是需要生成的文件,依赖文件是生成目标所需的文件,命令是生成目标所需执行的Shell命令
hello: hello.o
gcc -o hello hello.c
makefile文件写好后使用 make 指令运行makefile文件
2.依赖关系和依赖方法
依赖关系和依赖方法是构建自动化过程的核心
Makefile中的依赖关系和依赖方法是通过规则(rules)来定义的。
1.依赖关系
赖关系指的是源文件(如.c或.cpp文件)和目标文件(如.o对象文件或可执行文件)之间的关系。简单来说,就是哪些源文件需要被编译或重新编译来生成或更新目标文件。在Makefile中,这种关系通过规则的目标(target)和前置条件(prerequisites,也称为依赖)来定义。
例如,考虑一个简单的C程序,它由main.c和hello.c两个源文件组成,我们希望将它们编译成hello可执行文件。main.o和hello.o是这两个源文件编译后的对象文件。Makefile中的一个规则可能看起来像这样:
hello: main.o hello.o
gcc main.o hello.o -o hello
main.o: main.c
gcc -c main.c
hello.o: hello.c
gcc -c hello.c
在这个例子中,hello依赖于main.o和hello.o,而main.o依赖于main.c,hello.o依赖于hello.c。这就是依赖关系的表示。
2.依赖方法
依赖方法指的是如何根据依赖关系来生成目标文件。在Makefile中,这是通过规则中的命令(commands)来定义的。当make工具发现某个目标文件(或它的任何前置条件)比规则中列出的文件新时,它会执行该规则中的命令来生成或更新目标文件。
继续上面的例子,hello目标的依赖方法是使用gcc命令将main.o和hello.o链接成hello可执行文件。同样地,main.o和hello.o的依赖方法分别是使用gcc
-c命令分别编译main.c和hello.c。
3.自动变量
在Makefile中,还有一些自动变量可以帮助简化规则的编写。
例如,
@
代表规则中的目标,
@代表规则中的目标,
@代表规则中的目标,<代表规则中的第一个依赖。使用这些自动变量,上面的规则可以简化为:
hello: main.o hello.o
gcc $^ -o $@
main.o: main.c
gcc -c $<
hello.o: hello.c
gcc -c $<
这里, 代 表所有前置条件的列表,而 ^代表所有前置条件的列表,而 代表所有前置条件的列表,而@仍然代表目标文件
4.伪目标
使用make指令运行makefile文件时要确保目标文件的任何一个依赖文件比目标文件更新(即依赖文件的最后修改时间晚于目标文件的最后修改时间)
即“如果依赖文件比可执行代码更新,则重新构建可执行代码”
否则就会报错,这是Makefile保证软件项目构建正确性和一致性的重要机制之一。
如果你想要确保某个可执行代码(目标文件)总是被重新构建,而不管其依赖文件是否变化,你可以使用伪目标来实现这一点
在Makefile中,伪目标(也称为伪规则或伪依赖)是一种特殊的目标,它不代表一个真实的文件名。
在Makefile中,你可以通过.PHONY特殊目标来明确声明一个或多个伪目标。这样做的好处是,make会知道这些目标不是文件名,并且在执行这些目标时不会检查它们是否存在或是否最新。
.PHONY: clean all install
clean:
rm -f *.o hello
all: hello
hello: hello.o
gcc -o hello hello.o
install: hello
cp hello /usr/local/bin/
在这个例子中,clean、all和install都被声明为伪目标。这意味着,无论你运行make clean、make all还是make install,这些目标下的命令都会被执行,而不论对应的文件是否存在或是否最新
5.形成多个可执行文件
一般来说,makefile形成目标文件的时候,默认是从上到下扫描makefile文件,默认形成的是第一个目标文件(默认只形成一个可执行文件)
如果我们想要形成多个可执行文件,可以将这些文件作为 all 的依赖项列出。
# 定义编译器
CC=gcc
# 定义编译选项
CFLAGS=-Wall
# 定义可执行文件
all: program1 program2
# program1 的构建规则
program1: program1.o
$(CC) $(CFLAGS) -o $@ $^
# program1.o 的构建规则
program1.o: program1.c
$(CC) $(CFLAGS) -c -o $@ $<
# program2 的构建规则
program2: program2.o
$(CC) $(CFLAGS) -o $@ $^
# program2.o 的构建规则
program2.o: program2.c
$(CC) $(CFLAGS) -c -o $@ $<
# 清理构建文件的规则
clean:
rm -f *.o program1 program2
.PHONY: all clean
在这个例子中,all 目标依赖于 program1 和 program2,这意味着当你运行 make 或 make all 时,Makefile 会检查 program1 和 program2 是否已经是最新的,如果不是,它会根据提供的规则来构建它们。
.PHONY: all clean 这行告诉 make,all 和 clean 是伪目标,不对应任何文件名。这对于防止 make 将它们解释为文件名是很有用的,尤其是当它们与目录中的文件名相同时。
通过这种方式,你可以很容易地扩展Makefile来构建更多的文件,只需将新的目标添加到 all 的依赖列表中,并为它们提供相应的构建规则即可。