Makefile13--自动生成依赖关系(下) 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

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

发布了192 篇原创文章 · 获赞 100 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/LinuxArmbiggod/article/details/103742554