第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. JavaScript基础-01

    1. Javascript是一门动态的.弱类型的.解释型的脚本语言 动态:数据类型在运行时决定 弱类型:变量数据的类型不是确定的,可以随意的进行改变: 解释型:相对编译型来说,编译型计算机在执行之前需 ...

  2. CSS动画实例:Loading加载动画效果(一)

    一些网站或者APP在加载新东西的时候,往往会给出一个好看有趣的Loading图,大部分的Loading样式都可以使用CSS3制作出来,它不仅比直接使用gif图简单方便,还能节省加载时间和空间.下面介绍 ...

  3. python 11 类与对象

    给大家介绍对象hhhh 封装 举个例子,把乱七八糟的数据仍到列表,数据层面的封装 把常用的代码打包成一个函数,封装 外观特征(静态) 能做什么(动态) 对象=属性(静态) + 方法(动态) 1.方法多 ...

  4. SpringMVC 注解方式进行配置页面跳转

    @ 目录 修改IndexController 修改springmvc-servlet.xml 效果 修改IndexController 在类前面加上@Controller 表示该类是一个控制器 在方法 ...

  5. 无锁机制----比较交换CAS Compare And Swap

    一.锁与共享变量 加锁是一种悲观的策略,它总是认为每次访问共享资源的时候,总会发生冲突,所以宁愿牺牲性能(时间)来保证数据安全. 无锁是一种乐观的策略,它假设线程访问共享资源不会发生冲突,所以不需要加 ...

  6. ls-remote -h -t git://github.com/adobe-webplatform/eve.git 报错问题

    npm ERR! Error while executing:npm ERR! D:\开发工具\git\Git\cmd\git.EXE ls-remote -h -t git://github.com ...

  7. eclipse项目文件夹整理

    1.点击倒三角 2.系统默认为Projects,选择第二个working sets 3.点击Configure Working Sets,点new 4.点击后,选中点Add 5.添加一个名字,Fins ...

  8. peer_manager_handler: Connection security failed: role: Peripheral, conn_handle: 0x0, procedure: Bonding, error: 133

    调试nordic 52840 hids_keyboard 例程时,和手机配对,配对失败,提示:peer_manager_handler: Connection security failed: rol ...

  9. Spring Security 入门学习--数据库认证和授权

    首先是使用的SpringBoot框架 基础需要的pom以来如下,基础的springboot项目的创建就不一一赘述了. <!--spring web--> <dependency> ...

  10. SpringBoot2搭建基础架构——开源软件诞生4

    技术框架篇--第4篇 用日志记录“开源软件”的诞生 赤龙ERP开源地址: 点亮星标,感谢支持,加微信与开发者交流 kzca2000 码云:https://gitee.com/redragon/redr ...