第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. LeetCode 92 | 大公司常考的面试题,翻转链表当中指定部分

    今天是LeetCode专题的第58篇文章,我们一起来看看LeetCode 92题,翻转链表II(Reverse LInked List II). 这题的官方难度是Medium,2451个赞同,145个 ...

  2. Docker入门教程-Linux环境安装Nginx及入门使用

    介绍 Nginx("engine x")是一款是由俄罗斯的程序设计师Igor Sysoev所开发高性能的 Web和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服 ...

  3. kvm-virtualization – 删除“孤儿”libvirt快照

    原文链接:https://codeday.me/bug/20181110/371346.html 创建快照: virsh snapshot-create-as --domain prod snap - ...

  4. 关于ACID,BASE和CAP定理的探究

    前言 当我看到"根据CAP理论,由于分布式系统必须保证分区容错性,所以只能选择AP原则或者CP原则"这种结论时,我感到很疑惑: 什么是分区容错性? 为什么分布式系统必须保证分区容错 ...

  5. 微信支付宝个人免签约即时到帐接口开发附demo

    支付界面: 扫码支付界面: 付成功后可以跳转到你程序指定的地址! demo: http://likeyunba.com/WeChat-Pay/

  6. Python | 多线程死锁问题的巧妙解决方法

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是Python专题的第25篇文章,我们一起来聊聊多线程开发当中死锁的问题. 死锁 死锁的原理非常简单,用一句话就可以描述完.就是当多线程 ...

  7. Java面试题(JVM篇)

    JVM 194.说一下 jvm 的主要组成部分?及其作用? 类加载器(ClassLoader) 运行时数据区(Runtime Data Area) 执行引擎(Execution Engine) 本地库 ...

  8. 力扣Leetcode 983. 最低票价

    最低票价 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的日子将以一个名为 days 的数组给出.每一项是一个从 1 到 365 的整数. 火车票有三种不同的销 ...

  9. 同事跳槽阿里P7,甩我一份微服务架构设计模式文档,看完我也去

    给所有微服务架构开发者的忠告,我想对你们说: 第一,要记住微服务不是解决所有问题的万能“银弹”. 第二,编写整洁的代码和使用自动化测试至关重要,因为这是现代软件开发的基础. 第三,关注微服务的本质,即 ...

  10. Azure Storage 系列(一)入门简介

    一,引言 今天作为新的Azure 资源介绍的开篇,我们来学习一个新的服务,Azure Storage.众所周知,我们实际在开发过程中,会需要存储一些比如说日志,图片,等等,各种类型的数据.比如说存储图 ...