C语言16-makefile(3)——makefile的模式规则

1.模式规则

上一节我们的makefile文件如下:

makefile 复制代码
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))

app:$(obj)
	gcc $(obj) -o app
hello.o:hello.c
	gcc -c hello.c -o hello.o
add.o:add.c
	gcc -c add.c -o add.o
sub.o:sub.c
	gcc -c sub.c -o sub.o
mul.o:mul.c
	gcc -c mul.c -o mul.o 

我们目前只有4个c文件,可以生成4个o文件,那如果我们有200个呢,2000个呢,要咋办?make里面提供了一种模式规则,来对一类规则进行匹配并简化。

2.基本语法

makefile 复制代码
目标模式: 依赖模式1 依赖模式2 
    命令
  • 目标模式 包含一个 %,匹配目标文件名的一部分。必须含且仅含一个 %(如 %.o、build/%.o)
  • 依赖模式 也包含 %,匹配时 % 的值与目标中的 % 相同。
  • % 匹配非空字符串(不能空),可以出现在任何位置,但通常出现在文件名末尾(如 %.o)或中间(如 build/%.exe)。

核心机制:当 Make 需要生成一个目标(比如 foo.o)且没有显式规则时,会查找模式规则。如果 foo.o 匹配 %.o(% = foo),则依赖变为 foo.c(若模式是 %.o: %.c)。然后 Make 会尝试生成或找到 foo.c,如果成功则执行命令。

3.自动变量

  • $@:表示规则中的目标
  • $<:表示规则中的第一个条件
  • $^:表示规则中的所有条件,组成一个列表,以空格隔开,如果列表中有重复项,则消除重复项

到此,makefile可以修改为:

makefile 复制代码
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))

app:$(obj)
	gcc $^ -o app
%.o:%.c
	gcc -c $^ -o $@

4.内置变量

  • CC:默认是cc指令,可以改成gcc
  • CPPFLAGS:C语言预处理的选项 -I(大写的i)
  • CFLAGS:C编译器的选项
  • LDFLAGS:链接器选项 -L -l(小写的l)

到此,makefile可以修改为:

makefile 复制代码
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))

target=app
CC=gcc
CPPFLAGS=-I ./

$(target):$(obj)
	$(CC) $^ -o $@
%.o:%.c
	$(CC) -c $^ -o $@ $(CPPFLAGS)

5.伪目标

5.1.clean

我们每次make后都会产生.o文件以及可执行文件,当我们需要重新编译的时候,我们需要手动清理,make为我们提供了清理的机制,我们在makefile中编写clean即可。因为只有目标,没有依赖,又被称为伪目标 。

当我们clean的命令出错时应该如何处理呢?在指令前加上"-"

写法如下:

makefile 复制代码
clean:
	-rm -rf *.o $(target)

5.2. .PHONY

如果目录中存在名为 clean 的文件,make 会认为它们已经是最新的而不执行规则。

为避免这种情况,可以将它们声明为伪目标:

makefile 复制代码
.PHONY:clean
clean:
	-rm -rf *.o $(target)

6.最终的makefile

makefile 复制代码
src = $(wildcard *.c)
obj = $(patsubst %.c,%.o,$(src))
target=app

CC=gcc
CPPFLAGS=-I ./

.PHONY: clean

$(target):$(obj)
	$(CC) $^ -o $@
%.o:%.c
	$(CC) -c $^ -o $@ $(CPPFLAGS)
clean:
	-rm -rf *.o $(target)
相关推荐
夏幻灵6 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
程序猿编码6 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
Apipi*7 小时前
30天速通Linux 第六章信号及信号处理
linux·运维·信号处理
天启HTTP7 小时前
爬虫防封核心原理:IP轮换机制与风控规避逻辑
linux·服务器·网络·爬虫·tcp/ip
bkspiderx8 小时前
Qt 插件机制:动态扩展应用功能的核心框架
开发语言·qt·元数据·qt 插件·qpluginloader
程序员老陆8 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
沐晓时光8 小时前
C语言入门,深入理解指针(3)
c语言·开发语言
码云数智-园园8 小时前
unique_ptr 还是 shared_ptr?C++ 智能指针选型与内存泄漏实战分析
java·开发语言
禾小西9 小时前
07丨Redis 哨兵机制:主库故障后,如何恢复服务?
java·开发语言·redis
我不是阵雨9 小时前
JDK 21虚拟线程Pinning陷阱:一文拔钉解困
java·开发语言