目录
1.为什么要使用Makefile
在软件开发过程中,通常需要进行一系列的编译、链接等操作来生成可执行程序或库文件。如果手动执行这些命令,不仅繁琐易错,而且效率低下。Makefile 可以自动识别哪些文件发生了变化,并只重新编译和链接那些受影响的部分,大大节省了时间。例如,在一个大型项目中,当你只修改了一个源文件时,Makefile 会自动判断出只需要重新编译这个文件以及依赖它的部分,而不是重新编译整个项目。
使用Makefile有以下好处:
一、简化编译过程
对于大型项目,通常包含多个源文件和复杂的依赖关系。手动编译这些文件会非常耗时且容易出错。Makefile 可以定义一系列规则,指定如何编译、链接这些源文件。例如,你可以在 Makefile 中指定使用特定的编译器、编译选项等。当你执行 “make” 命令时,Makefile 会自动按照规则进行编译,大大简化了编译过程。
二、自动依赖管理
- 检测依赖关系:Makefile 能够自动检测源文件之间的依赖关系。如果一个源文件发生了变化,Makefile 会确定哪些文件依赖于它,并只重新编译那些受影响的文件。比如,有一个源文件 A.cpp 被修改了,而文件 B.cpp 和 C.cpp 依赖于 A.cpp,那么 Makefile 会只重新编译 B.cpp 和 C.cpp,而不会重新编译其他未受影响的文件。
- 确保一致性:通过管理依赖关系,Makefile 可以确保项目在不同的编译环境下保持一致性。如果某个依赖文件缺失或发生变化,Makefile 会发出错误提示,以便开发者及时处理。
三、提高开发效率
- 快速构建:由于 Makefile 只重新编译受影响的文件,所以可以大大缩短构建时间。在开发过程中,频繁的编译是很常见的,Makefile 的高效构建能力可以显著提高开发效率。
- 方便调试:在调试过程中,开发者可能需要频繁地修改和编译代码。Makefile 可以快速响应这些变化,使得调试过程更加顺畅。
四、可重复性和可维护性
- 可重复性:Makefile 确保了每次构建的结果都是一致的。这对于团队开发非常重要,因为每个开发者都可以使用相同的构建过程来获得相同的结果。
- 可维护性:随着项目的发展,源文件的数量和依赖关系可能会发生变化。Makefile 可以方便地进行修改和扩展,以适应这些变化。同时,清晰的规则和依赖关系也使得项目更容易维护。
五、跨平台支持
不同的操作系统和开发环境可能有不同的编译工具和命令。Makefile 可以通过适当的配置,在不同的平台上实现相同的构建过程。这使得项目可以在多个平台上进行开发和部署,提高了项目的可移植性。
2.Makefile的基础语法
Makefile 有以下基础语法:
一、目标、依赖和命令
1.基本结构:
- Makefile 由一系列规则组成。每个规则的形式为:
目标: 依赖文件列表
,接着是一个或多个命令行,以制表符(Tab)开头。例如:
myprogram: main.o utils.o
gcc -o myprogram main.o utils.o
在这个例子中,myprogram
是目标,main.o
和utils.o
是依赖文件。当执行 “make myprogram” 时,如果依赖文件比目标文件新,就会执行后面的命令来生成目标文件。
2.目标:
- 目标可以是一个可执行文件、目标文件、库文件等。它代表了要生成的产物。
- 可以有多个目标,也可以有一个目标依赖于其他目标。例如:
all: myprogram
myprogram: main.o utils.o
gcc -o myprogram main.o utils.o
main.o: main.c
gcc -c main.c
utils.o: utils.c
gcc -c utils.c
这里,“all” 是一个伪目标,它依赖于 “myprogram”。当执行 “make all” 时,会先构建 “myprogram”。
3.依赖:
- 依赖是生成目标所需要的文件。如果依赖文件的时间戳比目标文件新,就会触发命令的执行。
- 依赖可以是源文件、目标文件、库文件等。可以有多个依赖,用空格分隔。
4.命令:
- 命令是用于生成目标的具体操作。每个命令行必须以制表符开头,不能用空格。
- 命令可以是任何 shell 命令,如编译命令、链接命令、复制文件等。
二、变量
1.定义变量:
- 可以使用 “=”、“:=”、“?=” 等符号来定义变量。例如:
CC = gcc
OBJS = main.o utils.o
这里定义了两个变量 “CC” 和 “OBJS”。
1.使用变量:
- 在规则中可以使用变量来代替具体的值。例如:
myprogram: $(OBJS)
$(CC) -o myprogram $(OBJS)
这里使用了变量 “OBJS” 和 “CC” 来指定依赖文件和编译器。
三、通配符和模式规则
1.通配符:
- Makefile 支持通配符,如 “*”、“?” 等。可以用通配符来匹配一组文件。例如:
SRC_FILES = *.c
这里定义了一个变量 “SRC_FILES”,它包含了当前目录下所有的 C 源文件。
2.模式规则:
- 模式规则可以用于对一类目标进行统一的构建。例如:
%.o: %.c
$(CC) -c $< -o $@
这个规则表示,对于任何以 “.c” 结尾的文件,都可以生成一个对应的以 “.o” 结尾的目标文件。其中," < "表示第一个依赖文件," @ "表示目标文件。
四、伪目标
1.定义伪目标:
- 伪目标不是真正的文件,而是一个标签,用于执行一系列命令。定义伪目标的方式是在目标名前加上 “.PHONY” 关键字。例如:
.PHONY: clean
clean:
rm -f *.o myprogram
这里定义了一个伪目标 “clean”,用于删除生成的目标文件和中间文件。
2.使用伪目标:
- 可以像使用普通目标一样使用伪目标,执行 “make clean” 就会执行 “clean” 规则中的命令。
五、注释
1.注释方式:
- Makefile 中使用 “#” 进行注释。例如:
# 这是一个注释
myprogram: main.o utils.o
gcc -o myprogram main.o utils.o
3.Makefile函数
makefile里面可以包含很多函数,这些函数都是make本身实现的,下面我们来几个常用的函数。引用一个函数用“$”。
-
foreach
函数foreach语法如下:
$(foreach var,list,text)
前两个参数,‘var’和‘list’,将首先扩展,注意最后一个参数 ‘text’ 此时不扩展;接着,对每一个 ‘list’ 扩展产生的字,将用来为 ‘var’ 扩展后命名的变量赋值;然后 ‘text’ 引用该变量扩展;因此它每次扩展都不相同。结果是由空格隔开的 ‘text’。在 ‘list’ 中多次扩展的字组成的新的 ‘list’。‘text’ 多次扩展的字串联起来,字与字之间由空格隔开,如此就产生了函数 foreach 的返回值。
实例:
A = a b c
B = $(foreach f, &(A), $(f).o)
all:
@echo B = $(B)
结果:
B = a.o b.o c.o
-
filter/filter-out
函数filter/filter-out语法如下:
$(filter pattern...,text) # 在text中取出符合patten格式的值
$(filter-out pattern...,text) # 在text中取出不符合patten格式的值
实例:
C = a b c d/
D = $(filter %/, $(C))
E = $(filter-out %/, $(C))
all:
@echo D = $(D)
@echo E = $(E)
结果:
D = d/
E = a b c
-
Wildcard
函数Wildcard语法如下:
$(wildcard pattern) # pattern定义了文件名的格式, wildcard取出其中存在的文件。
这个函数 wildcard 会以 pattern 这个格式,去寻找存在的文件,返回存在文件的名字。
实例:
在该目录下创建三个文件:a.c b.c c.c
files = $(wildcard *.c)
all:
@echo files = $(files)
结果:
files = a.c b.c c.c
我们也可以用wildcard函数来判断,真实存在的文件
实例:
files2 = a.c b.c c.c d.c e.c abc
files3 = $(wildcard $(files2))
all:
@echo files3 = $(files3)
结果:
files3 = a.c b.c c.c
-
patsubst
函数 patsubst 语法如下:
$(patsubst pattern,replacement,\$(var))
patsubst 函数是从 var 变量里面取出每一个值,如果这个符合 pattern 格式,把它替换成 replacement 格式,
实例:
files2 = a.c b.c c.c d.c e.c abc
dep_files = $(patsubst %.c,%.d,$(files2))
all:
@echo dep_files = $(dep_files)
结果:
dep_files = a.d b.d c.d d.d e.d abc
实际上windows工具管理程序的内部机制,也是Makefile,我们在linux下来开发裸板程序的时候,使用Makefile组织管理这些程序