Linux Makefile 生成 *.d 依赖文件及 gcc -M -MF -MP 等相关选项说明【转】
1. 为什么要使用后缀名为 .d 的依赖文件?
在 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 ...
但如果是一个比较大型的工程,你必需清楚每一个 C 源文件包含了哪些头文件,并且在加入或删除头文件时,也需要小心地修改 Makefile,这是一个很没有维护性的工作。为了避免这种繁重而又容易出错的事情,我们可以使用 C/C++ 编译的一个功能。大多数的 C/C++ 编译器都支持一个 “-M” 的选项,即自动找寻源文件中包含的头文件,并生成一个依赖关系。例如,执行下面的命令:
gcc -M main.c
其输出如下:
main.o : main.c defs.h
由编译器自动生成依赖关系,这样做的好处有以下几点:
- 不必手动书写若干文件的依赖关系,由编译器自动生成
- 不管是 .c 文件还是 .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' 选项,使得编译器在预处理结束后就停止编译
-MMD
类似于 ‘-MD’,但是输出的依赖文件中,不包含标准头文件-MP
生成的依赖文件里面,依赖规则中的所有.h依赖项都会在该文件中生成一个伪目标,其不依赖任何其他依赖项。该伪规则将避免删除了对应的头文件而没有更新 “Makefile” 去匹配新的依赖关系而导致make出错的情况出现。
(英文描述:This option instructs CPP to add a phony target for each dependency
other than the main file, causing each to depend on nothing. These
dummy rules work around errors ‘make’ gives if you remove header
files without updating the ‘Makefile’ to match.)
例如1: gcc -c -MM -MD main.c
生成的 main.d 文件内容如下:
main.o: main.c defs.h
例如1: gcc -c -MM -MD main.c -MP
生成的 main.d 文件内容如下:
main.o: main.c defs.h
defs.h: //该选项会生成该伪目标,其没有任何依赖项,若不使用 '-MP' 选项,则不会生成该伪目标规则
- -MT Target
在生成的依赖文件中,指定依赖规则中的目标
例如: gcc -MF main.d -MG -MM -MP -MT main.d -MT main.o main.c
$ cat main.d #查看生成的依赖文件的内容
main.d main.o: main.c
注:依赖规则中main.d 和 main.o 目标都是通过'-MT'选项指定的
3. 使用参考:
以上简单介绍了 gcc -M 相关的选项,旨在让 make 自动推导并生成文件的依赖关系.
以下提供一个比较好的 gcc -M 选项的参考示例, 它将自动生成依赖文件,并保存在指定目录下的 ‘.d’ 文件中。
makefile如下所示:
SRCS=$(wildcard *.c)
OBJS=$(SRCS:.c=.o)
DEPS=$(SRCS:.c=.d)
.PHONY: all clean
all: main
-include $(DEPS) #注释:'-'号的作用:加载错误时,会继续执行 make,主要是考虑到首次 make 时,目录中若不存在 '*.d' 文件时,加载便会产生错误而停止 make 的执行
%.o:%.c
gcc -c -g -Wall $< -o $@ -MD -MF $*.d -MP
main: $(OBJS)
gcc $^ -o $@ #注释:$^:表示所有的依赖文件 $@:表示目标文件
clean:
rm -f *.d *.o main
仍旧以本篇文章开头的源文件进行 make,将生成如下文件:
main : 可执行文件
main.o : 编译的二进制目标文件
main.d:保存了 main.o 依赖关系的文件
注释: $* 表示目标模式中 '%' 及其之前的部分.如果目标是 'dir/a.foo.b',
并且目标的模式为 'a.%.b',那么 '$*' 的值就是 'dir/a.foo'.
如果目标中没有模式的定义,那么 '$*' 就不能被推导出.
但是,如果目标文件是 make 所识别的,那么 '$*' 就是除了后缀的那一部分,
例如:目标是 'foo.c',因为 '.c' 是 make 所能识别的后缀名,
所以 '$*' 的值就是 'foo'.这个特性是 GNU make 的.
4. 延伸说明:
Makefile 文件中使用比较多的自动变量:
- $@ : 表示一个规则中的目标.当规则中有多个目标时,$@ 所指的是其中任何造成规则的命令运行的目标
- $^ : 表示规则中的所有依赖项
- $< : 表示规则中的第一个依赖项
例如 Makefile 文件内容如下:
target1 target2:dep1 dep2 dep3
@echo "Tar:$@, First Dep:$<, All Dep:$^"
dep1 dep2 dep3: #注释:不写该行目标规则,执行 make 会报错,因为 makefile 目录下不仅没有 dep1 dep2 dep3 文件,makefile 文件中也没有以这些依赖文件做为目标的规则.
运行 make:
1. make target1 或者 make (把文件中第一个目标当作首要目标)
终端输出如下:
Tar:target1, First Dep:dep1, All Dep:dep1 dep2 dep3
2. make target2
终端输出如下:
Tar:target2, First Dep:dep1, All Dep:dep1 dep2 dep3
3. make target1 target2
终端输出如下:
Tar:target2, First Dep:dep1, All Dep:dep1 dep2 dep3
Tar:target2, First Dep:dep1, All Dep:dep1 dep2 dep3
相信大家在看了以上例子,能够更加理解这三个自动化变量的含义,尤其是 ‘$@‘, 前面已经说明了其含义,这里就不再赘述了.
以上有些内容引用了其他博客,在此,感谢博主!
以上内容,若有差错,欢迎指正,以免误人误己。
---------------------
作者:Jerry_yl_
来源:CSDN
原文:https://blog.csdn.net/qq1452008/article/details/50855810?utm_source=copy
版权声明:本文为博主原创文章,转载请附上博文链接!
Linux Makefile 生成 *.d 依赖文件及 gcc -M -MF -MP 等相关选项说明【转】的更多相关文章
- Linux Makefile 生成 *.d 依赖文件及 gcc -M -MF -MP 等相关选项说明
1. 为什么要使用后缀名为 .d 的依赖文件? 在 Makefile 中, 我们的依赖关系可能需要包含一系列的头文件.比如main.c 源文件内容如下: #include "stdio.h& ...
- linux下生成core dump文件方法及设置
linux下生成core dump文件方法及设置 from:http://www.cppblog.com/kongque/archive/2011/03/07/141262.html core ...
- linux下生成core dump文件方法及设置【转】
转自:http://blog.csdn.net/mrjy1475726263/article/details/44116289 源自:http://andyniu.iteye.com/blog/196 ...
- linux下生成core dump文件方法
core 文件的简单介绍 当程序运行的过程中异常终止或崩溃,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为就叫做Core Dump(中文有的翻译成“核心转储”).我们可以认为 co ...
- 生成python 依赖文件
1.生成requirement 文件的两种方式 1. 'pip freeze ' > requirements.txt --会将环境中的依赖包全都加入(不推荐) 2. 项目用到生成依赖 '# 安 ...
- Linux平台 获取程序依赖文件
创建sh脚本文件 =========================================================== #!/bin/sh exe=$1 #发布的程序名称des=$2 ...
- Makefile 8——使用依赖关系文件
Makefile中存在一个include指令,它的作用如同C语言中的#include预处理指令.在Makefile中,可以通过include指令将自动生成的依赖关系文件包含进来,从而使得依赖关系文件中 ...
- make自动生成依赖文件的两种形式
最近编译源文件发现当修改头文件后,make并不会自动把包含此头文件的所有源文件重新编译,而每次都是需要把对应的中间文件清除才能重新编译,非常的麻烦.因此需要make自动对源文件所依赖的头文件进行管理, ...
- <linux系统c语言生成.so文件,生成64位可执行文件,在64位系统中运行32位的可执行文件>
1.linux 系统c语言生成.o文件,---->gcc -m64 -c -fPIC test.c -o test.o2.linux 系统c语言生成.so文件,----->gcc -sha ...
随机推荐
- vmware centos7 网络配置
1. 在vmware创建centos虚拟机 2. 在cmd下看一下本机所处的网段,并对一下vmware上的配置 如果同样处于同一网段(192.168.aaa.bbb,aaa处一致就行),就可以直接开机 ...
- flask models循环使用和migrate迁移脚本
使用models目的是为了将创建数据库模型的代码与主程序代码分离,migrate的作用就是在数据库字段改变时不用drop表直接做更新操作 新建 models.py exts.py manage.py ...
- Can't read swagger JSON from http://localhost:8080/Test/api-docs
新手入坑Swagger,搜了下网上博客,各种整合费时费力.弄出来竟然报错: Can't read swagger JSON from http://localhost:8080/Test/api-do ...
- win7安装linux CentOS7双系统实践
开发需求要安装linux,百度了些资料,当然仅供参考,否则入坑. 步骤一 :制作Centos 7镜像文件,这步没什么坑 1.准备U盘8G以上 下载的话网上很多,这里提供一个下载路径: http:// ...
- IO流----操作文件的9种方法代码实现
IO流----操作文件的9种方法代码实现: 1:使用字节流读写数据: 四种方式: method1: 每次读写一个字节,边读边写: /* * 复制文本文件. * * 数据源:从哪里来 ...
- Map接口、HashMap类、LinkedHashSet类
java.util.Map<K, V>接口 双列集合,key不可以重复 Map方法: 1.public V put(K key, V value):键值对添加到map,如果key不重复返回 ...
- 我的长大app开发教程第三弹:实现四个子页面绑定RadioButton
在开始之前先上一张图 在上一节中我们实现了底部Button,这一弹我们要实现点击四个按钮分别切换到不同页面,我们可以把页面分为两部分,顶部栏和中间内容部分,我们可以通过线性布局包裹两部分内容,顶部栏又 ...
- Win10 64位连接LJM1005打印机局域网访问
除了网上常见的开Guest用户之类需要额外三个设置 (1)安装LJM1005驱动LJM1005_Full_Solution (2)设置打印机共享和安全中的everyone全部勾选(解决能看到打印机无法 ...
- man termios(FreeBSD 12.0)
TERMIOS() FreeBSD Kernel Interfaces Manual TERMIOS() NAME termios - general terminal line discipline ...
- Docker(一)基本概念
摘自 https://mp.weixin.qq.com/s/mcIMBMNMrFD9OE56iujhXQ 一.容器和虚拟机的比较 1.虚拟机 对于以前熟悉的虚拟机,我们需要模拟操作系统和硬件.虚拟机一 ...