有main.c:

 #include <stdio.h>
#include "command.h" int main(int argc, const char *argv[])
{
printf("run in main\n");
return ;
}

commad.h:

 #ifndef __COMMAND_H__
#define __COMMAND_H__ #define PI 3.14159 #endif

  之前写的makefile都是使用下面这种形式的静态规则:

 OBJ+=main.o

 $(OBJ):%.o:%.c
$(CC) -c $(CFLAGS) $< -o $@

  这种方法有个比较致命的缺点,比如main.c如果包含了一个头文件commad.h,我改动了这个头文件,由于main.o的依赖中没包含commad.h,所以main.o不会重新编译,显然这不是我想要的结果,通常我的做法是如果我修改了commad.h里面的一个宏MY_MCRO,使用souce insight的搜索共功能

  将最后一个选项: Touch files and cause recompile勾选上,这样被搜索到的文件就被touch了,或者麻烦点自己用shell语句实现同样的功能。但是如果.h文件里面如果改动了很多地方,这种做法显然太麻烦了,如果gcc的-M或者-MM选项那么就可以完美解决这个问题。

  首先gcc -M main.c输出:

  main.o: main.c /usr/include/stdc-predef.h /usr/include/stdio.h \
     /usr/include/features.h /usr/include/i386-linux-gnu/sys/cdefs.h \
     /usr/include/i386-linux-gnu/bits/wordsize.h \
     /usr/include/i386-linux-gnu/gnu/stubs.h \
     /usr/include/i386-linux-gnu/gnu/stubs-32.h \
     /usr/lib/gcc/i686-linux-gnu/4.8/include/stddef.h \
     /usr/include/i386-linux-gnu/bits/types.h \
     /usr/include/i386-linux-gnu/bits/typesizes.h /usr/include/libio.h \
     /usr/include/_G_config.h /usr/include/wchar.h \
     /usr/lib/gcc/i686-linux-gnu/4.8/include/stdarg.h \
     /usr/include/i386-linux-gnu/bits/stdio_lim.h \
     /usr/include/i386-linux-gnu/bits/sys_errlist.h command.h
 gcc -MM main.c输出:

  main.o: main.c command.h

  这就是目标与依赖的关系,利用gcc的预编译功能,找到目标依赖的.c .h文件,这个选项是专门为makefile准备的,-MM只输出非系统的.h文件,系统头文件不会变,所以一般用-MM。一个模板:

 objects = main.o

 CFLAGS:= -g

 main:$(objects)
cc $(objects) -o main -include $(objects:.o=.d)
%.d:%.c
@set -e; rm -f $@; \
$(CC) -MM $< > $@.$$$$; \
sed 's,\($*\)\.o[ : ]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$ .PHONY:clean
clean:
@-rm main -f $(objects) *.d *.d.*

  整个makefile的执行过程,先include文件,发现main.d不存在,但是下面有main.d的生成规则, main.d:main.c, main.d依赖于main.c,通过下面的规则生成了main.d文件,main.d文件的内容是:

main.o main.d : main.c command.h

  因此执行完include,实际得到的makefile会是这个样子:

objects = main.o

CFLAGS:= -g

main:$(objects)
cc $(objects) -o main main.o main.d : main.c command.h %.d:%.c
@set -e; rm -f $@; \
$(CC) -MM $(INCLUDE_DIRS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ : ]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$ .PHONY:clean
clean:
@-rm main -f $(objects) *.d *.d.*

  这样以来,如果改动了main.c文件会导致 main.d文件和main.o文件重新编译或生成,改动command.h文件也会导致main.o main.d文件重新编译或生成。

  有一点需要稍微注意,就是include和生成.d文件那段最好放在终极目标的后面,否则生成终极目标的时候需要显示指明了,比如:make main, 因为如果include 和 %.d:%.c那段如果放终极目标之前,终极目标不是第一个目标了,makefile默认执行第一个目标。

