第18课

第18课 - make 中的路径搜索(下)

1. 问题一

  当 VPATH vpath 同时出现,make 会如何处理?

  工程项目的目录结构如下图所示,src1 src2 中都包含了 func.c 文件,如果在 makefile 中使用 VPATH 指定了 src1 ,使用 vpath 指定了 src2,当 VPATH vpath 同时存在时,make 会做出怎样的处理?

  

【编程实验】

1 #include <stdio.h>
2 #include "func.h"
3 
4 void foo()
5 {
6     printf("void foo() : %s
", "This file is from src1 ...");
7 }
src1目录中的func.c文件
1 #include <stdio.h>
2 #include "func.h"
3 
4 void foo()
5 {
6     printf("void foo() : %s
", "This file is from src2 ...");
7 }
src2目录中的func.c文件
 1 VPATH := src1  # 使用VPATH指定src1
 2 CFLAGS := -I inc
 3 
 4 vpath %.c src2    #使用vpath指定src2
 5 vpath %.h inc
 6 
 7 app.out : func.o main.o
 8     @gcc -o $@ $^
 9     @echo "Target File ==> $@"
10 
11 %.o : %.c func.h
12     @gcc $(CFLAGS) -o $@ -c $<
VPATH和vpath同时出现,make的处理方式

  执行 make 后的输出结果:

  

【实验结论】

  make 搜索文件的次序如下:

  make 首先在当前文件夹中搜索需要的文件,如果搜索失败,make 优先在 vpath 指定的文件夹中搜索目标文件,当 vpath 搜索失败时,转而搜索 VPATH 指定的文件夹。

  

2. 问题二

   当使用 vpath 对同一个 Pattern 指定多个文件夹时,make 会如何处理?

  工程项目的目录结构与问题一相同,src1 和 src2 中都包含了 func.c 文件,如果在 makefile 中使用 vpath 同时指定了两个src1 src2 两个目录,make 会做出怎样的处理?

  

【编程实验】

 1 CFLAGS := -I inc
 2 
 3 vpath %.c src1
 4 vpath %.c src2
 5 
 6 vpath %.h inc
 7 
 8 app.out : func.o main.o
 9     @gcc -o $@ $^
10     @echo "Target File ==> $@"
11 
12 %.o : %.c func.h
13     @gcc $(CFLAGS) -o $@ -c $<
14 
15     
vpath指定多个文件夹

  执行 make 后的输出结果:(src1 出现在 src2 之前)

  

【实验结论】

  当 makefile 中使用 vpath 对同一个 Pattern 指定了多个目录时,make 会以自上而下的顺序搜索 vpath 指定的文件夹,当找到目标文件时,搜索结束。

  

3. 问题三

   通过 VPATH 指定搜索路径后,make 如何决定目标文件的最终位置?

  工程项目的目录结构如下图所示,查看 make 编译后当前目录下的内容,发现生成的可执行程序 app.out 在当前目录下。

    

1 VPATH := src
2 CFLAGS := -I inc
3 
4 app.out : func.o main.o
5     gcc -o $@ $^
6     
7 %.o : %.c inc/func.h
8     gcc $(CFLAGS) -o $@ -c $<
Makefile

  如果此时把 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 变量,否则可能会产生意想不到的结果。

注:本文整理于《狄泰12月提升计划》课程内容

狄泰QQ群:199546072

原文地址:https://www.cnblogs.com/shiwenjie/p/8372187.html