#1.两种依赖关系
如果出现这种形式的依赖关系 a : b | c,其中a和b是常见的依赖关系,主要包括两个方面:,一个是b必须在a之前生成,另一个则是如果b比a新,则a必须重新生成。而a和c的依赖关系则比较特殊,是一种顺序依赖,也就是c必须要在a之前生成,但c是否比a新并不影响是否需要重新生成a。
关于哪些场景下会需要a和c之间的这种依赖关系,我举个例子来说明下,比如a.o依赖a.cpp,并且你需要a.o存放在目录build下面,那么你可以这样写,a.o : a.cpp | build,这样就能够保证build在你生成a.o之前是存在的,并且如果在build目录下添加了文件或做了其他会修改目录build的timestamp的操作时,并不会导致a.o的重新生成。
下面是截图自gnu make手册的关于这种关系的讲解。
#2.自动生成依赖关系
一般写小型项目时,我们才会手动把各个文件之间的依赖关系写出来,但是当项目稍微大些时,手动写不仅麻烦而且容易出错或写漏,更重要的是如果你后面修改文件导致依赖关系也发生改变,还必须再次修改makefile文件。
我们可以利用g++的一些编译选项来帮助我们自动生成依赖关系,下面我举个例子来说明下:
我们有a.cpp文件,这个文件include几个头文件,包括a.h,b.h,c.h,我们可以在makefile中这样写:
a.o: a.cpp
g++ a.cpp -c -o a.o -MMD $(CFLAGS)
-include a.d
选项-MMD会将依赖关系保存在文件a.d(该文件名字由-o指定的文件名后缀改成.d得到),-include的表示即使文件不存在也不出错,因为在第一次运行makefile文件时,a.d文件是不存在的所以我们需要使用-include而不是include。同时也因为第一次运行时a.o文件是不存在的,所以语句g++ a.cpp -c -o a.o -MMD $(CFLAGS)是肯定会被执行的,并且会产生依赖文件a.d,a.d的内容如下:a.o: a.cpp a.h b.h c.h
那么在之后运行这个makefile文件时,a.d文件已经存在了,所以-include a.d会把a.d的内容包含在makefile文件中,此时a.o的多行依赖目标(makefile中的和include进来的a.d中的)会合并到一起,也就是相当于是将makefile的内容变成了a.o: a.cpp a.h b.h c.h
g++ a.cpp -c -o a.o -MMD $(CFLAGS)
此时任何一个文件(a.cpp,a.h,b.h,c.h)修改了,a.o都会被重新生成,于是我们就达成了让makefile自动生成依赖关系的目标啦。