Makefile13--自动生成依赖关系(下) include关键字暗黑操作

本文深入探讨Makefile的高级用法,包括如何避免重复创建依赖文件、优化clean规则,以及理解include指令的特殊行为。通过具体实验,揭示了Makefile在处理依赖文件时的内部逻辑,以及include指令在不同场景下的运作机制。

学习自狄泰软件学院唐佐临老师Makefile课程,文章中图片取自老师的PPT,仅用于个人笔记。


实验1 :成功创建了.dep文件,并且将各个.dep文件 放到 deps文件夹下,但是 func.dep文件被重复创建
实验2 :修正 func.dep 文件被重复创建
实验3 :进一步优化,如果是 make clean 不包含 include关键字后面的内容进来。

实验4 include黑暗操作1:在 include 关键字前加 ‘-’ 会忽略错误信息 直接执行,所以我们平时不要加‘-’

实验5:include黑暗操作2 :在当前目录找不到对应文件 在对应规则中创建目标文件之后并写入内容之后,会将新创建的文件中的内容载入到 include 位置,如果内容是 一条规则 则成为了 当前makefile 中的第一条规则!!

实验6 include黑暗操作3 :当前目录存在 指定文件,makefile中include 该文件,并且存在对应的规则,而且规则的依赖属性比目标新的时候,会先执行对应规则,再执行 make 指定的规则 all


在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

实验1 :成功创建了.dep文件,并且将各个.dep文件 放到 deps文件夹下,但是 func.dep文件被重复创建

.PHONY : all clean

MKDIR := mkdir
RM := rm -fr
CC := gcc

DIR_DEPS := deps

#将所有当前目录中的.c作为后缀的文件的文件名作为列表拿到,并保存到变量 SRCS 中
SRCS := $(wildcard *.c)

#变量的值替换,替换后缀 生成.dep 文件名列表
DEPS := $(SRCS:.c=.dep)

# 在 生成的 .dep 文件名列表中的每一项 文件名前加上 deps/ 路径前缀
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))

#此时的 DEPS 是 : $(DIR_DEPS)/%.dep
include $(DEPS)

all : 
	@echo "all"

$(DIR_DEPS) :
	$(MKDIR) $@

#在创建 .dep 文件之前 先创建 deps/ 文件夹 用于存放 .dep文件
$(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c
	@echo "Creating $@ ..."
	@set -e; \
	$(CC) -MM -E $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@
	
clean :
	$(RM) $(DIR_DEPS)
	


mhr@ubuntu:~/work/makefile1$ make all
makefile:14: deps/main.dep: No such file or directory
makefile:14: deps/func.dep: No such file or directory
mkdir deps
Creating deps/func.dep ...
Creating deps/main.dep ...
Creating deps/func.dep ...
all
mhr@ubuntu:~/work/makefile1$ 

mhr@ubuntu:~/work/makefile1$ cd deps/
mhr@ubuntu:~/work/makefile1/deps$ ll
total 16
drwxrwxr-x 2 mhr mhr 4096 Dec 27 19:52 ./
drwxrwxr-x 3 mhr mhr 4096 Dec 27 19:52 ../
-rw-rw-r-- 1 mhr mhr   28 Dec 27 19:52 func.dep
-rw-rw-r-- 1 mhr mhr   28 Dec 27 19:52 main.dep
mhr@ubuntu:~/work/makefile1/deps$ 

结果分析:

首先警告当前目录没有 incude关键字所包含的文件名,所以找到对应的规则,执行规则命令,首先创建 deps文件夹,然后创建各个 .dep文件,并且写入依赖关系。最后执行 all.

问题:
为什么最后又执行了一次 Creating deps/func.dep … ,也就是为啥会多创建一次 func.dep呢?

在这里插入图片描述

...

#此时的 DEPS 是 : $(DIR_DEPS)/%.dep
include $(DEPS)

...

#在创建 .dep 文件之前 先创建 deps/ 文件夹 用于存放 .dep文件
$(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c
	@echo "Creating $@ ..."
	@set -e; \
	$(CC) -MM -E $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@
	
...

首先包含 include关键字包含的文件,当前目录并没有该文件存在,所以在makefile中寻找对应的规则,根据我们自己实验的输出可以知道首先创建的是 func.dep ,func.dep创建好之后,make 就会将对应的依赖关系记录下来,

$(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c

因为这条规则已经被实际的解析出来了,func.dep 要依赖于 文件夹DIR_DEPS 与 func.c。接下来就是创建main.dep,创建好main.dep之后,make 突然发现 在之前记录的 func.dep的依赖关系中 其中的依赖 文件夹DIR_DEPS的时间属性更新了,这是因为 又在该文件夹中创建了 main.dep文件,文件夹DIR_DEPS的时间戳自然就被更新了。所以 依赖 文件DIR_DEPS 比他对应的目标更新,所以 make又执行了一次 func.dep对应的规则

 $(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c

在这里插入图片描述

实验2 :修正 func.dep 文件被重复创建

.PHONY : all clean

MKDIR := mkdir
RM := rm -fr
CC := gcc

DIR_DEPS := deps

SRCS := $(wildcard *.c)
DEPS := $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))


all : 
	@echo "all"

include $(DEPS)


$(DIR_DEPS) :
	$(MKDIR) $@

#判断 文件夹是否已经被创建 根据条件 来重新生成规则,当发现 func.dep 的依赖更新时 想要重新
#  执行func.dep对应的规则, 但是这里加了条件 如果已经存在而 文件夹 就改变 func.dep 的规则 ,让他
#  只依赖 func.c 。依赖没有更新,不会执行规则。所以最后  func.dep 不会被重新创建。

ifeq ("$(wildcard $(DIR_DEPS))", "")
$(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c
else
$(DIR_DEPS)/%.dep : %.c
endif
	@echo "Creating $@ ..."
	@set -e; \
	$(CC) -MM -E $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@
	
clean :
	$(RM) $(DIR_DEPS)
	


mhr@ubuntu:~/work/makefile1$ make all
makefile:19: deps/main.dep: No such file or directory
makefile:19: deps/func.dep: No such file or directory
mkdir deps
Creating deps/func.dep ...
Creating deps/main.dep ...
all
mhr@ubuntu:~/work/makefile1$ 

实验3 :进一步优化,如果是 make clean 不包含 include关键字后面的内容进来。

.PHONY : all clean

MKDIR := mkdir
RM := rm -fr
CC := gcc

DIR_DEPS := deps

SRCS := $(wildcard *.c)
DEPS := $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))


all : 
	@echo "all"

#通过预定义变量 检测 make 后的参数  all
ifeq ("$(MAKECMDGOALS)", "all")
-include $(DEPS)
endif
	、

#通过预定义变量 检测 make 后的参数  空
ifeq ("$(MAKECMDGOALS)", "")
-include $(DEPS)
endif

$(DIR_DEPS) :
	$(MKDIR) $@

ifeq ("$(wildcard $(DIR_DEPS))", "")
$(DIR_DEPS)/%.dep : $(DIR_DEPS) %.c
else
$(DIR_DEPS)/%.dep : %.c
endif
	@echo "Creating $@ ..."
	@set -e; \
	$(CC) -MM -E $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]*,objs/\1.o : ,g' > $@
	
