关于makefile中自动产生依赖的理解

本博文是在学习了《GNU Make中文手册》后记录下来的本身的关于自动产生makefile依赖的语句的理解,向你们分享。linux

《GNU make中文手册》中的相关章节见一下连接:正则表达式

http://blog.csdn.net/gmpy_tiger/article/details/51849257
shell

========================================================================================编程

为了理解自动产生依赖的代码,必须先掌握这两个基础又有点偏的知识点:数组

一、Makefile 中,一个文件能够做为多个规则的目标(多个规则中只能有一个规则定义命令)。这种状况时,以这个文件为目标的规则的全部依赖文件将会被合并成此目标一个依赖文件列表,当其中任何一个依赖文件比目标更新(比较目标文件和依赖文件的时间戳)时,make 将会执行特定的命令来重建这个目标。编辑器

举个例子:学习

有以下的makefile:this

               foo.o : defs.h
               bar.o : defs.h test.h
               foo.o : config.h

等效于:spa

               foo.o : defs.h config.h.net

               bar.o : defs.h test.h

就是把相同foo.o目标的规则(最多只容许一个规则有命令,其余规则只能有依赖)合并全部的依赖。

二、在linux 的命令sed中,有这么一个规则(模式替换单独的单词,见《Linux命令行与shell脚本编程大全》):

       sed编辑器用圆括号来定义替代模式的子字符串,替代字符由反斜杠和数组组成。

       很难理解是吧,举个例子你就懂了。

       echo "maybe this is a test" | sed 's/\ (this\ ) is a \ (test\ )/Is \1 really \2 /g'

输出:

       maybe Is this really test

       关于脚本的echo,管道,sed的替换命令s等基础我就不讲了,本身百度学习。这里我要讲的是,用“()”小括号括起来的被替换内容,能够在替换内容上用“\数字”代替,直接动态引用,省去重复输入的麻烦。例如上面的例子,\1表明this,\2表明test,整个sed命令的意思是把

       this is a test

替换为

       Is this really test

ps:由于小括号在正则表达式中有意义,所以须要转义,所以是\ (...\ )而不是(...)

========================================================================================

废话很少说,先直接上我本身写得自动产生依赖的代码(与《GNU Make中文手册》有些许出入,会写linux脚本的就会发现,修改的部分无伤大雅):

              %.d : %.c

                         gcc -MM  $< > $@.$ $ $ $; \                                    (1)
                         sed 's/\ ($*\ )\.o/\1.o $@/g' < $@.$ $ $ $ > $@; \       (2)

                         rm -f $@.$ $ $ $                                                       (3)

ps:网页的排版问题,为了看的直观作了修改,使用时请把四个$以及\ (和\ )之间的空格去掉,下同

继续以例子讲解:

源代码以下(helloworld.c):

          #include <stdio.h>
          #include "test.h" //test.h为空文件,只用于实验讲解
          int main(int argc, char *argv){
                  printf("hello world!\n");
          }

(1):

用gcc -MM helloworld.c的输出结果是:

         helloworld.o: helloworld.c test.h

所以(1)行代码

            gcc -MM  $< > $@.$ $ $ $; \                                    (1)

的做用,就是生成helloworld.o.xxxx的临时文件,文件内写得是"helloworld.o: helloworld.c test.h"

ps:在第一行的代码里涉及到makefile的自动化变量$<、$@和linux脚本的重定向,自行百度,再也不讲解。

(2):

第二行的代码

            sed 's/\ ($*\ )\.o/\1.o $@/g' < $@.$ $ $ $ > $@; \       (2)

参考本博文上文的基础知识2,其中,$*是自动化变量,在这里指的是:helloworld。$@也是自动化变量,在这里指的是helloworld.d。

这行代码能够理解为:

            sed 's/helloworld.o/helloworld.o helloworld.d/g' < $@.$ $ $ $ >$@

            ps:其中的两个< 、>为linux脚本的重定向,本身百度学习。

所以,实际的处理结果是把第(1)行代码的结果

            helloworld.o: helloworld.c test.h

转换为:

            helloworld.o helloworld.d: helloworld.c test.h

并把转换的结果保存到helloworld.d文件中。

(3):

第二行代码其实就已经完成任务了,第三行代码仅仅是删除第一行代码建立的临时文件$@.$$$$。在此再也不详述。

=======================================================================================

自动产生依赖的代码就这样理解,那怎么使用呢?

先看看上面代码生成的结果:

             helloworld.o helloworld.d: helloworld.c test.h      保存在helloworld.d文件中

要使用,除了上面的代码以外,只须要加一句

            include helloworld.d

其实就至关于把代码自动生成的 helloworld.o helloworld.d: helloworld.c test.h包含在makefile中。

包含上了helloworld.d的做用有两条

一、由于要包含helloworld.d,当搜索不到有helloworld.d文件时,就会自动匹配上文产生依赖的代码,自行生成helloworld.d,固然,当helloworld.c或者test.h修改后,因为helloworld.d已通过时,也会从新生成helloworld.d

二、helloworld.o的依赖会合并上helloworld.c test.h(参考本博文上文的基础知识1),从而实现了自动产生依赖

=======================================================================================

总结起来,我对上面helloworld源码写的makefile以下:

             CC = gcc 
             TARGET = helloworld

             $(TARGET) : 

             include $(TARGET).d

             %.d : %.c 
                 gcc -MM $^ > $@.$ $ $ $; \
                 sed 's/\ ($*.o\ )/\1 $@/g' < $@.$ $ $ $ > $@; \
                 rm  $@.$ $ $ $

             .PHONY: clean

             clean:
                 $(RM) $(TARGET) $(TARGET).d $(TARGET).o

helloworld.d以下:

             helloworld.o helloworld.d: helloworld.c test.h

相关文章
相关标签/搜索