第18课 - make 中的路径搜索(下)
1. 问题一:当 VPATH 和 vpath 同时出现,make 会如何处理?
工程项目的目录结构如下图所示,src1 和 src2 中都包含了 func.c 文件,如果在 makefile 中使用 VPATH 指定了 src1 ,使用 vpath 指定了 src2,当 VPATH 和 vpath 同时存在时,make 会做出怎样的处理?
【编程实验】
makefile.1
VPATH := src1 CFLAGS := -I inc vpath %.c src2 vpath %.h inc app.out : func.o main.o @gcc -o $@ $^ @echo "Target File ==> $@" %.o : %.c func.h @gcc $(CFLAGS) -o $@ -c $<
执行 make 后的输出结果:
【实验结论】
make 搜索文件的次序如下:
make 首先在当前文件夹中搜索需要的文件;如果搜索失败,make 优先在 vpath 指定的文件夹中搜索目标文件;当 vpath 搜索失败时,转而搜索 VPATH 指定的文件夹。
2. 问题二:当使用 vpath 对同一个 Pattern 指定多个文件夹时,make 会如何处理?
工程项目的目录结构与问题一相同,src1 和 src2 中都包含了 func.c 文件,如果在 makefile 中使用 vpath 同时指定了两个src1 和 src2 两个目录,make 会做出怎样的处理?
【编程实验】
makefile.2
CFLAGS := -I inc vpath %.c src1 vpath %.c src2 vpath %.h inc app.out : func.o main.o @gcc -o $@ $^ @echo "Target File ==> $@" %.o : %.c func.h @gcc $(CFLAGS) -o $@ -c $<
执行 make 后的输出结果:(src1 出现在 src2 之前)
【实验结论】
当 makefile 中使用 vpath 对同一个 Pattern 指定了多个目录时,make 会以自上而下的顺序搜索 vpath 指定的文件夹,当找到目标文件时,搜索结束。
3. 问题三: 通过 VPATH 指定搜索路径后,make 如何决定目标文件的最终位置?
工程项目的目录结构如下图所示,查看 make 编译后当前目录下的内容,发现生成的可执行程序 app.out 在当前目录下。
makefile.3
GPATH := src VPATH := src CFLAGS := -I inc app.out : func.o main.o @gcc -o $@ $^ @echo "Target File ==> $@" %.o : %.c inc/func.h @gcc $(CFLAGS) -o $@ -c $<
如果此时把 app.out 移到 src 目录下,再次 make 编译,会出现什么样的情况?
当 make 编译时,发现 app.out 在当前目录下不存在,会搜索 VPATH 变量指定的路径,发现里面存在 app.out ,因此出现了上面的情况。
改动 fun.c 这个源文件,重新编译,发现在当前目录下生成了新的 app.out。
【实验结论】
(1)当 app.out 完全不存在
- make 在当前文件下创建 app.out
(2)当 src 文件夹中存在 app.out
- 所有目标和依赖的新旧关系不变,make 不会重新创建 app.out
- 当依赖文件被更新,make 在当前文件夹下创建 app.out
【问题】
当依赖改变时,如何使得 src 下的 app.out 被更新?
【解决方案】
使用 GPATH 特殊变量指定目标文件夹
GPATH := src
-
当 app.out 完全不存在时(当前目录和 src 中都不存在时),make 默认在当前文件夹创建 app.out。
-
当 app.out 存在于 src 中,且依赖文件被更新,make 在 src 中创建 app.out
【工程项目中的几点建议】
(1)尽量使用 vpath 为不同文件指定搜索路径
(2)不要在源码文件中生成目标文件
(3)为编译得到的结果创建独立的文件夹
(4)避免 VPATH 和 GPATH 特殊变量的使用
4. 补充
make 的一个隐式规则以及 VPATH 变量可能会触发这个隐式规则。
假如当前目录下没有 main.c 这个文件,而有 main.cpp 这个文件,make 会有什么样的行为?
可以看到当 make 找不到 main.c 文件时,发现依赖是 .o 文件,这就触发了 make 的隐式规则,寻找 main.cpp 文件并使用 g++ 进行编译。正好当前目录下有一个 main.cpp 文件,就产生了上图所示的结果。
这一结果与 vpath 和 VPATH 联系起来,如果项目中使用 VPATH 指定的路径下有 xx.cpp ,而恰好又触发了上述的隐式规则,在原本应该报错的地方,make 却正常执行了。
如果使用 vpath 就不会产生这种情况, vpath %.c dir,这种方式只会寻找 .c 文件,因此 make 触发的隐式规则不会找到 xx.cpp 文件,程序会报错。
从这个实验中可以得到一个项目经验,在实际的工程开发中,尽量使用 vpath 关键字而不使用 VPATH 变量,否则可能会产生意想不到的结果。