单文件程序一行 gcc 就编译完了,项目一变大就难受:几十个源文件,每次都得敲一长串命令,还经常漏编译改过的文件。Makefile 就是解决这个的构建脚本,它让 make 工具自动替你编译、链接、清理。
Makefile 是什么
Makefile 是 make 工具使用的脚本,用来编译和链接程序。它定义一组规则,每条规则说清楚怎么从某些源文件生成某个目标文件。它最大的好处是增量编译:只重新编译那些改动过的文件,其余直接用旧的。
make 在 Linux 大多预装,Windows 上装 GNU Make 官方版就有。
Makefile 的结构
一条规则长这样:
target: dependencies
command- target:要生成的文件(比如 main.o、main)。
- dependencies:生成它需要哪些文件。
- command:具体的编译命令。这一行必须以 Tab 开头,空格不行,这是新手最常见的错误。
还能定义变量,用 $() 引用:
CC = gcc # 编译器
$(CC) -o main main.o一个完整例子
假设项目三个文件:main.c 调函数,function.h 放声明,另外两个 .c 文件放实现。
/* function.h */
#ifndef FUNCTION_H
#define FUNCTION_H
int multiply(int, int);
int factorial(int);
void print();
#endif/* multiply.c */
#include "function.h"
int multiply(int a, int b) { return a * b; }/* factorial.c */
#include "function.h"
int factorial(int n) {
if (n == 1)
return 1;
return n * factorial(n - 1);
}/* main.c */
#include <stdio.h>
#include "function.h"
int main() {
printf("%d\n", multiply(2, 3));
printf("%d\n", factorial(5));
print();
return 0;
}传统方式编译,要一条条敲:
gcc -c main.c
gcc -c multiply.c
gcc -c factorial.c
gcc -o main main.o multiply.o factorial.o
./main项目小还好,文件一多就抓狂。用 Makefile 接管:
# 编译器
CC = gcc
# 编译选项:开全警告、带调试信息
CFLAGS = -Wall -g
# 目标可执行文件
TARGET = main
# 源文件
SRCS = main.c multiply.c factorial.c
# 把 .c 换成 .o
OBJS = $(SRCS:.c=.o)
# 默认目标:编译并运行
all: $(TARGET) run
# 链接:把 .o 合成可执行文件
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $(TARGET) $(OBJS)
# 通用规则:任何 .o 由同名 .c 编译而来
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# 运行
run: $(TARGET)
./$(TARGET)
# 清理生成的文件
clean:
del $(TARGET).exe $(OBJS)然后在命令行执行:
makemake 会按规则生成 main。中途如果你改了 multiply.c,再跑 make 只会重编译 multiply.o,其他文件跳过,这就是增量编译的价值。
清理生成物:
make clean几个要记住的点
- Tab 开头:规则里的命令行必须是 Tab,这是 Makefile 语法铁律。
- 自动变量:
$@是当前目标,$<是第一个依赖,$^是所有依赖。 - 第一个规则是默认目标:直接敲
make就执行它。 - 模块化:头文件、源文件、编译产物分目录放,项目更清爽。
Makefile 好在哪
- 编译命令集中管理,不用每次手敲一大串。
- 改一个文件只重编译相关部分,大项目省大量时间。
- 项目结构很清楚:怎么编译、怎么清理都写清楚了。
等你开始写多个文件的项目,Makefile 就是第一个值得学起来的构建工具。