[Linux] make自动化构建
目录
一.什么是make
二.Makefile结构
2.1 典型结构
2.2 变量
1. 普通变量(User-Defined Variables)
2. 自动变量(Automatic Variables)
3. 预定义变量(Built-in Variables)
4. 函数变量(Functions)
2.3 伪目标
三. 实战解析
一.什么是make
在 Linux 中,make是一个用于自动化构建和编译程序的命令工具,而 Makefile 是make的配置文件,用于定义编译规则、依赖关系和执行步骤。
- 自动化编译:根据
Makefile
中定义的规则,自动完成编译、链接等操作。 - 增量编译:根据文件的修改时间,仅重新编译被修改的文件及其依赖项,提高效率。
- 管理复杂项目:处理多文件、多依赖的大型项目,避免手动编译的繁琐。
[注意事项]
-
make默认仅生成第一个目标,而非所有目标。
-
make通过依赖关系和时间戳自动判断是否需要重新生成。
-
make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到了解释这个文件
二.Makefile结构
2.1 典型结构
target: dependencies
command
- 目标(Target):要生成的文件或伪目标(如
clean
)。 - 依赖(Dependencies):生成目标所需的文件或目标。
- 命令(Commands):必须以 Tab 开头的 Shell 命令。
Makefile一般包含以下五个核心元素:
-
显式规则(显式定义目标及其依赖关系);
-
隐晦规则(隐式规则,由
make
内置推理规则支持); -
变量定义(类似宏的字符串变量);
-
文件指示(如
include
包含其他文件); -
注释(以
#
开头)。
2.2 变量
1. 普通变量(User-Defined Variables)
普通变量由用户自定义,用于存储字符串、路径、编译选项等信息。$符号用于引用已定义的变量,格式为 $(变量名)
或 $
带括号的变量名:
# 定义变量
CC = gcc
CFLAGS = -Wall -g
# 使用变量
all: main
main: main.o utils.o
$(CC) $(CFLAGS) -o $@ $^
2. 自动变量(Automatic Variables)
$后跟特定字符表示自动变量,用于引用目标、依赖等信息:
变量 | 含义 |
---|---|
$@ | 当前目标的完整名称。 |
$< | 当前规则中第一个依赖文件的名称。 |
$^ | 当前规则中所有依赖文件的列表(去重,以空格分隔)。 |
$? | 当前规则中比目标更新的依赖文件的列表(以空格分隔)。 |
$* | 当前目标的“茎”(Stem),即去掉后缀的部分(如 foo.o 的 $* 是 foo )。 |
$(@D) | 目标文件的目录路径(如 dir/file.o 的 $(@D) 是 dir )。 |
$(@F) | 目标文件的文件名(不含目录路径)。 |
$(<D) | 第一个依赖文件的目录路径。 |
$(<F) | 第一个依赖文件的文件名(不含目录路径)。 |
3. 预定义变量(Built-in Variables)
变量 | 默认值 | 用途 |
---|---|---|
CC | cc | C 编译器。 |
CXX | g++ | C++ 编译器。 |
AR | ar | 归档程序(用于生成静态库)。 |
AS | as | 汇编器。 |
CPP | $(CC) -E | C 预处理器。 |
CFLAGS | 空字符串 | C 编译器选项。 |
CXXFLAGS | 空字符串 | C++ 编译器选项。 |
LDFLAGS | 空字符串 | 链接器选项。 |
4. 函数变量(Functions)
$
可用于调用 Makefile 内置函数或特殊语法
(1) 文件名称处理函数
SRCS = $(wildcard src/*.c) # 获取 src/ 目录下所有 .c 文件
OBJS = $(patsubst %.c,%.o,$(SRCS)) # 将 .c 文件替换为 .o
BASE = $(basename test.c) # BASE = test
EXT = $(suffix test.c) # EXT = .c
(2) 控制函数
ifeq ($(OS),Windows_NT)
# Windows 特定配置
else
# 其他系统配置
endif
FILES = a b c
OBJ = $(foreach file,$(FILES),$(file).o)
# OBJ = a.o b.o c.o
2.3 伪目标
.PHONY: clean
clean:
rm -f *.o main
伪目标的特性是,总是被执行的。
三. 实战解析
# 定义变量
BIN=proc.exe # 定义最终生成的可执行文件名
CC=gcc # 定义编译器(gcc)
SRC=$(wildcard *.c) # 使用wildcard函数获取当前目录下所有.c文件的列表
# SRC=$(shell ls *.c) # 注释掉的另一种方法,通过shell命令获取.c文件(与wildcard功能相同)
OBJ=$(SRC:.c=.o) # 将SRC中的所有.c文件名替换为对应的.o文件名(例如:main.c → main.o)
LFLAGS=-o # 定义链接选项(-o用于指定输出文件名)
BFLAGS=-c # 定义编译选项(-c表示仅编译不链接)
RM=rm -f # 定义删除命令(rm -f强制删除)
# 定义生成可执行文件的规则
$(BIN): $(OBJ) # 目标:$(BIN)依赖于所有.o文件
$(CC) $^ $(LFLAGS) $@ # 隐式规则:链接所有.o文件生成$(BIN)
@echo "linking ... $^ to $@" # 输出链接信息($^是所有依赖文件,$@是目标文件名)
# 定义生成.o文件的通用规则(隐式规则)
%.o: %.c # 通配符规则:将每个.c文件编译为对应的.o文件
@$(CC) $(BFLAGS) $< # 编译单个.c文件为.o文件($<是第一个依赖文件,即对应的.c文件)
@echo "compiling ... $< to $@" # 输出编译信息($<是源文件,$@是目标文件)
# 定义伪目标(确保即使存在同名文件也会执行)
.PHONY: clean test # 声明clean和test为伪目标
# 清理生成的文件
clean:
$(RM) $(OBJ) $(BIN) # 删除所有.o文件和可执行文件
# 测试目标(显示变量内容)
test:
@echo $(SRC) # 输出所有.c文件列表
@echo $(OBJ) # 输出所有.o文件列表