在 Makefile 中,$ 是转义/引用符号,专门用于触发变量展开和函数调用。它本身不是运算符,而是告诉 Make:"后面的内容是变量名或函数,请替换为实际值"。
| 语法 | 含义 | 示例 |
|---|---|---|
$(VAR) | 引用变量值 | $(WHEREAMI) → bldc/ |
${VAR} | 同上(另一种括号风格) | ${ROOT_DIR} |
$@ $< | 单字符自动变量 | $@ = 目标名 |
$(func args) | 调用内置函数 | $(dir path) |
$$ | 转义为字面量 $ | $$VAR → 文本 $VAR |
为什么需要括号?
# 无括号:只能引用单字符变量
$a # 变量 a(单个字母)
# 有括号:引用多字符变量
$(WHEREAMI) # 变量 WHEREAMI
# 混合场景
$ab # 歧义:变量 a 后面跟字母 b?
# Make 解析为:$(a)b
$(ab) # 明确:变量 ab
WHEREAMI := $(dir $(lastword $(MAKEFILE_LIST)))
# ↑ ↑ ↑
# │ │ └─ 函数调用,需要 $(
# │ └─ 函数调用,需要 $(
# └─ 整个表达式用 $() 包裹
$(1)_BUILD_MACROS = -DHW_SOURCE=\"$$($(1)_HW_SRC_FILE)\"
# ↑
# └─ $$ 转义:最终输出文本 $,不是变量引用
# 用于生成 shell 命令中的字面量 $
$$ 的特殊用途
define FW_TEMPLATE
fw_$(1)_vescfw:
@echo "Building $(1)"
$(V1) $(MAKE) build_args='-DVAR=\"$$VALUE\"'
# ↑↑
# 这里需要输出 $VALUE 给 shell
# 但 Make 会先解析一层
# $$ → 保留一个 $ 给下游
endef
展开过程:
Make 解析阶段:
$$ → 替换为单个 $
最终传递给 shell 的命令:
-DVAR="$VALUE"
# 这里的 $VALUE 是 shell 变量,不是 Make 变量
对比其他语言
| 语言 | 变量引用符号 |
|---|---|
| Shell | $VAR 或 ${VAR} |
| Makefile | $(VAR) 或 ${VAR} 或 $@ |
| Python | 无符号,直接写变量名 |
| C | 无符号,标识符即变量 |
| Perl | $VAR |
| PHP | $VAR |
Makefile 的 $ 设计受 Shell 影响,但强制用 () 包裹以区分多字符变量。
总结
$= "Make,请展开后面的变量或函数"
没有 $,Make 把内容当纯文本;有 $,触发替换机制。$$ 则是"我要一个字面量的 $,留给下游程序用"。