第18课 - make 中的路径搜索(下)
第18课 - make 中的路径搜索(下)
1. 问题一
当 VPATH 和 vpath 同时出现,make 会如何处理?
工程项目的目录结构如下图所示,src1 和 src2 中都包含了 func.c 文件,如果在 makefile 中使用 VPATH 指定了 src1 ,使用 vpath 指定了 src2,当 VPATH 和 vpath 同时存在时,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)避免 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
第18课 - make 中的路径搜索(下)的更多相关文章
- 第17课 - make 中的路径搜索(上)
第17课 - make 中的路径搜索(上) 1. 问题 在以往的 make 学习中,我们使用到的 .c 文件和 .h 文件都与 makefile 处在同一个路径.在实际的工程项目中,所有的源文件和头文 ...
- 第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据
第18课-数据库开发及ado.net 连接数据库.增.删.改向表中插入数据并且返回自动编号.SQLDataReade读取数据 ADO.NET 为什么要学习? 我们要搭建一个平台(Web/Winform ...
- 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效
数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...
- Linux中/proc目录下文件详解
转载于:http://blog.chinaunix.net/uid-10449864-id-2956854.html Linux中/proc目录下文件详解(一)/proc文件系统下的多种文件提供的系统 ...
- struts2 jsp表单提交后保留表单中输入框中的值 下拉框select与input
原文地址:struts2 jsp表单提交后保留表单中输入框中的值 下拉框select与input jsp页面 1 function dosearch() {2 if ($(&q ...
- Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询
原文:Linq to Sql:N层应用中的查询(下) : 根据条件进行动态查询 如果允许在UI层直接访问Linq to Sql的DataContext,可以省去很多问题,譬如在处理多表join的时候, ...
- Linux中/proc目录下文件详解(转贴)
转载:http://www.sudu.cn/info/index.php?op=article&id=302529 Linux中/proc目录下文件详解(一) 声明:可以自由转载本文, ...
- 将MySQL库的表转入到MSSQL中的某个库中(Employees下的Employees表 → pubs库下)_2
将MySQL库的表转入到MSSQL中的某个库中(Employees下的Employees表 → pubs库下, 此pubs下的表名是employee,不冲突),方法大致以下几个(另有其他方法待补充), ...
- Scala 深入浅出实战经典 第49课 Scala中Variance代码实战(协变)
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
随机推荐
- element-ui 格式化树形数组在table组件中展示(单元格合并)
最近做的项目涉及到很多单元格合并问题,element-ui组件对于单元格合并的处理虽然很灵活,但是需要事先计算好每个单元格合并的rowspan和colspan,直接在span-method属性中计算实 ...
- GUAVA-ListenableFuture实现回调
随着软件开发的不断进步,在实际的开发应用中,可能一次请求需要查询若干次数据库或者调用若干次第三方,按照传统的串行执行的话,会大大增加响应时间,无法满足业务需求,更无法满足用户迫切需要响应迅速的愿望.对 ...
- Docker: docker pull, wget, curl, git clone 等如何更快?
1) Docker 配置 1.1) daemon.json 配置镜像 路径: /etc/docker/daemon.json 文档: Config Daemon registry-mirrors 设定 ...
- UML活动图(Activity Diagram)
目录: 1.什么是活动图 2.活动图的构成 (1)起点 (2)重点 (3)活动名称 (4)判断条件 (5)同步条 (6)接收信号 (7)发送信号 (8)泳道 (9)转移 3.活动图实例--订单处理 4 ...
- linux 部署jar包开机自启
1.用xShell将jar包上传到linux上(jar包上传到 /root/java) 输入rz命令,看是否已经安装了lrzsz,如果没有安装则执行 yum -y install lrzsz ...
- java反序列化——XMLDecoder反序列化漏洞
本文首发于“合天智汇”公众号 作者:Fortheone 前言 最近学习java反序列化学到了weblogic部分,weblogic之前的两个反序列化漏洞不涉及T3协议之类的,只是涉及到了XMLDeco ...
- java基础-03:注释
1.注释的意义: (1) 为了更好的阅读自己编写的代码,方便日后代码维护,建议添加注释. (2) 有利于团队协作. (3) 代码即文档.程序源代码是程序文档的重要组成部分. 2.注释分类 (1) 单行 ...
- linux云服务器搭建 express后台 nginx转发
购买云服务器 或者自己在本地搭建一个虚拟机 (我用的是腾讯云云服务器(CVM),或者可以购买阿里云 ecs服务器) 购买完成后 配置安全组 允许http https ftp 端口 一般运营商会提供说明 ...
- Spring MVC 的运行流程
1.用户发送请求到DispatcherServlet 2.DispatcherServlet调用处理器映射器(HanderMapping)找到处理器 3.处理器映射器(HanderMapping)返回 ...
- 焦大:逛网seo案例浅析
http://www.wocaoseo.com/thread-93-1-1.html 逛,发现喜欢.这或许是很多人上网的喜欢方式,我隐约记得白鸦在一次采访上说到现在人的购物方式,在淘宝上人们决定买一件 ...