- addprefix函数
函数名称:加前缀函数—addprefix
返回值:以单空格分割的添加了前缀“PREFIX”的文件名序列。
示例:
$(addprefix src/,foo bar)
回值为“src/foo src/bar”
- wildcard即通配符,通常包括?以及*
$(wildcard PATTERN)
src=main.
chap-dir=chapters
tmp-suffix = aux log out toc
tmp-files = $(addprefix ${src}, ${tmp-suffix})
tmp-files += $(wildcard $(addprefix ${chap-dir}/, ${tmp-suffix}))
倒数第二句将 main. 作为前缀分别添加到aux log out toc,于是展开得到 main.aux main.log main.out main.toc。
最后一句首先将 chapters/ 添加到 aux log out toc 前,展开后得到 chapters/*aux chapters/*log chapters/*out chapters/*toc。之后 wildcard 函数将得到匹配此模式的所有文件列表,即得到 chapters 目录下所有满足上述四种文件类型的文件名。
参考
- patsubst: 替换通配符(pattern substitute)
src=$(wildcard *.c */*.c */*/*.c)
dir=$(notdir $(src))
obj=$(patsubst %.c, %.o, $(src))
all:
@echo $(src)
@echo $(dir)
@echo $(obj)
@echo "end"
#第一句话获取了当前目录及子目录下所有的匹配 .c 的文件名(包括路径)。如果目录深度增加的话,加 */ 即可。
#第二句去除了或者文件名的路径信息。
#第三句则是从第一句匹配到的字符串里将 .c 换成了 .o
- call函数是唯一一个可以用来创建新的参数化的函数。
$(call <expression>;,<parm1>;,<parm2>;,<parm3>;...)
reverse = $(1) $(2)
foo = $(call reverse,a,b)
那么,foo的值就是“a b”。当然,参数的次序是可以自定义的,不一定是顺序的,如:
reverse = $(2) $(1)
foo = $(call reverse,a,b)
此时的foo的值就是“b a”。
- foreach作为makefile中的函数,相当于一个循环函数。
$(foreach var, list, text)
前两个参数var和list,参数中的单词逐一取出放到参数所指定的变量中,然后再执行所包含的表达式。每一次会返回一个字符串,循环过程中,的所返回的每个字符串会以空格分隔,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串(以空格分隔)将会是foreach函数的返回值。
所以,最好是一个变量名,可以是一个表达式,而中一般会使用这个参数来依次枚举中的单词。
names := a b c d
files := $(foreach n,$(names),$(n).o)
上面的例子中,$(name)中的单词会被挨个取出,并存到变量“n”中,“$(n).o”每次根据“$(n)”计算出一个值,这些值以空格分隔,最后作为foreach函数的返回,所以,$(files)的值是“a.o b.o c.o d.o”。
- eval函数
eval函数可以通过其他变量或函数的结果来定义新的makefile结构。Eval的参数被按照makefile的语法格式展开。展开的结果可以用来构造新的变量、目标、隐式或者显式规则。
PROGRAMS = server client
server_OBJS = server.o server_priv.o server_access.o
server_LIBS = priv protocol
client_OBJS = client.o client_api.o client_mem.o
client_LIBS = protocol
# Everything after this is generic
.PHONY: all
all: $(PROGRAMS)
define PROGRAM_template =
$(1): $$($(1)_OBJS) $$($(1)_LIBS:%=-l%)
ALL_OBJS += $$($(1)_OBJS)
endef
$(foreach prog,$(PROGRAMS),$(eval $(call PROGRAM_template,$(prog))))
$(PROGRAMS):
$(LINK.o) $^ $(LDLIBS) -o $@
clean:
rm -f $(ALL_OBJS) $(PROGRAMS)
- 自动变量
$@:$@指代当前目标
$<:$< 指代第一个前置条件。
$?:$? 指代比目标更新的所有前置条件,之间以空格分隔。
$^:$^ 指代所有前置条件,之间以空格分隔。
$*:$* 指代匹配符 % 匹配的部分, 比如% 匹配 f1.txt 中的f1 ,$* 就表示 f1。
$(@D) 和 $(@F):$(@D) 和 $(@F) 分别指向 $@ 的目录名和文件名。比如,$@是 src/input.c,那么$(@D) 的值为 src ,$(@F) 的值为 input.c。
$(<D) 和 $(<F):$(<D) 和 $(<F) 分别指向 $< 的目录名和文件名
例子:
dest/%.txt: src/%.txt
@[ -d dest ] || mkdir dest
cp $< $@
上面代码将 src 目录下的 txt 文件,拷贝到 dest 目录下。首先判断 dest 目录是否存在,如果不存在就新建,然后,$< 指代前置文件(src/%.txt), $@ 指代目标文件(dest/%.txt)
- 模式匹配
%.o: %.c
相当于:
f1.o: f1.c
f2.o: f2.c
- 变量
调用Shell变量,需要在美元符号前,再加一个美元符号,这是因为Make命令会对美元符号转义。
test:
@echo $$HOME
- if函数
#if 函数的语法是:
#$(if <condition>,<then-part> )
#或
#$(if <condition>,<then-part>,<else-part> )
#<condition>参数是if的表达式,如果其返回的为非空字符串,那么这个表达式就相当于返回真,于是,<then-part>会被计算,否则<else-part>会被计算
#
- FORCE
clean: FORCE
rm $(objects)
FORCE:
As you can see, using ‘FORCE’ this way has the same results as using ‘.PHONY: clean’.
Using ‘.PHONY’ is more explicit and more efficient. However, other versions of make do not support ‘.PHONY’; thus ‘FORCE’ appears in many makefiles. See Phony Targets.