上篇讲解了makefile的基础知识,这篇介绍点更有意思的,能够大幅度提高编写编译指令效率的方法。
有这样一个需求,先将文件下的所有c文件编译,然后链接成可执行文件。
你不会要我写如下的代码吧:
app: a.o b.o c.o ....
gcc -o app a.o b.o c.o
a.o : a.c
gcc -c -o a.o a.c
b.o : b.c
gcc -c -o b.o b.c
...
当然不是,至少gcc也支持通配符,这样就可以解决问题:gcc *.c -o app。我们先介绍makefile通配符匹配所有文件的函数--wildcard,用法如下:
查找文件夹下所有的c文件:
src = $(wildcard *c)
#然后我们可以这样:
app : $(src)
gcc -o app $(src)
wildcard就是一个makefile函数,调用时的规则如下:
$(<function> <arguments> )
或是
${<function> <arguments>}
这里,<function>就是函数名,make支持的函数不多。<arguments>是函数的参数,参数间以逗号“,”分 隔,而函数名和参数之间以“空格”分隔。函数调用以“$”开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?
为了更精准的把控整个项目,我们希望对每个c文件分开编译,然后链接,又该怎么办呢?
我们再介绍两个函数subst与patsubst,他们的作用都是字符串处理函数。
$(subst <from>,<to>,<text> )
名称:字符串替换函数——subst。
功能:把字串<text>中的<from>字符串替换成<to>。
返回:函数返回被替换过后的字符串。
示例:
x = $(subst .c,.o, a.c b.c )
将a.c b.c中的.c替换为.o,即x = a.o b.o
$(patsubst <pattern>,<replacement>,<text> )
名称:模式字符串替换函数——patsubst。
功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>中的这个“%”将是<pattern>中的那个“%”所代表的字串。(可以用“/”来转义,以“/%”来表示真实含义的“%”字符)
返回:函数返回被替换过后的字符串。
示例:
x = $(patsubst %.c, %.o, a.c b.c )
将a.c b.c中的.c替换为.o,即x = a.o b.o
与上面不同的地方是:subst不是那么的智能,连空格也会替换,例如:
subst .c, .o, a.c 替换成了a. o,而patsubst则不会
subst .c,.o, a.cc 替换成了a.oc,而patsbust则不会替,保留a.cc
再介绍一种将变量中替换字符串的方法,例如:
x = a.c b.c
y = $(x:.c=.cpp) #y将变成a.cpp b.cpp注意=两边都不能有空格
y = $(x:.c=) #y将变成a b,注意=两边都不能有空格,一般用这个得的可执行文件
虽然我们可以通过字符串替换函数把所有的.c文件全部替换为.o文件,例如:
objs = $(patsubst %.c, %.o, $(wildcard *.c))
#objs目前为a.o b.o c.o等等
但是是否所有的.o文件都要单独写编译指令呢?当然也不是,这里可以用makefile的模式规则,例如:
src = $(wildcard *.c)
objs = $(patsubst %.c, %.o, $(src))
app : $(objs)
gcc $^ -o $@ #$^表示所有的依赖文件,生成最终目标文件时,肯定要依赖所有的中间文件,$@表示目标文件
%.o : %.c #模式规则,也可以写成.c.o:,不是.o.c:
gcc -c $< -o $@ #$<表示第一个依赖文件,因为在编译的时候,我们往往只编译一个c文件,其余可能都是.h文件,他不参与编译
为什么这里可以用模式规则呢,因为gcc在生成可执行目标文件的时候,其实隐含有一个编译为中间代码的步骤,例如:
objs = $(patsubst %.c, %.o, $(src))
app : $(objs)
gcc -o app $(objs) #这里会先调用cc -c -o x.o x.c生成中间文件
我们可以通过模式规则自定义执行命令来替换隐含的那个过程,达到想要的效果。
上面的代码中还遇到了$<,$^, $@等火星文,其实这些都是一些助记符,对编写简要的makefile帮助非常大。看看上面的注释应该很快能够理解。
看完本节之后,应该能写出非常简洁又高效的makefile文件。
欢迎加入QQ群 858791125 讨论skynet,游戏后台开发,lua脚本语言等问题。