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

《GNU make中文手册》中的相关章节见一下链接:

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

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

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

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

举个例子:

有如下的makefile:

foo.o : defs.h

               bar.o : defs.h test.h

               foo.o : config.h

等效于:

foo.o : defs.h config.h

bar.o : defs.h test.h

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

2、在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的作用有两条

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

2、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

关于makefile中自动产生依赖的理解的更多相关文章

  1. Makefile中自动生成头文件依赖

    为什么需要自动生成头文件依赖? 编译单个源文件时,需要获取文件中包含的头文件的信息,但是一般的Makefile不会在规则中明确写明文件依赖的头文件,所以单独修改头文件后,不会导致包含头文件的源文件重新 ...

  2. Makefile 7——自动生成依赖关系 三颗星

    后面会介绍gcc获得源文件依赖的方法,gcc这个功能就是为make而存在的.我们采用gcc的-MM选项结合sed命令.使用sed进行替换的目的是为了在目标名前加上“objs/”前缀.gcc的-E选项, ...

  3. 工程管理之makefile与自动创建makefile文件过程

    (风雪之隅 http://www.laruence.com/2009/11/18/1154.html) Linux Makefile自动编译和链接使用的环境 想知道到Linux Makefile系统的 ...

  4. Makefile 自动生成依赖

    虽然以前对Makefile有个基本概念,但是真正到自己去写一个哪怕是简单的Makefile时也会遇到不少的麻烦.    现在我有如下文件 dList.h dList.c memory.c debug. ...

  5. makefile自动生成依赖关系

    手工编写依赖关系不仅工作量大而且极易出现遗漏,更新也很难及时,修改源或头文件后makefile可能忘记修改.为了解决这个问题,可以用gcc的-M选项自动生成目标文件和源文件的依赖关系.-M选项会把包含 ...

  6. makefile 中添加依赖的库文件

    当库文件中包含多个头文件和c源文件时,需要执行如下步骤: 1) makefile中添加 库文件依赖, -L 后面跟库文件的路径,  -l(小写)后面跟库的名字 2)将库文件中的头文件添加到工程中去,使 ...

  7. makefile中伪目标的理解

    1. 我们知道Makefile中的语法是这样: target ... : prerequisites ... command - - 2. 假如编译两个文件可以这么写: a.o:a.c  gcc -c ...

  8. 对 makefile 中 .DEFAULT 的理解

    上例子: all:gao @echo "final".DEFAULT: @echo "In default" 由于 gao 是一个前提条件,但是 makefil ...

  9. Makeflie自动生成依赖,自动化编译

    在netbeans里开发,有一个重要文件makefile,是用来编译所有的文件. 项目的目录结构如下,扁平的目录结构,如何实现自动化编译,写makefile呢? 第一版 基础版: CC = g++ C ...

随机推荐

  1. Linux watch命令详解

    watch可以帮你监测一个命令的运行结果,来监测你想要的一切命令的结果变化 常见命令参数 Usage: watch [-dhntv] [--differences[=cumulative]] [--h ...

  2. 沉淀再出发:java中线程池解析

    沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...

  3. awk 截取某段时间的日志

    好久没有截取nginx/haproxy 中 的日志了,竟有点不熟悉了. 记录一下,以免以后忘记. NGINX 日志格式: 192.168.1.26 - - [14/Sep/2017:16:48:42 ...

  4. Innodb_io_capacity 对于IO稳定性的一些研究

    背景:最近在做一台线上服务器IO负载情况的时候发现了以下现象: 24小时的IO_UTIL 的曲线看似风平浪静,毛刺较少 但当图片放大到半小时级别的时候发现IO_UTIL即磁盘使用率出现了规律性的波动, ...

  5. 使用zepto实现QQ消息左滑删除效果

    有这样一个需求: 1. 有一个列表,将每一个列表项左滑动出现删除按钮: 2. 右滑动隐藏删除按钮: 3. 点击这个删除按钮删除该列表项. 完成以后的效果: 这是微信网页端的页面,使用的是 zepto ...

  6. BZOJ 1001 狼抓兔子 平面图的最小割

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1001 题目大意: 见链接 思路: 求最小割,平面图的最小割等价于对偶图的最短路 直接建 ...

  7. Java类修饰符的使用与作用以及常见问题

    首先明确,类是放在文件里的,在文件里面的不同位置就有不同的作用,就是不同类型的类. 1, 顶级类or外部类:包括两种,一个文件中与文件名同名称的类我们称作顶级类(也是外部类),如果在一个文件中的一个类 ...

  8. Calabash(葫芦娃)

    嘟嘟嘟 第一眼就觉得肯定某种是最短路,然后想了半天也不知道.然后就把送的50分写了,然后就爆搜,结果因为一个错误的剪枝竟然90分?!只能怪数据太水…… 考完试后听bin哥讲,说就是普通的最短路,只不过 ...

  9. Odoo中如何复制有唯一性约束的记录?

    转载请注明原文地址:https://www.cnblogs.com/cnodoo/p/9281393.html  如果为模型的字段添加了唯一性约束,那么在记录的form视图功能菜单上选择“复制”时就会 ...

  10. spring boot +druid数据库连接池配置

    1.启动应用入口修改 增加servlet注解 import javax.sql.DataSource; import org.apache.ibatis.session.SqlSessionFacto ...