GNU Make 4.4.1 官方手册(Edition 0.77, 2023年2月26日更新)
目录
- 概述
- [Makefile 入门](#Makefile 入门)
- [编写 Makefile](#编写 Makefile)
- 编写规则
- 编写配方
- 使用变量
- 条件判断
- 文本变换函数
- [运行 make](#运行 make)
- 隐式规则
- 附录:快速参考
1. 概述
1.1 什么是 Make
make 是一个自动构建工具,它能够自动确定大型程序中哪些部分需要重新编译,并执行相应的命令来完成编译。GNU make 由 Richard Stallman 和 Roland McGrath 实现,3.76 版本之后由 Paul D. Smith 维护。
GNU make 遵循 IEEE 标准 1003.2-1992 (POSIX.2) 第 6.2 节。
虽然本文示例使用 C 语言,但 make 适用于任何可以通过 shell 命令运行编译器的编程语言。实际上,make 不限于程序编译------它可以描述任何需要根据文件变化自动更新其他文件的任务。
1.2 如何阅读本手册
- 如果你对 make 完全陌生,从第 2 章开始阅读
- 如果你有经验,可以直接跳到相关章节
- 附录 A 提供了快速参考
2. Makefile 入门
2.1 规则长什么样
一个简单的 makefile 由"规则"组成,格式如下:
makefile
目标 ... : 前置条件 ...
配方
...
- 目标(target) :通常是程序生成的文件名(如可执行文件或目标文件),也可以是某个动作的名称(如
clean) - 前置条件(prerequisite):作为输入来创建目标的文件
- 配方(recipe) :make 执行的动作。注意:每个配方行必须以 Tab 字符开头!
2.2 一个简单的 Makefile 示例
以下 makefile 描述了一个名为 edit 的可执行文件如何依赖于 8 个目标文件,而这些目标文件又依赖于 8 个 C 源文件和 3 个头文件:
makefile
edit : main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
main.o : main.c defs.h
cc -c main.c
kbd.o : kbd.c defs.h command.h
cc -c kbd.c
command.o : command.c defs.h command.h
cc -c command.c
display.o : display.c defs.h buffer.h
cc -c display.c
insert.o : insert.c defs.h buffer.h
cc -c insert.c
search.o : search.c defs.h buffer.h
cc -c search.c
files.o : files.c defs.h buffer.h command.h
cc -c files.c
utils.o : utils.c defs.h
cc -c utils.c
clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
使用方式:
make--- 构建可执行文件editmake clean--- 删除所有编译产物
2.3 Make 如何处理 Makefile
默认情况下,make 从第一个目标(称为默认目标)开始处理:
- 读取当前目录的 makefile
- 处理第一个规则(通常是链接可执行文件)
- 在处理第一个规则之前,先处理其所有前置条件的规则
- 对于每个
.o文件,检查源文件和头文件是否比目标文件更新 - 如果任何前置条件更新了,则重新编译
- 最后,如果任何目标文件被重新编译,则重新链接可执行文件
2.4 使用变量简化 Makefile
使用变量可以避免重复列出文件:
makefile
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
edit : $(objects)
cc -o edit $(objects)
main.o : main.c defs.h
cc -c main.c
# ... 其他规则类似
clean :
rm edit $(objects)
3. 编写 Makefile
3.1 Makefile 包含的内容
Makefile 包含五种内容:
- 显式规则 --- 说明何时以及如何重新生成一个或多个文件
- 隐式规则 --- 根据文件名自动推断如何重新生成一类文件
- 变量定义 --- 为变量指定文本字符串值
- 指令 --- 让 make 在读取 makefile 时做特殊处理(如包含其他 makefile、条件判断、定义多行变量)
- 注释 --- 以
#开头
3.2 Makefile 的命名
make 按以下顺序查找 makefile:
GNUmakefilemakefileMakefile
推荐使用 Makefile。GNUmakefile 只在你的 makefile 特定于 GNU make 时使用。
使用 -f 选项可以指定其他文件名:
bash
make -f mymakefile
3.3 包含其他 Makefile
makefile
include filenames...
- 支持通配符
- 搜索路径:
-I选项指定的目录 →/usr/local/include→/usr/include -include或sinclude在文件不存在时不会报错
示例:
makefile
include foo *.mk $(bar)
3.4 拆分长行
使用反斜杠加换行符来拆分长行:
makefile
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o
4. 编写规则
4.1 规则语法
makefile
目标 : 前置条件
配方
- 规则顺序不重要,除非是确定默认目标
- 默认目标是第一个 makefile 中第一个规则的目标
- 以
.开头的目标不作为默认目标(除非包含/)
4.2 前置条件的类型
GNU make 支持两种前置条件:
- 普通前置条件:如果比目标新,则触发重新构建
- 仅顺序前置条件(order-only) :用
|分隔,仅确保它们存在,不触发重新构建
makefile
目标 : 普通前置条件 | 仅顺序前置条件
4.3 通配符
支持 shell 风格的通配符:*、?、[...]
makefile
clean:
rm -f *.o
注意 :通配符在目标和前置条件中自动展开,在配方中由 shell 展开,在其他上下文中需要使用 $(wildcard ...) 函数。
~ 表示家目录:~/bin、~john/bin
4.4 目录搜索(VPATH)
使用 VPATH 变量或 vpath 指令来搜索前置条件:
makefile
VPATH = src:../headers
或更精确的:
makefile
vpath %.c src
vpath %.h ../headers
4.5 伪目标(Phony Targets)
伪目标不是文件名,而是动作的名称。使用 .PHONY 声明:
makefile
.PHONY: clean
clean:
rm -f *.o
常见用法:
all--- 构建所有程序clean--- 清理- 递归调用子目录 make
4.6 静态模式规则
makefile
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
4.7 双冒号规则
双冒号规则允许同一个目标有多个规则,每个规则有自己的配方:
makefile
目标 :: 前置条件
配方
4.8 自动生成前置条件
使用编译器的 -M 选项自动生成依赖关系:
makefile
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
然后包含生成的 .d 文件:
makefile
sources = foo.c bar.c
include $(sources:.c=.d)
5. 编写配方
5.1 配方语法
配方由一行或多行 shell 命令组成,每行必须以 Tab 开头(或 .RECIPEPREFIX 指定的字符)。
5.2 配方回显
- 默认情况下,make 在执行前打印每行命令
- 在命令前加
@可以禁止回显:@echo "Building..."
5.3 配方执行
- 每行配方在独立的 shell 进程中执行
- 可以使用
.ONESHELL让所有行在同一个 shell 中执行 - 可以通过
SHELL变量指定 shell
5.4 并行执行
使用 -j 选项:
bash
make -j4 # 同时执行 4 个任务
make -j # 不限数量的并行任务
make -l 2.5 # 负载平均值超过 2.5 时不启动新任务
5.5 配方错误处理
- 在命令前加
-忽略错误:-rm -f *.o -i或--ignore-errors忽略所有错误-k或--keep-going出错后继续构建其他目标.DELETE_ON_ERROR让 make 在配方失败时删除目标文件
5.6 递归使用 Make
在子目录中调用 make:
makefile
subsystem:
cd subdir && $(MAKE)
或:
makefile
subsystem:
$(MAKE) -C subdir
重要 :始终使用 $(MAKE) 而非 make,这样能正确传递标志和变量。
5.7 定义罐头配方
使用 define 定义可重用的配方:
makefile
define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef
foo.c: foo.y
$(run-yacc)
6. 使用变量
6.1 变量引用基础
使用 $(变量名) 或 ${变量名} 引用变量:
makefile
objects = program.o foo.o utils.o
program : $(objects)
cc -o program $(objects)
- 变量名区分大小写:
foo、FOO、Foo是不同的变量 - 单字符变量可以省略括号:
$x,但推荐使用括号 $$表示一个字面量$
6.2 变量的两种风格
6.2.1 递归展开变量(=)
值在每次使用时才展开:
makefile
foo = $(bar)
bar = $(ugh)
ugh = Huh?
# $(foo) 最终展开为 "Huh?"
优点:可以后定义引用的变量
缺点:不能追加自身(会导致无限循环),函数每次使用时都会重新执行
6.2.2 简单展开变量(:= 或 ::=)
值在定义时立即展开:
makefile
x := foo
y := $(x) bar
x := later
# y 的值是 "foo bar"(定义时的值)
优点:可预测,性能好,可以追加自身
6.2.3 立即展开变量(:::=)
立即展开但结果是递归变量(值中的 $ 被转义为 $$):
makefile
var = first
OUT :::= $(var)
var = second
# OUT 的值是 "first",但作为递归变量
6.2.4 条件赋值(?=)
只在变量未定义时赋值:
makefile
FOO ?= bar
# 等价于:
ifeq ($(origin FOO), undefined)
FOO = bar
endif
6.3 设置变量
makefile
# 递归展开
变量 = 值
# 简单展开
变量 := 值
# 立即展开(递归结果)
变量 :::= 值
# 条件赋值
变量 ?= 值
# 追加
变量 += 值
6.4 追加文本
makefile
objects = main.o
objects += foo.o
# objects 现在是 "main.o foo.o"
6.5 Override 指令
覆盖命令行传入的变量:
makefile
override CFLAGS += -g
6.6 多行变量
makefile
define two-lines
echo foo
echo $(bar)
endef
6.7 环境变量
- make 启动时自动导入环境变量
- 可以使用
-e选项让环境变量覆盖 makefile 中的变量 - 使用
export将变量传递给子进程
6.8 目标特定变量
makefile
prog : CFLAGS = -g
prog : prog.o foo.o
$(CC) $(CFLAGS) -o prog prog.o foo.o
6.9 模式特定变量
makefile
%.o : CFLAGS = -O2
6.10 自动变量
在配方中使用的特殊变量,由 make 自动设置:
| 变量 | 含义 |
|---|---|
$@ |
目标文件名 |
$% |
归档成员名(当目标是归档文件时) |
$< |
第一个前置条件 |
$? |
所有比目标新的前置条件 |
$^ |
所有前置条件(去重) |
$+ |
所有前置条件(不去重) |
| `$ | ` |
$* |
模式规则匹配的"茎"(stem) |
目录变体(追加 D 或 F):
$(@D)--- 目标的目录部分$(@F)--- 目标的文件名部分$(<D)--- 第一个前置条件的目录部分$(<F)--- 第一个前置条件的文件名部分- 以此类推:
$(*D)、$(*F)、$(^D)、$(^F)、$(?D)、$(?F)
7. 条件判断
7.1 条件示例
makefile
ifeq ($(CC),gcc)
$(CC) -o foo $(objects) $(libs_for_gcc)
else
$(CC) -o foo $(objects) $(normal_libs)
endif
7.2 条件语法
makefile
conditional-directive
text-if-true
else
text-if-false
endif
支持的指令:
| 指令 | 说明 |
|---|---|
ifeq (arg1, arg2) |
如果相等则为真 |
ifneq (arg1, arg2) |
如果不相等则为真 |
ifdef variable-name |
如果变量已定义(非空)则为真 |
ifndef variable-name |
如果变量未定义(为空)则为真 |
注意 :ifdef 只检查变量是否被定义,不展开变量值。foo = 被认为是空,但 foo = $(bar) 即使 bar 为空也被认为是已定义。
7.3 测试标志
makefile
ifeq ($(findstring clean,$(MAKECMDGOALS)),clean)
# 如果目标是 clean
endif
8. 文本变换函数
8.1 函数调用语法
makefile
$(函数名 参数1,参数2,...)
${函数名 参数1,参数2,...}
8.2 字符串替换和分析函数
$(subst from,to,text)
替换文本中的子串:
makefile
$(subst ee,EE,feet on the street)
# 结果:fEEt on the strEEt
$(patsubst pattern,replacement,text)
模式替换(% 通配):
makefile
$(patsubst %.c,%.o,x.c.c bar.c)
# 结果:x.c.o bar.o
替换引用(简化写法):
makefile
$(var:.o=.c) # 等价于 $(patsubst %.o,%.c,$(var))
$(var:pattern=replacement) # 等价于 $(patsubst pattern,replacement,$(var))
$(strip string)
去除首尾空白,合并内部空白:
makefile
$(strip a b c )
# 结果:a b c
$(findstring find,in)
查找子串:
makefile
$(findstring a,a b c) # 结果:a
$(findstring a,b c) # 结果:(空)
$(filter pattern...,text)
筛选匹配模式的单词:
makefile
sources := foo.c bar.c baz.s ugh.h
$(filter %.c %.s,$(sources))
# 结果:foo.c bar.c baz.s
$(filter-out pattern...,text)
筛选不匹配模式的单词:
makefile
$(filter-out $(mains),$(objects))
$(sort list)
排序并去重:
makefile
$(sort foo bar lose)
# 结果:bar foo lose
$(word n,text)
取第 n 个单词(从 1 开始):
makefile
$(word 2, foo bar baz)
# 结果:bar
$(wordlist s,e,text)
取单词范围:
makefile
$(wordlist 2, 3, foo bar baz)
# 结果:bar baz
$(words text)
单词计数:
makefile
$(words foo bar baz)
# 结果:3
$(firstword names...)
取第一个单词:
makefile
$(firstword foo bar)
# 结果:foo
$(lastword names...)
取最后一个单词:
makefile
$(lastword foo bar)
# 结果:bar
8.3 文件名函数
$(dir names...)
提取目录部分:
makefile
$(dir src/foo.c hacks)
# 结果:src/ ./
$(notdir names...)
提取文件名部分:
makefile
$(notdir src/foo.c hacks)
# 结果:foo.c hacks
$(suffix names...)
提取后缀:
makefile
$(suffix src/foo.c src-1.0/bar.c hacks)
# 结果:.c .c
$(basename names...)
提取基本名(去掉后缀):
makefile
$(basename src/foo.c src-1.0/bar hacks)
# 结果:src/foo src-1.0/bar hacks
$(addsuffix suffix,names...)
添加后缀:
makefile
$(addsuffix .c,foo bar)
# 结果:foo.c bar.c
$(addprefix prefix,names...)
添加前缀:
makefile
$(addprefix src/,foo bar)
# 结果:src/foo src/bar
$(join list1,list2)
连接两个列表(逐词):
makefile
$(join a b,.c .o)
# 结果:a.c b.o
$(wildcard pattern)
通配符匹配(返回存在的文件):
makefile
$(wildcard *.c)
$(realpath names...)
获取规范绝对路径(解析符号链接):
makefile
$(realpath foo.c)
$(abspath names...)
获取绝对路径(不解析符号链接):
makefile
$(abspath foo.c)
8.4 条件函数
$(if condition,then-part[,else-part])
makefile
$(if $(wildcard foo.c),foo.c,)
$(or condition1[,condition2...])
返回第一个非空值。
$(and condition1[,condition2...])
如果所有条件都非空,返回最后一个条件的值。
$(intcmp lhs,rhs[,lt-part[,eq-part[,gt-part]]])
数值比较。
8.5 $(foreach var,list,text)
循环展开:
makefile
dirs := a b c d
files := $(foreach dir,$(dirs),$(wildcard $(dir)/*))
8.6 $(call var,param,...)
调用用户定义的函数:
makefile
reverse = $(2) $(1)
foo = $(call reverse,a,b)
# foo 的值:b a
8.7 $(shell command)
执行 shell 命令并返回输出:
makefile
contents := $(shell cat foo)
files := $(shell echo *.c)
8.8 $(error text...) 和 $(warning text...)
makefile
ifndef CONFIG_FILE
$(error CONFIG_FILE is not set)
endif
$(warning This is a warning)
8.9 $(origin variable)
返回变量来源的描述:
undefined--- 未定义default--- 默认定义environment--- 环境变量file--- makefile 中定义command line--- 命令行定义override--- override 指令automatic--- 自动变量makefile--- makefile 中定义
8.10 $(eval text)
将文本作为 makefile 语法求值:
makefile
$(eval $(call program-variable,foo))
9. 运行 Make
9.1 指定 Makefile
bash
make -f mymakefile
make --file=mymakefile
9.2 指定目标
bash
make clean # 构建 clean 目标
make all install # 构建 all 和 install
9.3 替代执行
bash
make -n # 只打印命令,不执行(dry-run)
make -t # touch 目标文件
make -q # 检查是否过时(不执行)
9.4 避免重新编译
bash
make -o main.o # 假装 main.o 没有过时
9.5 覆盖变量
bash
make CFLAGS="-O2 -g"
make CC=gcc-12
9.6 选项汇总
| 选项 | 说明 |
|---|---|
-B, --always-make |
无条件重新构建所有目标 |
-C dir |
切换到目录 dir |
-d |
打印调试信息 |
--debug[=选项] |
调试选项:a(全部), b(基本), v(详细), i(隐式规则), j(作业), m(makefile), p(打印配方), w(原因) |
-e |
环境变量覆盖 makefile 变量 |
-f file |
指定 makefile |
-i |
忽略所有错误 |
-I dir |
搜索包含文件的目录 |
-j [N] |
并行执行 N 个任务 |
-k |
出错后继续 |
-l [负载] |
负载限制 |
-L |
检查符号链接时间戳 |
-n |
只打印不执行 |
-o file |
假装文件未过时 |
-O[类型] |
输出同步:target, line, recurse, none |
-p |
打印数据库 |
-q |
问题模式 |
-r |
不使用内置隐式规则 |
-R |
不使用内置变量 |
-s |
静默模式 |
-S |
取消 -k |
--shuffle[=模式] |
随机化构建顺序(测试依赖完整性) |
-t |
touch 目标 |
--trace |
跟踪信息 |
-v |
版本信息 |
-w |
打印工作目录 |
-W file |
假装文件已修改 |
9.7 退出状态
- 0 --- 成功
- 1 ---
-q模式下目标不是最新的 - 2 --- 发生错误
10. 隐式规则
10.1 使用隐式规则
隐式规则(隐含规则)让 make 自动推断如何从一种文件生成另一种文件。例如,make 知道如何从 .c 文件生成 .o 文件:
makefile
foo.o: foo.c # 不需要写配方,make 会自动使用 cc -c
10.2 内置规则目录
GNU make 内置了大量隐式规则,包括:
- C 编译:
%.o : %.c→$(CC) -c $(CPPFLAGS) $(CFLAGS) - C++ 编译:
%.o : %.cc→$(CXX) -c $(CPPFLAGS) $(CXXFLAGS) - 汇编:
%.o : %.s→$(AS) $(ASFLAGS) - 链接:
% : %.o→$(CC) $(LDFLAGS) ... - 更多:Fortran、Pascal、Yacc、Lex、RCS、SCCS 等
10.3 隐式规则使用的变量
| 变量 | 默认值 | 说明 |
|---|---|---|
CC |
cc |
C 编译器 |
CXX |
g++ |
C++ 编译器 |
CFLAGS |
(空) | C 编译器标志 |
CXXFLAGS |
(空) | C++ 编译器标志 |
CPPFLAGS |
(空) | 预处理器标志 |
LDFLAGS |
(空) | 链接器标志 |
LDLIBS |
(空) | 链接库 |
AR |
ar |
归档工具 |
ARFLAGS |
rv |
归档标志 |
AS |
as |
汇编器 |
ASFLAGS |
(空) | 汇编器标志 |
RM |
rm -f |
删除命令 |
10.4 隐式规则链
make 可以链接多个隐式规则。例如,从 .y(Yacc)文件生成 .o 文件:
.y → .c → .o
10.5 模式规则
模式规则是定义隐式规则的主要方式:
makefile
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
%通配符匹配任意非空子串- 匹配的部分称为"茎"(stem),可通过
$*访问
模式规则示例
makefile
# 从 .c 编译到 .o
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
# 从 .y 编译到 .c
%.c : %.y
$(YACC) $(YFLAGS) $<
mv y.tab.c $@
匹配任意模式规则
makefile
% : %.c
$(CC) $(CFLAGS) $< -o $@
取消隐式规则
定义一个没有配方的模式规则来取消内置规则:
makefile
%.o : %.c
10.6 最后手段规则
当没有其他规则可用时使用:
makefile
.DEFAULT:
@echo "Don't know how to make $@"
10.7 后缀规则(旧式)
旧式隐式规则定义方式,保留用于兼容性:
makefile
.c.o:
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
等价于模式规则 %.o : %.c。
附录:快速参考
指令汇总
| 指令 | 说明 |
|---|---|
define variable / endef |
定义多行变量 |
undefine variable |
取消变量定义 |
ifdef / ifndef / ifeq / ifneq / else / endif |
条件判断 |
include / -include / sinclude |
包含其他 makefile |
override variable-assignment |
覆盖变量 |
export / unexport |
控制变量导出 |
private |
禁止变量继承 |
vpath pattern path |
设置搜索路径 |
特殊目标
| 目标 | 说明 |
|---|---|
.PHONY |
声明伪目标 |
.SUFFIXES |
后缀列表 |
.DEFAULT |
默认规则 |
.PRECIOUS |
保留中间文件 |
.INTERMEDIATE |
中间文件 |
.SECONDARY |
二级文件 |
.SECONDEXPANSION |
启用二次展开 |
.DELETE_ON_ERROR |
出错时删除目标 |
.IGNORE |
忽略错误 |
.LOW_RESOLUTION_TIME |
低精度时间 |
.SILENT |
静默模式 |
.EXPORT_ALL_VARIABLES |
导出所有变量 |
.NOTPARALLEL |
禁止并行 |
.ONESHELL |
单 shell 执行 |
.POSIX |
POSIX 兼容模式 |
.WAIT |
等待前置条件完成 |
.NOEXPORT |
禁止导出 |
特殊变量
| 变量 | 说明 |
|---|---|
MAKEFILES |
每次调用 make 时读取的 makefile |
VPATH |
目录搜索路径 |
SHELL |
shell 程序(默认 /bin/sh) |
MAKE |
make 命令名 |
MAKE_VERSION |
make 版本号 |
MAKE_HOST |
构建主机 |
MAKELEVEL |
递归层级 |
MAKEFLAGS |
make 标志 |
GNUMAKEFLAGS |
GNU make 特定标志 |
MAKECMDGOALS |
命令行目标 |
CURDIR |
当前工作目录 |
SUFFIXES |
默认后缀列表 |
.LIBPATTERNS |
库搜索模式 |
.RECIPEPREFIX |
配方前缀字符(默认 Tab) |
.VARIABLES |
所有变量列表 |
.FEATURES |
可用功能列表 |
.INCLUDE_DIRS |
包含搜索目录 |
.EXTRA_PREREQS |
额外前置条件 |
.SHELLSTATUS |
上次 shell 函数退出状态 |
函数汇总
| 函数 | 说明 |
|---|---|
$(subst from,to,text) |
替换子串 |
$(patsubst pattern,replacement,text) |
模式替换 |
$(strip string) |
去除空白 |
$(findstring find,in) |
查找子串 |
$(filter pattern...,text) |
筛选匹配 |
$(filter-out pattern...,text) |
筛选不匹配 |
$(sort list) |
排序去重 |
$(word n,text) |
取第 n 个单词 |
$(words text) |
单词计数 |
$(wordlist s,e,text) |
取单词范围 |
$(firstword names...) |
第一个单词 |
$(lastword names...) |
最后一个单词 |
$(dir names...) |
目录部分 |
$(notdir names...) |
文件名部分 |
$(suffix names...) |
后缀 |
$(basename names...) |
基本名 |
$(addsuffix suffix,names...) |
添加后缀 |
$(addprefix prefix,names...) |
添加前缀 |
$(join list1,list2) |
连接列表 |
$(wildcard pattern) |
通配符匹配 |
$(realpath names...) |
规范路径 |
$(abspath names...) |
绝对路径 |
$(error text...) |
致命错误 |
$(warning text...) |
警告 |
$(info text...) |
信息 |
$(shell command) |
执行 shell 命令 |
$(origin variable) |
变量来源 |
$(flavor variable) |
变量风格 |
$(let var...,words,text) |
绑定变量 |
$(foreach var,list,text) |
循环 |
$(if condition,then,else) |
条件 |
$(or condition...) |
逻辑或 |
$(and condition...) |
逻辑与 |
$(intcmp lhs,rhs,lt,eq,gt) |
数值比较 |
$(call var,params...) |
调用用户函数 |
$(eval text) |
求值 |
$(file op filename,text) |
文件操作 |
$(value var) |
原始值 |