clean :
	$(RM) $(DIR_DEPS)

在这里插入图片描述

实验4 include黑暗操作1:在 include 关键字前加 ‘-’ 会忽略错误信息 直接执行,所以我们平时不要加‘-’

.PHONY : all

include test.txt

all : 
	@echo "this is all"



mhr@ubuntu:~/work/makefile1$ 
mhr@ubuntu:~/work/makefile1$ make all
makefile:3: test.txt: No such file or directory
make: *** No rule to make target 'test.txt'.  Stop.
mhr@ubuntu:~/work/makefile1$ 、

-改成 -include test.txt 之后 就会忽略报错,直接执行!

.PHONY : all

-include test.txt

all : 
	@echo "this is all"

mhr@ubuntu:~/work/makefile1$ make all
this is all
mhr@ubuntu:~/work/makefile1$ 

在这里插入图片描述

实验5:include黑暗操作2 :在当前目录找不到对应文件 在对应规则中创建目标文件之后并写入内容之后,会将新创建的文件中的内容载入到 include 位置,如果内容是 一条规则 则成为了 当前makefile 中的第一条规则!!

.PHONY : all

-include test.txt

all : 
	@echo "this is all"
	
test.txt :
	@echo "creating $@ ..."
	@echo "other : ; @echo "this is other" " > test.txt

mhr@ubuntu:~/work/makefile1$ make all
creating test.txt ...
this is all
mhr@ubuntu:~/work/makefile1$ 
mhr@ubuntu:~/work/makefile1$ ls
deps  func.c  func.h  func.o main.c main.o  makefile  test.txt //  test.txt 创建成功
mhr@ubuntu:~/work/makefile1$ 

test.txt

other : ; @echo this is other 

现在接着做实验,rm -rf test.txt 然后make(不是make all)

mhr@ubuntu:~/work/makefile1$ ls
func.c  func.h  main.c  makefile
mhr@ubuntu:~/work/makefile1$ 
mhr@ubuntu:~/work/makefile1$ 
mhr@ubuntu:~/work/makefile1$ make
creating test.txt ...
this is other
mhr@ubuntu:~/work/makefile1$ 

注意结果!!! 按照我们预想,首先在当目录寻找 include关键字包含的文件,并没有发现,所以去执行对应的规则,创建 text.txt,然后 make all 才对呀! 但是为什么这里没有执行 make all 反而打印了 this is other.为什么呢?

答案:在创建 test.txt 的时候,test.txt里面的内容被写成了 :other : ; @echo "this is other
是一条 makefile 里面的规则,创建完 test.txt之后,test.txt里面的内容会被载入到 makefile中的 include 位置!!所以此时 makefile 的最顶上的第一条规则是 other : ; @echo "this is other。而make 不带参数的时候 默认执行的是 第一条规则!! 所以没有执行到 make all


在这里插入图片描述

实验6 include黑暗操作3 :当前目录存在 指定文件,makefile中include 该文件,并且存在对应的规则,而且规则的依赖属性比目标新的时候,会先执行对应规则,再执行 make 指定的规则 all

创建 b.txt,并且已经存在了 test.txt

.PHONY : all

-include test.txt

all : 
	@echo "this is all"
	
test.txt : b.txt
	@echo "creating $@ ..."
		
		
mhr@ubuntu:~/work/makefile1$ touch b.txt  //更新文件时间戳
mhr@ubuntu:~/work/makefile1$ ls
b.txt  func.c  func.h  main.c  makefile  test.txt
mhr@ubuntu:~/work/makefile1$ 
mhr@ubuntu:~/work/makefile1$ make all
creating test.txt ...
this is all
mhr@ubuntu:~/work/makefile1$ 

结果出了打印了预料到的 all 目标,居然也打印了 test.txt 目标,这是为什么呢? 当前文件夹明明已经存在了 test.txt文件了啊,怎么还会执行对应的规则呢???

答案 make all 之后 先来包含 include test.txt ,包含进来之后,make 突然发现 makefie 中存在文件对应的规则,并且还存在依赖,依赖的时间属性还比目标更新,这时候 make 就会去执行 对应的规则了,执行完规则之后 在执行 all 规则。


实验7

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ma浩然

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值