变量赋值
变量赋值
- `VAR = value`:递归/延迟展开(在使用时再展开,适合引用其他变量)。
- `VAR := value`:简单/立即展开(定义时就展开,效率高)。
- `VAR ?= value`:条件赋值,只有变量未定义时才赋值(常用于默认值,如 `ARCH ?= arm`)。
- `VAR += value`:追加(若变量未定义则等同于 `VAR = value`)。
- `override VAR = value`:无视命令行/环境覆盖变量。
- `export VAR` / `export VAR = value`:将变量导出到子 shell/命令。
- `define NAME` ... `endef`:定义多行变量或宏体(可与 `$(call NAME, arg)` 一起使用)。
变量引用
- `$(VAR)` 或 `${VAR}`:引用变量值。注意两者等价,推荐 `$(VAR)`。
- 延迟展开会在实际使用时才替换变量,立即展开则在赋值时替换。
规则
- 语法:
- recipe 行必须以 Tab 字符开头。
- `.PHONY: clean all`:声明伪目标(不对应实际文件)。
- 双冒号规则 `target:: ...`:允许多个独立配方(不常用)。
- order-only 依赖:`target: normal_deps | order_only_deps`,`order_only_deps` 的变化不会触发重建,仅保证存在顺序。
示例:
hello.o: hello.c hello.h
$(CC) -c $< -o $@
规则头 hello.o: hello.c hello.h
目标(target)是 hello.o,依赖(prerequisites)是 hello.c 和 hello.h。
含义:若 hello.o 不存在,或 hello.c/hello.h 比 hello.o 新,make 就会执行配方重建 hello.o。
配方 $(CC) -c $< -o $@ 的含义:
$(CC):使用的编译器(如 gcc,由变量 CC 指定)。
-c:只编译,不链接,生成目标文件(.o)。
$<:自动变量,表示第一个依赖,即 hello.c。
$@:自动变量,表示目标,即 hello.o。
整句就是把 hello.c 编译成 hello.o:相当于 gcc -c hello.c -o hello.o。
模式规则 / 隐式规则
示例: %.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
规则头 %.o: %.c
表示一个模式规则:对任意同名的文件对,匹配 "源.c -> 目标.o" 的转换(例如 foo.c -> foo.o)。
配方 $(CC) $(CFLAGS) -c $< -o $@ 含义:
$(CC):编译器(如 gcc)。
$(CFLAGS):编译选项。
-c:只编译成目标文件,不链接。
$<:自动变量,表示第一个依赖(这里是 foo.c)。
$@:自动变量,表示目标(这里是 foo.o)。
所以整句相当于:把源文件编译成对应的目标文件(例:gcc -c foo.c -o foo.o)。
自动变量(常用)
- `$@`:规则的目标文件名。
- `$<`:第一个依赖(常用于模式规则)。
- `$^`:所有依赖(去重)。
- `$?`:比目标新的依赖列表(用于增量处理)。
条件判断与控制
- `ifeq (a,b)` / `ifneq`:字符串比较(注意空格和引号)。
- `ifdef VAR` / `ifndef VAR`:判断变量是否定义。
- `else` / `endif`:配套使用。条件常用于根据 `ARCH`、`CROSS_COMPILE` 等切换行为。
包含与容错包含
`include filename`:包含其它 Makefile 片段(例如自动生成的依赖文件)。
`-include filename` 或 `sinclude filename`:若文件不存在则忽略,不报错。
函数与内建处理
文本/列表函数:`$(subst from,to,text)`、`$(patsubst pattern,repl,text)`、`$(filter pattern...,text)`、`$(filter-out ...)`。
文件/目录函数:`$(wildcard pattern)`、`$(dir list)`、`$(notdir list)`。
迭代与调用:`$(foreach var, list, text)`、`$(call macro, args...)`(配合 `define` 使用)。
`$(shell cmd)`:执行 shell 命令并将输出作为字符串返回(慎用,频繁调用影响性能)。
目标特定变量与模式特定变量
目标特定:`foo.o: CFLAGS = -O2`(仅对 `foo.o` 有效)。
模式特定:`%.o: CFLAGS = -g`(对匹配规则的目标生效)。
调试与诊断
`make -n`:只显示将执行的命令,不运行。
`make -p`:打印数据库(变量、规则等)。
`make -d`:详细调试输出(非常冗长)。
工程常用 `V=1`、`V=2` 等变量切换命令行详细程度(这是项目约定,不是 GNU make 固有)。
常见约定(U-Boot 风格)
使用 `ARCH`、`CROSS_COMPILE`、`O`(输出目录)、`KBUILD_*` 等变量控制构建。
先构建 host-tools(如 `tools/mkimage`),再构建目标代码。
使用 `if_changed`、`cmd_*`、`quiet_cmd_*` 等宏实现"只在命令变化时执行"的机制,减少不必要重建。
提供 `make <board>_defconfig`、`make menuconfig`、`make u-boot.bin` 等目标,结合 `configs/` 和 `include/configs/` 管理配置。