LinuxMakefile生成*.d依赖文件以及gcc
blog.csdn/qq1452008/article/details/50855810
1. 为什么要使用后缀名为 .d 的依赖文件?
makefile phony在 Makefile 中, 目标文件的依赖关系需要包含一系列的头文件。
比如
main.c 源文件内容如下:
#include "stdio.h"
#include "defs.h"
int main(int argc, char *argv[])
{
printf("Hello, %s!\n", NAME);
return 0;
}
defs.h 头文件如下:
#ifndef _DEFS_H_
#define _DEFS_H_
#define NAME"makefile"
#endif _DEFS_H_
那么依赖关系如下(依赖的文件省略了绝对路径):
main.o : main.c stdio.h defs.h ... 
假设目标文件的依赖关系缺少了 defs.h 文件,当 defs.h 文件中的内容改变后,根本不会重新编译目标文件,这是致命的,因为目标文件内部引用了 defs.h 文件中的宏定义。
如果是一个比较大型的工程,我们必需清楚每一个源文件都包含了哪些头文件,并且在加入或删除某些头文件时,也需要一并修改 Makefile,这是一个很没有维护性的工作。为了避免这种繁重而又容易出错的事情,可以使用 C/C++ 编译器的 “-M” 选项,即自动获取源文件中包含的头文件,并生成一个依赖关系。例如,执行下面的命令:
gcc -M main.c
其输出如下:
main.o : main.c defs.h
由编译器自动生成依赖关系,这样做的好处有以下几点:
不必手动书写若干目标文件的依赖关系,由编译器自动生成
不管是源文件还是头文件有更新,目标文件都会重新编译
2. 使用说明
参数介绍:
-M
生成文件的依赖关系,同时也把一些标准库的头文件包含了进来。本质是告诉预处理器输出一个适合 make 的规则,用于描述各目标文件的依赖关系。对于每个源文件,预处理器输出 一个 make 规则,该规则的目标项 (target) 是源文件对应的目标文件名,依赖项 (dependency) 是源文件中 “#include” 引用的所有文件,生成的规则可以是单行,但如果太长,就用’'换行符续成多行。规则显示在标准输出,不产生预处理过的 C 程序。
注意:该选项默认打开了 -E 选项, -E 参数的用处是使得编译器在预处理结束时就停止编译
例如:
gcc -M main.c
则在终端上输出如下:
main.o: main.c defs.h  /usr/include/stdio.h  /usr/include/features.h \                                         
/usr/include/sys/cdefs.h /usr/include/gnu/stubs.h \       
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h \ 
/usr/include/bits/types.h  /usr/include/bits/pthreadtypes.h \
/usr/include/_G_config.h /usr/include/wchar.h \
/usr/include/bits/wchar.h /usr/include/gconv.h \
/usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h \
/usr/include/bits/stdio_lim.h
-MM
生成文件的依赖关系,和 -M 类似,但不包含标准库的头文件
例如:
gcc -MM main.c
则在终端上输出如下:
main.o: main.c defs.h
-MG
要求把缺失的头文件按存在对待,并且假定他们和源文件在同一目录下,必须和 ‘-M’ 选项一起用。
-MF File
当使用了 “-M” 或者 “-MM” 选项时,则把依赖关系写入名为 “File” 的文件中。若同时也使用了 “-MD” 或 “-MMD”,“-MF” 将覆写输出的依赖文件的名称 。
例如:
gcc -M -MF main.d main.c
则 “-M” 输出的内容就保存在 main.d 文件中了
-MD
等同于 -M -MF File,但是默认关闭了 -E 选项。其输出的文件名是基于 -o 选项,若给定了 -o 选项,则输出的文件名是 -o 指定的文件名,并添加 .d 后缀,若没有给定,则输入的文件名作为输出的文件名,并添加 .d 后缀,同时继续指定的编译工作。
注意:-MD 不会像 -M 那样阻止正常的编译任务,因为它默认关闭了 -E 选项,比如命令中使用了 -c 选项,其结果要生成 .o 文件,若使用了 -M 选项,则不会生成 .o 文件,若使用的是 -MD 选项,则会生成 .o 文件
例 1:
gcc -E -MD main.c
本目录下生成了以下文件:
main.d
同时在终端上输出了 main.c 文件的预处理结果
经实测发现,不使用 '-o' 指定输出文件名,以下情况有细微的差别:
gcc -E main.c //不使用 '-o',则把结果输出在终端上
gcc -S main.c //不使用 '-o',则把结果输出到以输入文件名为名称的 .s 文件中,即 main.s
gcc -c main.c //同上
gcc main.o    //不使用 '-o',则把结果默认输出到 a.out 可执行文件中
例 2:
gcc -E -o tmp.i -MD main.c
本目录下生成了以下文件:
tmp.d tmp.i
例 3:
gcc -c -MD main.c
本目录下生成了以下文件:
main.d main.o
例 4:
gcc -c -o tmp.o -MD main.c
本目录下生成了以下文件:
tmp.d tmp.o
例 5:
gcc -MD main.c
本目录下生成了以下文件:
a.out main.d
例 6:
gcc -M -MD main.c
本目录下生成了以下文件:
main.d 
#注释:并不会生成a.out可执行文件,因为 '-M' 默认打开了 '-E' 选项,

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。