学习自狄泰软件学院唐佐临老师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