Makefile自动生成头文件依赖

前言

Makefile自动生成头文件依赖是很常用的功能,本文的目的是想尽量详细说明其中的原理和过程。

Makefile模板

首先给出一个本人在小项目中常用的Makefile模板,支持自动生成头文件依赖。

CC      = gcc
CFLAGS  = -Wall -O
INCLUDEFLAGS =
LDFLAGS =
OBJS    = seq.o
TARGETS = test_seq 

.PHONY:all
all : $(TARGETS)

test_seq:test_seq.o $(OBJS)
    $(CC) -o [email protected] $^ $(LDFLAGS)

%.o:%.c
    $(CC) -o [email protected] -c $< $(CFLAGS) $(INCLUDEFLAGS)

%.d:%.c
    @set -e; rm -f [email protected]; $(CC) -MM $< $(INCLUDEFLAGS) > [email protected]$$$$;     sed ‘s,\($*\)\.o[ :]*,\1.o [email protected] : ,g‘ < [email protected]$$$$ > [email protected];     rm -f [email protected]$$$$

-include $(OBJS:.o=.d)

.PHONY:clean
clean:
    rm -f $(TARGETS) *.o *.d *.d.*

基础知识

在进行下一步之前,首先需要了解make的执行步骤:

  1. 读入Makefile
  2. 读入被include的其它Makefile
  3. 初始化Makefile中的变量
  4. 推导隐晦规则,并分析所有规则
  5. 为所有目标创建依赖关系链
  6. 根据依赖关系,决定哪些目标需要重新生成
  7. 执行生成命令

如何动态生成依赖关系?

从上面make的执行过程中可看出,要动态生成依赖关系,只能利用第2步读入其它Makefile的机制。那么,我们是否可以先把生成的依赖关系保存到文件,然后再把该文件的内容包含进来?
答案是Yes! 只要利用include的机制。

include关键字是用于读入其它Makefile文件。当该文件不存在时,make会寻找是否有生成它的规则,如果有,则执行其生成命令,然后再尝试读入。在include前加减号"-"可以上make忽略其产生的错误,并不输出任何错误信息。

即是说,我们需要提供生成规则文件的规则。例如,我们可以这样动态生成头文件依赖关系:

seq.d : seq.c
    @echo “seq.o seq.d : seq.c seq.h" > [email protected]

-include seq.d

当make执行时,Makefile中的内容将是这样子(指内存上的数据):

seq.d : seq.c
    @echo “seq.o seq.d : seq.c seq.h" > [email protected]

seq.o seq.d : seq.c seq.h

特别注意的是,由于对seq.c和seq.h的修改需要更新seq.d的内容(因为依赖关系可能已变化),因此seq.d也要在依赖关系的目标列表中。

自动生成头文件依赖

基于上面的例子,现在可以开始讨论如何自动生成头文件依赖。

自动生成依赖关系

大多数c/c++编译器提供了-M选项,可自动寻找源文件依赖的头文件,并生成依赖规则。对于gcc,需要使用-MM选项,否则它会把系统依赖的头文件也包含进来。例如执行下面一个命令:

    gcc -MM seq.c

将输出:

    seq.o : seq.c seq.h

但我们需要结果是seq.d也要包含在目标列表中,所以还需要对它进行文本处理。因此,上面的例子可改为:

seq.d : seq.c
    @set -e;     gcc -MM $< > [email protected]$$$$;     sed ‘s,\($*\)\.o[ :]*,\1.o [email protected] : ,g‘ < [email protected]$$$$ > [email protected];     rm -f [email protected]$$$$

-include seq.d

生成规则中的执行命令解释

第一个命令@set -e。@关键字告诉make不输出该行命令;set -e的作用是,当后面的命令的返回值非0时,立即退出。

那么为什么要把几个命令写在”同一行“(是对于make来说,因为\的作用就是连接行),并用分号隔开每个命令?因为在Makefile这样做才能使上一个命令作用于下一个命令。这里是想要set -e作用于后面的命令。

第二个命令gcc -MM $< > [email protected]$$$$, 作用是根据源文件生成依赖关系,并保存到临时文件中。内建变量$<的值为第一个依赖文件(那seq.c),$$$$为字符串"$$",由于makefile中所有的$字符都是特殊字符(即使在单引号之中!),要得到普通字符$,需要用$$来转义; 而$$是shell的特殊变量,它的值为当前进程号;使用进程号为后缀的名称创建临时文件,是shell编程常用做法,这样可保证文件唯一性。

第三个命令作用是将目标文件加入依赖关系的目录列表中,并保存到目标文件。关于正则表达式部分就不说了,唯一要注意的是内建变量$*$*的值为第一个依赖文件去掉后缀的名称(这里即是seq)。

第四个命令是将该临时文件删除。

如果把内建变量都替换成其值后,实际内容是这样子:

seq.d : seq.c
    @set -e;     gcc -MM seq.c > seq.d.$$$$;     sed ‘s,\(seq\)\.o[ :]*,\1.o seq.d : ,g‘ < seq.d.$$$$ > seq.d;     rm -f seq.d.$$$$

-include seq.d

Makefile的模式匹配

最后,再把Makefile的模式匹配应用上,就完成自动生成头文件依赖功能了:

