问题
这里,我们给出了一个模式规则来产生[.d]文件:
%.d: %.c
@set -e; rm -f $@; \
$(CC) -M $(CPPFLAGS) $< >; $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ >; $@; \
rm -f $@.$$$$
这个规则的意思是,所有的[.d]文件依赖于[.c]文件,“rm -f $@”的意思是删除所有的目标,也就是[.d]文件,第二行的意思是,为每个依赖文件“$<”,也就是[.c]文件生成依赖文件,“$@”表示模式“%.d”文件,如果有一个C文件是name.c,那么“%”就是“name”,“$$$$”意为一个随机编号,第二行生成的文件有可能是“name.d.12345”,第三行使用sed命令做了一个替换,关于sed命令的用法请参看相关的使用文档。第四行就是删除临时文件。
上面代码的解释1:
%.d: %.c
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
p-162:sed替换命令的格式是‘s///g’如果没有g,则sed的替换操作只对文本中的第一次出现的匹配模式进行替换。关于‘s///’命令的另一个注意点是‘/’分隔符有许多替换选项。如果正在执行字符串替换,并且规则表达式或替换字符串中有许多斜杠,则可以通过在’s’之后指定一个不同的字符来更改分隔符。例如,下列将把所有出现的/usr/local替换成/usr:
sed –e ‘s:/usr/local:/usr:g’ mylist.txt
在该例中,使用冒号作为分隔符。如果需要在规则表达式中使用分隔符,可以在它前面加入反斜杠。关于\(\)是保留的模式空间,参见p-70,$* 是makefile中匹配的“茎”,$$$$表示当前进程的进程号,命令行中还运用了输入输出重定向。
上面代码的解释2: 这是sed命令的用法了。Stream Editor
简单来讲就是替换。这里采用逗号作为基本语法的分隔。一般的形式是sed 's/pattern/new/g'
\($*\)\.o[ :]*替换为\1.o $@ :
后面的g表示全局替换,就是不止替换一次。
同时又是用在makefile当中,所以要牵扯到$*,$@之类的自动变量。
$*,表示的是target的除去了suffix后的filename,也就是%.d: %.c当中的%部分。
$@,表示的是target,也就是%.d
sed操作的文件是来自上面命令的生成的临时文件$@.$$$$
最后再把sed的输出定向到零时文件$@.$$$$
后面的\都是为了和下面的命令连成一行,然后都用用;分隔,所以都是放在一个subshell当中执行。
没有猜错的话,这应该是Manage project with GNU make 3rd Edition当中的例子。
sed命令例子
在makefile里经常看到sed指令,经常看到替换功能,今天写了个makefile来学习下sed的替换功能,makefile如下:
- test = abcdefghisdabcjsdlfkj
- test2 = $(test) | sed -e 's/abc/123/g'
- debug:
- @echo $(test)
- @echo $(test2)
然后输入make debug,看到如下输入:
- abcdefghisdabcjsdlfkj
- 123defghisd123jsdlfkj
abc被替换成了123,如果不加字母g,结果就变成了只有第一个abc被替换,另外可以在复杂的makefile里使用echo指令来显示一些变量,有助学习makefile