对make中自动生成依赖及sed的解释

原创,学习gmake中一些理解,转贴请注明出处^_^

 

大多数gmake手册中给出的例子为:

 

%.d: %.c                                                 
    $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \                 
    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
     rm -f $@.$$$$                                       

对上述代码进行稍微详细的分析:

1 第一行 目标与依赖定义

%.d: %.c                                                 

按照make对规则的分类,这行是一个“模式规则”,它表示的含义是:所有的.d文件依赖于对应的.c文件。而模式规则中的“%”的匹配和替换发生在make执行时。一个模式规则的格式为:
                                %.o : %.c ; COMMAND...                                
这个模式规则指定了如何由文件“*.c”来创建文件“*.o”,文件“*.c”应该是已存在的或者可被创建的。

因此,对当前搜索目录下的每一个c源文件,make进行模式替换,相应的自动化变量也会赋值。相当于:

for each *.c fsource file                             
{                                                     
   % <---基本文件名,不包含.c   ## 如foo.c,则 % = foo    
   $* = % = 基本的文件名                                
   $@ = %.d                  ## $@ =  foo.d            
   $< = %.c                  ## 即$< = foo.c           
   ......                                             
}                                                     

假设当前处理的文件为foo.c,那么就有S* = foo, $@ = foo.d, $< = foo.c

2 第二行 gcc 自动分析依赖文件

    $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \                 

需要将第一步的自动化变量展开代入,得到

    $(CC) -MM $(CPPFLAGS) foo.c > foo.d.$$$$; \                 

$$$$代表了一个随机数,假设为35,即执行

     gcc -MM $(CPPFLAGS) foo.c

结果存入文件foo.d.35

这个文件的内容可能是这样的

foo.o: foo.c foo.h defs.h common.h

它说明了foo.c真实的依赖关系。(注意由gcc产生的,make还并不知道这个依赖关系),为了让make也知道这个依赖关系,我们的目标是根据这个结果产生一个“依赖文件”foo.d,加入到Makefile中。即在Makefile中增加类似这样的规则:

foo.o: foo.c foo.h defs.h common.h

但是要直接把这个包含“目标:依赖”的新规则加入到当前的Makefile文件,并不是一件容易的事,还是需要借助于include。因此,可以把上面的结果存入到另一个foo.d的文件中,在Makefile中再通过:

sources = foo.c bar.c           
sinclude $(sources:.c=.d)       

就可以加入新的目标规则了。

但这样做还不够....因为这样一来,又产生了新的foo.d的文件,那么foo.d的依赖关系呢??显然,foo.d的依赖关系和foo.o是一致的!所以,在foo.d文件中还需要定义foo.d的依赖关系。用简单的多目标规则改写成下面的这样就可以:

foo.o foo.d: foo.c foo.h defs.h common.h

这也是为什么上面保存的文件是foo.d.35而不是最终的foo.d的原因,我们还需要编辑这个文件。要编辑,当然是要用到那个强大的sed工具了。

3 第三行 sed的使用

到这一步,我们的任务就十分明确了:将foo.d.35文件中的"foo.o:foo.c foo.h defs.h common.h"改写成"foo.o foo.d:foo.c foo.h defs.h common.h",并存为foo.d文件。

看看第三行发生了什么:

    sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \

首先对自动变量替换:

    sed 's,\(foo\)\.o[ :]*,\1.o foo.d : ,g' < foo.d.35 > foo.d; \

即:从文件foo.d.35读入,结果保存在foo.d中。

sed命令为 sed 's\(foo\)\.o[ :]*,\1.o foo.d : ,g'

这是s替换命令,这里用逗号","作分隔符(注意:s后跟的第一个字符被看作分隔符),其一般格式为:

            sed  's/regexp/replacement/'                          

所以第一段"\(foo\)\.o[ :]*"被当成是正则表达式处理,它表示的模式是foo.o,后面可以有空格,或者冒号,如下面这些模式:

"foo.o" "foo.o:"  "foo.o:  " "foo.o    :  "foo.o :  :  " 都可以匹配。(当然,这里是用贪婪模式匹配)。

对我们给出的例子,匹配情况是这样的:

foo.o: foo.c foo.h defs.h common.h --(注,匹配包含冒号后一个空格,死新浪老自动改,以下也类似)

替换字符串为"\1.o foo.d : ",其中\1 = foo(sed中的replacement可以使用\1抓字串的),代入\1,于是有:\1.o foo.d : =foo.o foo.d :

至此,原来的内容变成了:

foo.o foo.d : foo.c foo.h defs.h common.h

正是我们所想要的结果, 大功告诫了~~~~

 


你可能感兴趣的:(对make中自动生成依赖及sed的解释)