%.d : %.c
    @set -e;     gcc -MM [email protected] > [email protected]$$$$;     sed ‘s,\($*\)\.o[ :]*,\1.o [email protected] : ,g‘ < [email protected]$$$$ > [email protected];     rm -f [email protected]$$$$

-include seq.d

参考资料

<跟我一起写Makefile> by 陈晧
GNU make官方文档 http://www.gnu.org/software/make/manual/make.html

时间: 2024-10-26 10:49:24

Makefile自动生成头文件依赖的相关文章

Makefile中自动生成头文件依赖

为什么需要自动生成头文件依赖? 编译单个源文件时,需要获取文件中包含的头文件的信息,但是一般的Makefile不会在规则中明确写明文件依赖的头文件,所以单独修改头文件后,不会导致包含头文件的源文件重新编译.如果每次手动的添加头文件依赖,又会非常的繁琐,所以需要一种自动生成依赖的方法. 编译器中神奇的选项 使用$(CC)中的-M命令就可以完美的解决问题,因为-M选项可以将源文件依赖的所有头文件,自动解析出来. 例子:在当前路径下,编辑test.c和test.h文件,test.c如下所示,test.

Makefile 自动生成头文件的依赖关系 .

最近在看一本书<Windows游戏编程大师技巧> (Tricks of Windows Game Programming Gurus). 第一章给出了一个打砖块小游戏的示例程序. 包括三个文件: blackbox.h, blackbox.cpp和freakout.cpp (600行代码, 对于Windows C++程序来说还好, 没有让我freak out…). blackbox.cpp封装了部分DirectDraw, 提供了一些更傻瓜化的初始化DirectDraw, 画点, 画方框的工具函数

自动编译Makefile,原版升级版,支持自动推倒头文件依赖关系、创建目标路径

################################################################################### # 简易多模块程序自动编译/清除Makefile v2.0 #简介: 自动编译.清除功能,不需要每次编译输入gcc或者rm指令 #使用方法: 先配置Makefile中的配置项.目标名称等,然后在终端执行make即可 # #使用说明:1. 本Makefile可以自动推倒源程序与头文件之间的依赖关系,并生成.depend文件 # 2.

makefile自动生成目标与依赖的关系

有main.c: 1 #include <stdio.h> 2 #include "command.h" 3 4 int main(int argc, const char *argv[]) 5 { 6 printf("run in main\n"); 7 return 0; 8 } commad.h: 1 #ifndef __COMMAND_H__ 2 #define __COMMAND_H__ 3 4 #define PI 3.14159 5 6 #

设置pycharm 创建文件时自动生成头文件

找到该路径并添加以下信息 File->settings->Editor->File and Code Templates->Python Script  #!/usr/bin/env python# -*- coding: utf-8 -*-# @Time    : ${DATE} ${TIME}# @Author  : Aries# @Site    : ${SITE}# @File    : ${NAME}.py# @Software: ${PRODUCT_NAME}

CPLUSPLUS 获得 一个源文件的头文件依赖。即该文件所需要的所有头文件

核心命令:gcc -M *.h.*.cpp 转: 自动处理头文件的依赖关系 http://blog.csdn.net/su_ocean16/article/details/5374696 现在我们的Makefile写成这样: all: main main: main.o stack.o maze.o gcc $^ -o [email protected] main.o: main.h stack.h maze.h stack.o: stack.h main.h maze.o: maze.h ma

程序自动生成dump文件

作用 可以再程序崩溃后保留崩溃现场,方便事后查找程序的崩溃原因. 前提是奔溃程序所对应的代码和PDB文件都是匹配的(发布程序的时候,保留源代码和PDB文件). 代码示例 原理是使用DbgHelp的自定义未处理异常来保留崩溃现场到文件的,使用直接包含该头文件,然后再main函数的开始就调用EnableAutoDump函数. // pro_dump.h // 包含本文件是用来处理程序崩溃时自动生成dump文件的 // 生成的dump文件在程序的工作目录下 // 文件名格式是:年月日_时分秒.dmp

程序自动生成Dump文件()

前言:通过drwtsn32.NTSD.CDB等调试工具生成Dump文件, drwtsn32存在的缺点虽然NTSD.CDB可以完全解决,但并不是所有的操作系统中都安装了NTSD.CDB等调试工具.了解了mini dump文件格式后,完全可以程序自动生成Dump文件. 本文主要讨论以下内容: 1.  运行原理 2.  程序修改 3.  注意事项 一.   运行原理 当程序遇到未处理异常(主要指非指针造成)导致程序崩溃死,如果在异常发生之前调用了SetUnhandledExceptionFilter(

Makefile自动生成工具-----autotools的使用(详细)

相信每个学习Linux的人都知道Makefile,这是一个很有用的东西,但是编写它是比较复杂,今天介绍一个它的自动生成工具,autotools的使用.很多GNULinux的的软件都是用它生成Makefile的,包括我们非常熟悉的Linux内核源代码. 1.准备: 需要工具 autoscan aclocal autoheader automake autoconf auto make 在终端敲入命令,哪个没有安装哪个,一般是第一个autoscan没有,其它的我用的Ubuntu10.04下全部都有