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 $@ main.o: main.h stack.h maze.h
stack.o: stack.h main.h
maze.o: maze.h main.h clean:
-rm main *.o .PHONY: clean
按照惯例,用all
做缺省目标。现在还有一点比较麻烦,在写main.o
、stack.o
和maze.o
这三个目标的规则时要查看源代码,找出它们依赖于哪些头文件,这很容易出错,一是因为有的头文件包含在另一个头文件中,在写规则时很容易遗漏,二是如果以后修改源代码改变了依赖关系,很可能忘记修改Makefile的规则。为了解决这个问题,可以用gcc
的-M
选项自动生成目标文件和源文件的依赖关系:
$ gcc -M main.c
main.o: main.c /usr/include/stdio.h /usr/include/features.h /
/usr/include/sys/cdefs.h /usr/include/bits/wordsize.h /
/usr/include/gnu/stubs.h /usr/include/gnu/stubs-.h /
/usr/lib/gcc/i486-linux-gnu/4.3./include/stddef.h /
/usr/include/bits/types.h /usr/include/bits/typesizes.h /
/usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h /
/usr/lib/gcc/i486-linux-gnu/4.3./include/stdarg.h /
/usr/include/bits/stdio_lim.h /usr/include/bits/sys_errlist.h main.h /
stack.h maze.h
-M
选项把stdio.h
以及它所包含的系统头文件也找出来了,如果我们不需要输出系统头文件的依赖关系,可以用-MM
选项:
$ gcc -MM *.c
main.o: main.c main.h stack.h maze.h
maze.o: maze.c maze.h main.h
stack.o: stack.c stack.h main.h
接下来的问题是怎么把这些规则包含到Makefile中,GNU make
的官方手册建议这样写:
all: main main: main.o stack.o maze.o
gcc $^ -o $@ clean:
-rm main *.o .PHONY: clean sources = main.c stack.c maze.c include $(sources:.c=.d) %.d: %.c
set -e; rm -f $@; /
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; /
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; /
rm -f $@.$$$$
sources
变量包含我们要编译的所有.c
文件,$(sources:.c=.d)
是一个变量替换语法,把sources
变量中每一项的.c
替换成.d
,所以include
这一句相当于:
include main.d stack.d maze.d
类似于C语言的#include
指示,这里的include
表示包含三个文件main.d
、stack.d
和maze.d
,这三个文件也应该符合Makefile的语法。如果现在你的工作目录是干净的,只有.c
文件、.h
文件和Makefile
,运行make
的结果是:
$ make
Makefile:: main.d: No such file or directory
Makefile:: stack.d: No such file or directory
Makefile:: maze.d: No such file or directory
set -e; rm -f maze.d; /
cc -MM maze.c > maze.d.$$; /
sed 's,/(maze/)/.o[ :]*,/1.o maze.d : ,g' < maze.d.$$ > maze.d; /
rm -f maze.d.$$
set -e; rm -f stack.d; /
cc -MM stack.c > stack.d.$$; /
sed 's,/(stack/)/.o[ :]*,/1.o stack.d : ,g' < stack.d.$$ > stack.d; /
rm -f stack.d.$$
set -e; rm -f main.d; /
cc -MM main.c > main.d.$$; /
sed 's,/(main/)/.o[ :]*,/1.o main.d : ,g' < main.d.$$ > main.d; /
rm -f main.d.$$
cc -c -o main.o main.c
cc -c -o stack.o stack.c
cc -c -o maze.o maze.c
gcc main.o stack.o maze.o -o main
一开始找不到.d
文件,所以make
会报警告。但是make
会把include
的文件名也当作目标来尝试更新,而这些目标适用模式规则%.d: %c
,所以执行它的命令列表,比如生成maze.d
的命令:
set -e; rm -f maze.d; /
cc -MM maze.c > maze.d.$$; /
sed 's,/(maze/)/.o[ :]*,/1.o maze.d : ,g' < maze.d.$$ > maze.d; /
rm -f maze.d.$$
注意,虽然在Makefile中这个命令写了四行,但其实是一条命令,make
只创建一个Shell进程执行这条命令,这条命令分为5个子命令,用;
号隔开,并且为了美观,用续行符/
拆成四行来写。执行步骤为:
set -e
命令设置当前Shell进程为这样的状态:如果它执行的任何一条命令的退出状态非零则立刻终止,不再执行后续命令。把原来的
maze.d
删掉。重新生成
maze.c
的依赖关系,保存成文件maze.d.1234
(假设当前Shell进程的id是1234)。注意,在Makefile中$
有特殊含义,如果要表示它的字面意思则需要写两个$,所以Makefile中的四个$传给Shell变成两个$,两个$在Shell中表示当前进程的id,一般用它给临时文件起名,以保证文件名唯一。这个
sed
命令比较复杂,就不细讲了,主要作用是查找替换。maze.d.1234
的内容应该是maze.o: maze.c maze.h main.h
,经过sed
处理之后存为maze.d
,其内容是maze.o maze.d: maze.c maze.h main.h
。最后把临时文件
maze.d.1234
删掉。
不管是Makefile本身还是被它包含的文件,只要有一个文件在make
过程中被更新了,make
就会重新读取整个Makefile以及被它包含的所有文件,现在main.d
、stack.d
和maze.d
都生成了,就可以正常包含进来了(假如这时还没有生成,make
就要报错而不是报警告了),相当于在Makefile中添了三条规则:
main.o main.d: main.c main.h stack.h maze.h
maze.o maze.d: maze.c maze.h main.h
stack.o stack.d: stack.c stack.h main.h
如果我在main.c
中加了一行#include "foo.h"
,那么:
1、main.c
的修改日期变了,根据规则main.o main.d: main.c main.h stack.h maze.h
要重新生成main.o
和main.d
。生成main.o
的规则有两条:
main.o: main.c main.h stack.h maze.h
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
第一条是把规则main.o main.d: main.c main.h stack.h maze.h
拆开写得到的,第二条是隐含规则,因此执行cc
命令重新编译main.o
。生成main.d
的规则也有两条:
main.d: main.c main.h stack.h maze.h
%.d: %.c
set -e; rm -f $@; /
$(CC) -MM $(CPPFLAGS) $< > $@.$$$$; /
sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; /
rm -f $@.$$$$
因此main.d
的内容被更新为main.o main.d: main.c main.h stack.h maze.h foo.h
。
2、由于main.d
被Makefile包含,main.d
被更新又导致make
重新读取整个Makefile,把新的main.d
包含进来,于是新的依赖关系生效了。
------------------------
问题来了,Visual Studio的C++ 的获得头文件依赖的命令是很什么呢?【即 cl.exe 系列工具 参数】
CPLUSPLUS 获得 一个源文件的头文件依赖。即该文件所需要的所有头文件的更多相关文章
- Makefile自动生成头文件依赖
前言 Makefile自动生成头文件依赖是很常用的功能,本文的目的是想尽量详细说明其中的原理和过程. Makefile模板 首先给出一个本人在小项目中常用的Makefile模板,支持自动生成头文件依赖 ...
- Makefile中自动生成头文件依赖
为什么需要自动生成头文件依赖? 编译单个源文件时,需要获取文件中包含的头文件的信息,但是一般的Makefile不会在规则中明确写明文件依赖的头文件,所以单独修改头文件后,不会导致包含头文件的源文件重新 ...
- C语言学习_C如何在一个文件里调用另一个源文件中的函数
问题 C如何在一个文件里调用另一个源文件中的函数,如题. 解决办法 当程序大了代码多了之后,想模块化开发,不同文件中存一点,是很好的解决办法,那我们如何做才能让各个文件中的代码协同工作呢?我们知道,m ...
- [转] 关于c++的头文件依赖
http://www.cnblogs.com/yvesliao/p/3938730.html PS: 使用单向依赖 正在看google c++编程规范,里面对头文件依赖是这么说的: 1 2 3 4 5 ...
- 未能加载文件或程序集“Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”或它的某一个依赖项。系统找不到指定的文件
发布的打包项目在本机测试好使,部署到客户服务器上报错 分析器错误消息: 未能加载文件或程序集“Microsoft.ReportViewer.WebForms, Version=10.0.0.0, Cu ...
- 关于c++的头文件依赖
正在看google c++编程规范,里面对头文件依赖是这么说的: 使用前置声明(forward declarations)尽量减少.h文件中#include的数量. 当一个头文件被包含的同时也引入了一 ...
- 机房重构所遇问题"未能载入文件或程序集“DAL”或它的某一个依赖项。系统找不到指定的文件"的解决的方法集锦
敲七层登录的时候.忽然间认为敲三层搞清的思路瞬间又凌乱了.花了一天的时间边敲边梳理,最终整完了,执行的时候弹出了这种错误:未能载入文件或程序集"DAL"或它的某一个依赖项. 系统找 ...
- Error-ASP.NET:未能加载文件或程序集“CMSCalendar”或它的某一个依赖项。系统找不到指定的文件。
ylbtech-Error-ASP.NET:未能加载文件或程序集“CMSCalendar”或它的某一个依赖项.系统找不到指定的文件. 1.返回顶部 1. “/”应用程序中的服务器错误. 分析器错误 说 ...
- 未能加载文件或程序集“Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5”或它的某一个依赖项。系统找不到指定的文件。
在创建ASP.NET MVC项目过程中发生了这个异常 未能加载文件或程序集"Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0 ...
随机推荐
- UE4新手编程之创建空白关卡和添加碰撞体
让我们接着上次继续学习UE4引擎,今天我们学习下怎样创建空白的关卡以及添加碰撞物体. 一. 创建空白关卡 1) 点击文件 -> 新建关卡(或者按快捷键Ctrl+N). 2) 你可以选择Defau ...
- [代码审计]phpshe开源商城后台两处任意文件删除至getshell
0x00 背景 这套系统审了很久了,审计的版本是1.6,前台审不出个所以然来.前台的限制做的很死. 入库的数据都是经过mysql_real_escape_string,htmlspecialchars ...
- OpenStack Juno 版本发布——支持Spark和NFV[转]
作者:郑晨,OpenStack中国社区,转载请注明出处 美国时间2014年10月16日,OpenStack Juno版本正式发布,这是OpenStack开源云计算项目自2010年创立以来的第10个版本 ...
- Codeforces Round #374 (Div. 2) D. Maxim and Array 贪心
D. Maxim and Array 题目连接: http://codeforces.com/contest/721/problem/D Description Recently Maxim has ...
- Springboot 线程池配置
最近的项目里要手动维护线程池,然后看到一起开发的小伙伴直接用Java了,我坚信Springboot不可能没这功能,于是查了些资料,果然有,这里给一下. 首先我们都知道@Async标签能让方法异步执行, ...
- Java删除ArrayList中的重复元素
Java删除ArrayList中的重复元素的2种方法 ArrayList是Java中最常用的集合类型之一.它允许灵活添加多个null元素,重复的元素,并保持元素的插入顺序.在编码时我们经常会遇到那种必 ...
- mysql_提示 Lock wait timeout exceeded解决办法
我的mysql报这个错 err=1205 - Lock wait timeout exceeded; try restarting transaction 利用 SHOW PROCESSLIST来查看 ...
- 关于使用react的思考
1. 组件化开发:将可以复用的部分独立封装成一个组件,每个部分的数据互不影响
- Revit手工创建族
手工创建族 1.画两个参考平面. 图3001 2.点击族类型,添加参数. 图3002,3003 3.添加类型,为类型赋值. 3004 4.创建拉伸截面,完成后,可以三维查看. 3005 5.创建对齐, ...
- 报错:此版本的SQL Server Data Tools与此计算机中安装的数据库运行时组件不兼容
在Visual Studio 2012中使用Entity Framework,根据模型生成数据库时,报如下错误: 无法在自定义编辑器中打开Transact-SQL文件此版本的SQL Server Da ...