DoubleLi

qq: 517712484 wx: ldbgliet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  4737 随笔 :: 2 文章 :: 542 评论 :: 1615万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

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

下面我们以一个简单的例子来说明如何自动生成依赖关系:

exm/

     main.c

     s.c

     s.h

makefile文件内容如下:

all:a

src=$(wildcard *.c)

obj:=$(patsubst %.c,%.o,$(src))

ifneq($(MAKECMDGOALS),clean)

-include$(src:.c=.d)

endif

a:$(obj)

gcc$(obj)-o $@

%.d:%.c

set-e;rm -f $@; \

gcc-MM$(CPPFLAGS) $< > $@.

 

; \

 

sed's,$\.o[:]*,\1.o $@ : ,g' < $@.

 

> $@; \

 

rm-f$@.

 

 

%.o:%.c

@echo'Buildingfile: $<'

@echo'Invoking:GCC C Compiler'

gcc-O0-g3 -Wall -c -o "$@" "$<"

@echo'Finishedbuilding: $<'

@echo''

 

其中wildcard作用就是将指定目录下.c文件全部找出,所以这里src=main.cs.c

patsubst作用是把$(src)中的.c全部换为.o,于是obj=main.os.o

include$(src:.c=.d)相当于includemain.ds.d

由于此时这两个文件并不存在,所以会出现下面提示:

makefile:6:main.d:没有那个文件或目录

makefile:6:s.d:没有那个文件或目录

如果不想要这个提示,可以将include替换为-include

尽管一开始找不到.d文件,所以make会报警告。但是make会把include的文件名也当作目标来尝试更新,而这些目标适用模式规则%.d:%c

注意,虽然在Makefile中这个命令写了四行,但其实是一条命令,make只创建一个Shell进程执行这条命令,这条命令分为5个子命令,用;号隔开,并且为了美观,用续行符\拆成四行来写。执行步骤为:

1)set-e命令设置当前Shell进程为这样的状态:如果它执行的任何一条命令的退出状态非零则立刻终止,不再执行后续命令。@表示makefile执行这条命令时不显示出来

2)把原来的.d文件删掉。

3)$<依赖的目标集(即*.c), -MM:表示生成文件依赖关系,$@:表示生成的目标文件(即*.d),$$:表示本身的ProcessID。注意,在Makefile中$有特殊含义,如果要表示它的字面意思则需要写两个$,所以Makefile中的四个$传给Shell变成两个$,两个$在Shell中表示当前进程的id,一般用它给临时文件起名,以保证文件名唯一。

4)这个sed命令比较复杂,就不细讲了,主要作用是查找替换,并加入.d的依赖关系。

5)最后把临时文件删掉。

 

不管是Makefile本身还是被它包含的文件,只要有一个文件在make过程中被更新了,make就会重新读取整个Makefile以及被它包含的所有文件,现在main.dstack.dmaze.d都生成了,就可以正常包含进来了,相当于在Makefile中添了下面规则:

main.omain.d : main.c s.h

s.os.d : s.c s.h

当源或头文件修改时,如果依赖关系发生变化,执行makefile时将更新具有依赖关系的.d文件,而.d文件的更新又促使make重新读取makefile文件,把新的.d文件包括进来,于是新的依赖关系被建立。

除了上面方法外,还可使用GCC的-MMD-MP -MF -MT选项,如下,可起到同样目的:

all:a

src=$(wildcard *.c)

obj:=$(patsubst %.c,%.o,$(src))

ifneq($(MAKECMDGOALS),clean)

-include$(src:.c=.d)

endif

a:$(obj)

gcc$(obj)-o $@

%.o:%.c

@echo'Buildingfile: $<'

@echo'Invoking:GCC C Compiler'

gcc-O0-g3 -Wall -c -fmessage-length=0 -MMD -MP-MF"$(@:%.o=%.d)"-MT"$(@:%.o=%.d)" -o "$@""$<"

@echo'Finishedbuilding: $<'

@echo''

 

posted on   DoubleLi  阅读(3785)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2015-12-21 ARM-Linux配置DHCP自动获取IP地址
2015-12-21 Linux中的syslog 入门学习教程
2014-12-21 Nginx 模块开发(1)—— 一个稍稍能说明问题模块开发 Step By Step 过程
2014-12-21 Nginx Http模块开发
2014-12-21 nginx模块开发获取post参数
2014-12-21 nginx上传模块nginx_upload_module和nginx_uploadprogress_module模块进度显示,如何传递GET参数等。
2014-12-21 nginx自定义模块编写-根据post参数路由到不同服务器
点击右上角即可分享
微信分享提示