Makefile自动变量浅析

Makefile中的自动变量是在规则命令执行时,由“make” 自动填充的变量。它们代表了当前规则中的特定目标或依赖,让你无需重复写出冗长的文件名,使规则变得通用和简洁。

1. `$@` (Target)

代表当前规则的目标。这是最常用的变量。

例:

output/main.o: src/main.c src/common.h

gcc -c $< -o $@ # 相当于:gcc -c src/main.c -o output/main.o

2. `$<` (First Prerequisite)

代表第一个依赖。在从 `.c` 编译 `.o` 的规则中,它一般就是源文件。

例:

%.o: %.c

gcc -c $< -o $@ # 对于 `foo.o: foo.c`,$< 就是 `foo.c`

3. `$^` 与 `$+` (All Prerequisites)

– `$^`:所有依赖,去重。这是最安全、最常用的选择。

– `$+`:所有依赖,保留原顺序和重复项。用于某些特殊场景(如需要重复链接某个库)。

例:

假设:myapp: foo.o bar.o foo.o (依赖中 foo.o 出现两次)

myapp: foo.o bar.o foo.o

gcc $^ -o $@ # 链接命令实际为:gcc foo.o bar.o -o myapp (去重)

gcc $+ -o $@ # 链接命令实际为:gcc foo.o bar.o foo.o -o myapp (保留重复)

4. `$?` (Newer Prerequisites)

代表所有比目标文件更新的依赖文件。常用于只想重新编译发生变化的文件。

例:

lib.a: foo.o bar.o baz.o

ar rcs $@ $? # 只有当 foo.o, bar.o, baz.o 中有比 lib.a 新的时,才将其加入库

5. `$*` (Stem)

在模式规则 (`%`) 中,代表与模式匹配的部分(“词干”)。

例:

# 规则:将任意 .c 文件编译为对应的 .o 文件

%.o: %.c

gcc -c $< -o $@ # 对于 `test.o: test.c`,$* 就是 `test`

echo “正在编译词干为 $* 的文件” # 会输出:正在编译词干为 test 的文件

6. `$%` (Archive Member)

专门用于归档文件(静态库) 规则。

例:

# 规则:将对象文件 bar.o 加入归档库 foo.a

foo.a(bar.o): bar.o

ar rv $@ $% # 相当于:ar rv foo.a bar.o

最佳实践与常见陷阱

1.习惯使用自动变量:它们能让你的 `makefile` 更短、更通用、更易于维护。

2.为命令加上 `@` 前缀:在命令前加 `@`(如 `@echo “编译 $@”`)可以阻止 `make` 回显该命令本身,让输出更干净。

3.注意变量与普通文本的区分:`$` 是特殊符号。如果你需要在命令中使用真正的美元符号,需要用 `$$` 进行转义。

4.小心空格:自动变量代表的是一个完整的词(文件名),不会有前导或尾随空格。

5.`$<` 在显式规则和隐式规则中的区别:在显式规则中,`$<` 是第一个依赖;在隐含规则(如 `.c.o:`)中,它代表添加了后缀的依赖名。

一个综合示例

# 定义编译器和标志

CC = gcc

CFLAGS = -Wall -I./include

# 最终目标

TARGET = myapp

OBJS = main.o utils.o parser.o

# 链接:使用 $^ 代表所有对象文件

$(TARGET): $(OBJS)

$(CC) $^ -o $@

@echo “程序 $@ 构建成功!”

# 编译:模式规则,使用 $< 和 $@

%.o: src/%.c

$(CC) $(CFLAGS) -c $< -o $@

# 清理:使用 $(RM)是良好习惯,由于不同系统的 rm 命令可能不同

clean:

$(RM) $(OBJS) $(TARGET)

.PHONY: clean

© 版权声明

相关文章

暂无评论

none
暂无评论...