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

1. 问题一

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

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

  

【编程实验】

 #include <stdio.h>
#include "func.h" void foo()
{
printf("void foo() : %s\n", "This file is from src1 ...");
}

src1目录中的func.c文件

 #include <stdio.h>
#include "func.h" void foo()
{
printf("void foo() : %s\n", "This file is from src2 ...");
}

src2目录中的func.c文件

 VPATH := src1  # 使用VPATH指定src1
CFLAGS := -I inc vpath %.c src2 #使用vpath指定src2
vpath %.h inc app.out : func.o main.o
@gcc -o $@ $^
@echo "Target File ==> $@" %.o : %.c func.h
@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 会做出怎样的处理?

  

【编程实验】

 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 $<

vpath指定多个文件夹

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

  

【实验结论】

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

  

3. 问题三

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

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

    

 VPATH := src
CFLAGS := -I inc app.out : func.o main.o
gcc -o $@ $^ %.o : %.c inc/func.h
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)避免 VPATHGPATH 特殊变量的使用

4. 补充

  make 的一个隐式规则以及 VPATH 变量可能会触发这个隐式规则。

  

  假如当前目录下没有 main.c 这个文件,而有 main.cpp 这个文件,make 会有什么样的行为?

  

  可以看到当 make 找不到 main.c 文件时,发现依赖是 .o 文件,这就触发了 make 的隐式规则,寻找 main.cpp 文件并使用 g++ 进行编译。正好当前目录下有一个 main.cpp 文件,就产生了上图所示的结果。

  这一结果与 vpathVPATH 联系起来,如果项目中使用 VPATH 指定的路径下有 xx.cpp ,而恰好又触发了上述的隐式规则,在原本应该报错的地方,make 却正常执行了。

  如果使用 vpath 就不会产生这种情况, vpath  %.c  dir,这种方式只会寻找 .c 文件,因此 make 触发的隐式规则不会找到 xx.cpp 文件,程序会报错。

  从这个实验中可以得到一个项目经验,在实际的工程开发中,尽量使用 vpath 关键字而不使用 VPATH 变量,否则可能会产生意想不到的结果。

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

狄泰QQ群:199546072

第18课 - make 中的路径搜索(下)的更多相关文章

  1. 第17课 - make 中的路径搜索(上)

    第17课 - make 中的路径搜索(上) 1. 问题 在以往的 make 学习中,我们使用到的 .c 文件和 .h 文件都与 makefile 处在同一个路径.在实际的工程项目中,所有的源文件和头文 ...

  2. 第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据

    第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据 ADO.NET 为什么要学习? 我们要搭建一个平台(Web/Winform ...

  3. 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效

    数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...

  4. Linux中/proc目录下文件详解

    转载于:http://blog.chinaunix.net/uid-10449864-id-2956854.html Linux中/proc目录下文件详解(一)/proc文件系统下的多种文件提供的系统 ...

  5. struts2 jsp表单提交后保留表单中输入框中的值 下拉框select与input

    原文地址:struts2 jsp表单提交后保留表单中输入框中的值 下拉框select与input jsp页面 1     function dosearch() {2         if ($(&q ...

  6. Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询

    原文:Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询 如果允许在UI层直接访问Linq to Sql的DataContext,可以省去很多问题,譬如在处理多表join的时候, ...

  7. Linux中/proc目录下文件详解(转贴)

      转载:http://www.sudu.cn/info/index.php?op=article&id=302529   Linux中/proc目录下文件详解(一) 声明:可以自由转载本文, ...

  8. 将MySQL库的表转入到MSSQL中的某个库中(Employees下的Employees表 → pubs库下)_2

    将MySQL库的表转入到MSSQL中的某个库中(Employees下的Employees表 → pubs库下, 此pubs下的表名是employee,不冲突),方法大致以下几个(另有其他方法待补充), ...

  9. Scala 深入浅出实战经典 第49课 Scala中Variance代码实战(协变)

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

随机推荐

  1. CheckList:ACL 2020 Best Paper

    Beyond Accuracy: Behavior Testing of NLP Models with CheckList. Marco Tulio Ribeiro, Tongshuang Wu, ...

  2. 个人电脑搭建ftp----------------2

    个人电脑搭建ftp 从上一次搭建好的局域网继续完成我的后续. 打开windows10 控制面板 点击启用或关闭windows功能 找到Internet Information Services,开启所 ...

  3. GAN量化评估方法——IS(Inception Score)和FID(Frechet Inception Distance score)

    生成模型产生的是高维的复杂结构数据,它们不同于判别模型,很难用简单的指标来评估模型的好坏.下面介绍两种当前比较流行的评估生成模型的指标(仅判别图像):IS(Inception Score)和FID(F ...

  4. JavaScript设计模式之命令模式【命令解耦】

    在讲解命令模式之前我们先来了解一个生活中的命令模式场景: 场景1: 医院看病抓药: 当你因为肾虚到医院看医生,医生一番操作之后得出结论:要吃个疗程[夏桑菊].[小柴胡](药名纯属虚构,真的肾虚就找医生 ...

  5. Mybatis入门(二)------增删改查

    Mybatis增删改查基本操作 一.XML实现方式 1.mapper.xml的配置 <?xml version="1.0" encoding="UTF-8" ...

  6. golang 判断IPv4 or IPv6 address

    import strings func IsIPv4(address string) bool { return strings.Count(address, ":") < ...

  7. Java实现树形结构的数据转Json格式

    在项目中难免会用到树形结构,毕竟这是一种常用的组织架构.楼主这里整理了两个实现的版本,可以直接拿来使用,非常方便. 楼主没有单独建项目,直接在以前的一个Demo上实现的.第一种,看下面代码: pack ...

  8. @RequestBody和@RequestParam

    @RequestBody的使用 https://blog.csdn.net/justry_deng/article/details/80972817 (@RequestBody Map map)接收多 ...

  9. wampserver64 apache2.4版本局域网互相访问总结

    wampserver64  apache2.4版本局域网互相访问总结 背景:在我的电脑上给算法组开发了一个工具,需要在局域网环境下其他同事都能访问到,搞了一下午终于搞定,于是整理了这篇文档,给其他同行 ...

  10. Unity Prefab关联

    Unity3D研究院之Prefab里面的Prefab关联问题http://www.xuanyusong.com/archives/3042