makefile自动生成目标与依赖的关系的更多相关文章

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

    前言 Makefile自动生成头文件依赖是很常用的功能,本文的目的是想尽量详细说明其中的原理和过程. Makefile模板 首先给出一个本人在小项目中常用的Makefile模板,支持自动生成头文件依赖 ...

  2. makefile自动生成依赖关系

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

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

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

  4. Linux Makefile自动生成--config.h

    Linux Makefile自动生成--config.h http://blog.csdn.net/spch2008/article/details/12510805

  5. Makefile 自动生成依赖

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

  6. pip自动生成requirements.txt依赖关系清单

    Python项目中经常会带requirements.txt文件,里面是项目所依赖的包的列表,也就是依赖关系清单,这个清单也可以使用pip命令自动生成. pip命令: 1 pip freeze > ...

  7. Makefile自动生成

    automake/autoconf入门作为Linux下的程序开发人员,大家一定都遇到过Makefile,用make命令来编译自己写的程序确实是很方便.一般情况下,大家都是手工写一个简单Makefile ...

  8. makefile自动生成学习

    https://www.cnblogs.com/jrglinux/p/6964169.html 关键是如何写Makefile.am  其他的交给 自动工具完成 添加一个 很好的博客 学习下 https ...

  9. 使用pip命令自动生成项目安装依赖清单

    Python项目中经常会带requirements.txt文件,里面是项目所依赖的包的列表,也就是依赖关系清单,这个清单也可以使用pip命令自动生成. pip命令: 1 pip freeze > ...

随机推荐

  1. Winform中的窗体一些常用属性

    Winform窗体的常用窗体属性 1)窗体全屏显示 this.DesktopBounds = Screen.GetWorkingArea(this);  //全屏显示桌面 注:可以放在初始化方法中,也 ...

  2. fibonacci封闭公式

    Description 2007年到来了.经过2006年一年的修炼,数学神童zouyu终于把0到100000000的Fibonacci数列 (f[0]=0,f[1]=1;f[i] = f[i-1]+f ...

  3. js 自带的 reduce() 方法

    1.方法说明 , Array的reduce()把一个函数作用在这个Array的[x1, x2, x3...]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,其效果 ...

  4. 单例(Singleton pattern)模式的七种写法

    转载请注明出处:http://www.cnblogs.com/smbk/ One: public class Singleton { private static Singleton instance ...

  5. ABAP指针

    1. 什么是ABAP指针:在ABAP里面,field symbol就相当于c语言的指针.如果你定义并且分配了相应的结构或者变量给它,其实它就指向这个结构或者变量的地址,如果修改了field symbo ...

  6. ArcEngine环境下合并断开的线要素(根据属性)

    1.遇到的问题: 最近遇到在线要素(矢量数据)中,一条完整的道路.河流等往往是断开的,如下图1所示: 2.思路: 在ArcGIS Desktop中没有相关的工具可以将这些断开的线要素进行自动合并,今天 ...

  7. Q:关于Outlook for CRM 中预览记录窗体的设置

    问题: 如何在Outlook for CRM中,将实体记录的预览窗口的信息做调整? 解决方案: 在Outlook里,在打开实体后选择View=>Customize Reading Pane,这里 ...

  8. 类型“GridView”的控件“GridView1”必须放在具有 runat=server 的窗体标记内。

    错误的写法:  if (this.GridView1.Rows.Count > 0)         {             string style = @"<style& ...

  9. SharePoint 服务器端对象模型 之 使用LINQ进行数据访问操作(Part 2)

    (四)使用LINQ进行列表查询 在生成实体类之后,就可以利用LINQ的强大查询能力进行SharePoint列表数据的查询了.在传统SharePoint对象模型编程中,需要首先获取网站对象,再进行其他操 ...

  10. UWP开发-HTTP详解

    HTTP作为一个基础功能,有必要介绍下在UWP下的使用方法. 一.Get请求: 一般我们用到的是GetAsync方法 public static async Task Gets(Uri uri) { ...