1. 简单例子
target=main
$(target): main.o
gcc -o $(target) $^
%.o:%.c
gcc -c -o $@ $<
我想生成一个目标文件 main,但是它依赖 main.o ,而 main.o 依赖 $^,“$^”的意思是当前规则编译出目标文件所有需要依赖的文件 例如编译 gcc -o main main.o test.o d 等文件
.o 文件不存在, 则需要获取
%.o:%.c gcc -c -o $@ $<%.o 是目标,%.c 是依赖文件, 例如 main.o 编译出来需要 main.c 需要命令为
- 目标:
main.o($@)- 依赖:
main.c($<)- 执行命令:
gcc -c -o main.o main.c
变量 含义 示例(规则: test: a.o b.o) $@目标文件名称 main $<第一个依赖文件 main.o $^所有依赖文件(去重) main.o test.o $+所有依赖文件(保留重复) main.o test.o test.o $?比目标新的依赖文件 若 test.o 较新:test.o
$^:所有依赖文件生成目标文件 需要连接多个 o 文件
$<:第一个依赖文件生成 o 文件 只需要一个 c 文件
既然 $@ 代表目标文件,那么修改为
target=main $(target): main.o gcc -o $@ $^ %.o:%.c gcc -c $< -o $@同时因为因为一些编译需要条件再次添加
1. 编译阶段的 Flags(如
-Wall -O2 )编译阶段将
.c 源文件转换为.o 目标文件,此时的 flags 主要控制:
- 语法检查:如
-Wall(开启所有常见警告)- 优化级别:如
-O2(二级优化)- 调试信息:如
-g(生成调试符号)- 宏定义:如
-DDEBUG(定义 DEBUG 宏)2. 链接阶段的 Flags(如
-lm -lpthread )链接阶段将多个
.o 文件合并为可执行程序,此时的 flags 主要控制:
- 库文件路径:如
-L/path/to/lib- 链接特定库:如
-lm(数学库)、-lpthread(线程库)- 链接选项:如
-static(静态链接)CC = gcc CFLAGS = -Wall -O2 -g # 编译选项(警告、优化、调试) LDFLAGS = -L/usr/local/lib # 链接器搜索路径 LDLIBS = -lm -lpthread # 需要链接的库 $(target): main.o utils.o $(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) # 链接阶段 %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< # 编译阶段 clean: rm -f *.o $(target)gcc -c -o main.o main.c
gcc -o main main.o伪目标 .PHONY
makefile 执行的条件有两条
目标文件不存在
目标依赖的文件比目标新
如果在同级目录中 clean 名称的文件,这个 make clean 不会执行
因为目标存在,也找不到依赖文件
所以添加伪目标关键字如下
target=main $(target): main.o gcc -o $(target) $^ %.o:%.c gcc -c -o $@ $< .PHONY clean: clean: rm -rf $(target) *.o变量
- 立即变量:A:=XXX.定义时确定值
- 延迟变量 B=XXX 使用时确定值
引用变量 用“$”,不想看到命令的执行结果“@”
:= # 即时变量 = # 延时变量 ?= # 延时变量, 如果是第1次定义才起效, 如果在前面该变量已定义则忽略这句 += # 附加, 它是即时变量还是延时变量取决于前面的定义 ?=: 如果这个变量在前面已经被定义了,这句话就会不会起效果,A := $(C) B = $(C) C = abc #D = ljgh666 D ?= luojunguang all: @echo A = $(A) @echo B = $(B) @echo D = $(D) C += 123A =
B = abc 123
D = luojunguang
makefile 执行分为两个阶段
解析阶段 读取整个文件 收集变量和规则
执行阶段
根据规则执行命令
所以此处 B 为 abc 123
函数
-
$(foreach var, list,text)
-
var:循环变量,依次代表列表中的每个元素。 -
list:要遍历的列表,元素之间用空格分隔。 -
text:对每个元素执行的操作,可以包含对$(var) 的引用。
SRCS := main.c utils.c test.c
OBJS := $(foreach var, $(SRCS), $(var).o)结构为
OBJS = main.c.o utils.c.o test.c.o对列表中的每个元素执行相同的操作并返回结果列表
-
-
filter$(filter patten ..., text) # 在text中取出符合patten格式的值
$(filter-out patten ..., text) # 在text中取出不符合patten格式的值C = src/ inc/ main.c lib/ func.h ./docs/ D = $(filter %/, $(C)) # 筛选以 / 结尾的元素 all: @echo "原始列表 C: $(C)" @echo "筛选结果 D: $(D)"
原始列表 C: src/ inc/ main.c lib/ func.h ./docs/ 筛选结果 D: src/ inc/ lib/ ./docs/ -
wildcard
$(wildcard pattern) wildcard 会以 pattern 这个格式,去寻找存在的文件,返回存在文件的名字files = $(wildcard *.c) all: @echo files = $(files)
files = a.c b.c c.c -
patsubst
$(patsubst patten,replacement, $(var))
var 变量里面取出每一个值,如果这个符合 pattern 格式,把它替换成 replacement 格式在函数 foreach 中做过这样测试
SRCS := main.c utils.c test.c
OBJS := $(foreach var, $(SRCS), $(var).o)结构为
OBJS = main.c.o utils.c.o test.c.o对列表中的每个元素执行相同的操作并返回结果列表
每一个文件中都有.c 存在,这时候使用 patsubst 使用
SRCS := main.c utils.c test.c OBJS := $(foreach var, $(SRCS), $(var).o) 改成 OBJS := $(foreach var, $(SRCS), $(patsubst %.c, %.o, $(var)))
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于