Makefile 模式规则
Makefile 中第 3~8 行是将对应的.c 源文件编译为.o 文件,每一个 C 文件都要写一个对应的规则,如果工程中 C 文件很多的话显然不能这么做。为此,我们可以使用 Makefile 中的 模式规则,通过 模式规则 我们就可以使用一条规则来将所有的.c 文件编译为对应的.o 文件。
模式规则中,至少在规则的目标定定义中要包涵“%”,否则就是一般规则,目标中的“%”表示对文件名的匹配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以 .c 结尾的文件,类似与通配符,a.%.c 就表示以 a. 开头,以 .c 结束的所有文件。
当“%”出现在目标中的时候,目标中“%”所代表的值决定了依赖中的“%”值,使用方法如下:
%.o : %.c
命令
Makefile 自动化变量
模式规则中,目标和依赖都是一系列的文件,每一次对模式规则进行解析的时候都会是不同的目标和依赖文件,而命令只有一行,如何通过一行命令来从不同的依赖文件中生成对应的目标?自动化变量就是完成这个功能的!所谓自动化变量就是这种变量会把模式中所定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完,自动化变量只应该出现在规则的命令中,常用的自动化变量如表:
自动化变量 | 描述 |
$@ | 规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模式中定义的目标集合。 |
$< | 依赖文件集合中 的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么“$<”就是符合模式的一系列的文件集合。 |
$^ | 所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件,“$^”会去除重复的依赖文件,只保留一份。 |
表中的 7 个自动化变量中,常用的三种:$@
、$<
和$^
,我们使用自动化变量来完成 Makefile,最终完整代码:
修改后的完成的 Makefile,可以看出精简了很多,核心就在于第 5、6 这两行,第 5 行使用了 模式规则,第 6 行使用了 自动化变量。
模式规则
模式规则类似于普通规则。只是在模式规则中,目标名中需要包含有模式字符"%",包含有模式字符"%"的目标被用来匹配一个文件名,"%" 可以匹配任何非空字符串。规则的依赖文件中同样可以使用"%",依赖文件中模式字符"%"的取值情况由目标中的"%"来决定。
例如:对于模式规则"%.o : %.c",它表示的含义是:所有的.o文件依赖于对应的.c文件。
下列示例就是一个makefile內建的模式规则,由所有的.c文件生成对应的.o文件:
%.o : %.c
$(CC) -c $(CFLAGS) $< -o $@
根据这个模式规则,makefile提供了隐式推导规则。
同时,模式规则的依赖可以不包含"%",当依赖不包含"%"时代表的是所有与模式匹配的目标都依赖于指定的依赖文件。
静态模式规则
静态模式可以更加容易地定义多目标的规则,它的语法是这样的:
目标 ...: 目标模式 : 依赖的模式
命令
...
相对于普通的模式规则,静态模式规则则显得更加地灵活,作为模式规则的一种,仍然使用"%"来进行模式的匹配,我们来看下面一个简单的例子:
当前目录下的文件:foo.c foo.h bar.c bar.h main.c. makefile内容:
1 OBJ = foo.o bar.o
2 main:${OBJ}
3 cc ${OBJ} main.c -o main
4 ${OBJ}:%.o : %.c
5 cc -c $^
执行make时的运行log:
cc -c foo.c
cc -c bar.c
cc foo.o bar.o main.c -o main
make在编译时会将执行的指令打印出来,这一部分就是实际被执行的指令。
可以看到,在makefile第二行,main的依赖文件为${OBJ},即foo.o和bar.o,make在当前目录中并没有找到这两个文件,所以就需要寻找生成这两个依赖文件的规则。
第四行就是生成foo.o和bar.o的规则,所以需要先被执行,这一行使用了静态模式规则,对于存在于${OBJ}中的每个.o文件,使用对应的.c文件作为依赖,调用命令部分,而命令就是生成.o文件。
可以看到,相对应普通的模式规则,静态模式规则相对来说更加地灵活。
makefile命令模板1(百搭)
src = $(wildcard *.c) # 找到当前目录下所有后缀为.c 的文件,赋值给 src
obj = $(patsubst %.c, % , $(src)) # 把 src 变量里所有 %.c 的文件替换成 %
ALL:$(obj)
$(obj):%:%.c #静态模式规则
gcc $< -o $@
clean:
rm -rf $(obj)
.PHONY: clean ALL
输出:
gcc mycp.c -o mycp
gcc open.c -o open
makefile命令模板2
src = $(wildcard *.c) # 找到当前目录下所有后缀为.c 的文件,赋值给 src
target = $(patsubst %.c, %.out, $(src)) # 把 src 变量里所有 %.c 的文件替换成 %.out
ALL:$(target)
$(target):%.out:%.c
gcc $< -o $@
clean:
rm -rf $(target)
.PHONY: clean ALL
# $@ : 在规则命令中, 表示规则中的目标
# $< : 在规则命令中, 表示规则中的第一个条件,如果将该变量用在模式规则中,它可以将依赖条件列表中的依赖依次取出,套用模式规则
# $^ : 在规则命令中, 表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复项,则去重
输出:
gcc mycp.c -o mycp.out
gcc open.c -o open.out
我感觉加了这个.out后,老是会出bug。不推荐这个写法。
makefile命令模板3(常用)
src = $(wildcard *.c)
targets = $(patsubst %.c, %, $(src))
CC = gcc
CFLAGS = -lpthread -m32 -Wall -g #在Linux 64平台上编译32位程序
all:$(targets)
$(targets):%:%.c
$(CC) $< -o $@ $(CFLAGS)
.PHONY:clean all
clean:
-rm -rf $(targets)
参考链接: