1. Makefile 基础概念
-
Makefile 用于自动化编译、构建、测试、打包等任务。
-
make工具会根据 Makefile 定义的规则执行任务。 -
常见格式:
1target: prerequisites 2 command- target:目标,例如生成的文件或任务名。
- prerequisites:依赖文件或其他目标。
- command:执行的命令,必须以 Tab 键 开头。
2. 简单示例
假设有以下源文件:main.c 和 functions.c。
示例 Makefile
1# 变量定义
2CC = gcc
3CFLAGS = -Wall -g
4TARGET = program
5OBJECTS = main.o functions.o
6
7# 默认目标
8all: $(TARGET)
9
10# 编译目标文件
11$(TARGET): $(OBJECTS)
12 $(CC) $(CFLAGS) -o $(TARGET) $(OBJECTS)
13
14# 编译源文件为中间目标 (object 文件)
15main.o: main.c
16 $(CC) $(CFLAGS) -c main.c
17
18functions.o: functions.c
19 $(CC) $(CFLAGS) -c functions.c
20
21# 清理目标
22clean:
23 rm -f $(TARGET) $(OBJECTS)
24
25# 伪目标:不生成文件
26.PHONY: all clean
执行流程
- 执行
make命令:make会查找默认目标all并执行相关依赖规则。
- 编译生成目标文件:
main.c和functions.c会被编译为main.o和functions.o。
- 链接生成最终可执行文件:
- 链接中间文件,生成
program。
- 链接中间文件,生成
- 执行
make clean:- 清理中间文件和目标文件。
3. Makefile 语法详解
3.1 变量
- 使用
=定义变量。 - 使用
$(VAR)引用变量。
1CC = gcc
2CFLAGS = -Wall -g
3.2 自动变量
$@:表示目标文件名。$<:第一个依赖文件。$^:所有依赖文件。
1$(TARGET): $(OBJECTS)
2 $(CC) $(CFLAGS) -o $@ $^
3.3 伪目标 (.PHONY)
- 用于指定不会生成实际文件的目标,如
clean、all。
1.PHONY: clean
2clean:
3 rm -f $(TARGET) $(OBJECTS)
3.4 模式规则
- 通过通配符简化规则,
%表示任意字符。
1%.o: %.c
2 $(CC) $(CFLAGS) -c $< -o $@
表示将所有 .c 文件编译成对应的 .o 文件。
4. Makefile 进阶技巧
4.1 自动搜索依赖
使用 -MMD 选项自动生成依赖文件。
1CFLAGS = -Wall -g -MMD
2-include $(OBJECTS:.o=.d)
4.2 多目标编译
1all: program1 program2
2
3program1: program1.c
4 $(CC) -o program1 program1.c
5
6program2: program2.c
7 $(CC) -o program2 program2.c
4.3 定义函数
使用 define 定义复杂操作。
1define compile
2 $(CC) $(CFLAGS) -c $1.c -o $1.o
3endef
4
5main.o:
6 $(call compile, main)
5. 常用命令总结
| 命令 | 说明 |
|---|---|
make |
执行默认目标(第一个规则) |
make target |
执行指定目标 |
make clean |
执行clean规则 |
make -jN |
并行执行任务,N 表示线程数 |
make -n |
只打印命令,不执行 |
6. 示例执行过程
1# 编译项目
2make
3
4# 执行清理
5make clean
6
7# 使用多线程编译
8make -j4
7. 基本示例
7.1 编译Makefile文件同级目录下的 .c 文件
1# 变量定义
2CC = gcc
3CFLAGS = -Wall -g
4TARGET = program
5
6# 自动查找当前目录下的所有 .c 文件
7SRCS := $(wildcard *.c)
8OBJS := $(SRCS:.c=.o)
9
10# 默认目标
11all: $(TARGET)
12
13# 链接目标文件
14$(TARGET): $(OBJS)
15 $(CC) $(CFLAGS) -o $@ $(OBJS)
16
17# 编译 .c 文件为 .o 文件(模式规则)
18%.o: %.c
19 $(CC) $(CFLAGS) -c $< -o $@
20
21# 清理目标
22clean:
23 rm -f $(TARGET) $(OBJS)
24
25.PHONY: all clean
7.2 编译Makefile文件所在目录及子目录的c文件
1# 变量定义
2CC = gcc
3CFLAGS = -Wall -g
4TARGET = program
5
6# 查找当前目录及所有子目录中的 .c 文件
7SRCS := $(shell find . -name "*.c")
8OBJS := $(SRCS:.c=.o)
9
10# 默认目标
11all: $(TARGET)
12
13# 链接目标文件
14$(TARGET): $(OBJS)
15 $(CC) $(CFLAGS) -o $@ $(OBJS)
16
17# 编译 .c 文件为 .o 文件(模式规则)
18%.o: %.c
19 $(CC) $(CFLAGS) -c $< -o $@
20
21# 清理目标
22clean:
23 rm -f $(TARGET) $(OBJS)
24
25.PHONY: all clean
7.3 多个Makefile编译
- 假设项目目录结构如下:
1project/
2├── Makefile # 顶层 Makefile
3├── main.c
4├── src/
5│ ├── Makefile # src 目录下的 Makefile
6│ ├── func1.c
7│ └── func2.c
8└── lib/
9 ├── Makefile # lib 目录下的 Makefile
10 ├── utils.c
11 └── helper.c
- 顶层
Makefile
顶层 Makefile 负责调用子目录中的 Makefile 并编译整个项目。
1# 变量定义
2SUBDIRS = src lib
3CC = gcc
4CFLAGS = -Wall -g
5TARGET = program
6
7# 默认目标
8all: subdirs $(TARGET)
9
10# 编译主程序
11main.o: main.c
12 $(CC) $(CFLAGS) -c main.c -o main.o
13
14# 链接所有目标文件
15$(TARGET): main.o
16 @echo "Linking target: $(TARGET)"
17 $(CC) $(CFLAGS) -o $(TARGET) main.o src/*.o lib/*.o
18
19# 递归编译子目录
20subdirs:
21 @for dir in $(SUBDIRS); do \
22 echo "Building in $$dir..."; \
23 $(MAKE) -C $$dir; \
24 done
25
26# 清理目标
27clean:
28 @for dir in $(SUBDIRS); do \
29 echo "Cleaning in $$dir..."; \
30 $(MAKE) -C $$dir clean; \
31 done
32 rm -f $(TARGET) main.o
33
34.PHONY: all clean subdirs
- 子目录的
Makefile
s**rc/Makefile**
1CC = gcc
2CFLAGS = -Wall -g
3OBJS = func1.o func2.o
4
5all: $(OBJS)%.o: %.c
6 $(CC) $(CFLAGS) -c $< -o $@
7
8clean:
9 rm -f $(OBJS)
10
11.PHONY: all clean
lib/Makefile
1CC = gcc
2CFLAGS = -Wall -g
3OBJS = utils.o helper.o
4
5all: $(OBJS)%.o: %.c
6 $(CC) $(CFLAGS) -c $< -o $@
7
8clean:
9 rm -f $(OBJS)
10
11.PHONY: all clean
- 工作原理
- 顶层
Makefile:- 定义了子目录
SUBDIRS = src lib。 - 使用
$(MAKE) -C命令进入子目录并执行子目录的Makefile。
- 定义了子目录
- 递归编译:
$(MAKE) -C dir会在dir目录中执行make。- 子目录的
Makefile负责编译自己的.c文件并生成.o文件。
- 主程序链接:
- 在顶层
Makefile中,链接主程序的main.o和子目录生成的所有.o文件,生成最终的可执行文件。
- 在顶层
- 清理目标:
make clean会递归调用子目录的Makefile中的clean目标,删除所有中间文件。
end.