第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 ...
随机推荐
- Python基础入门知识点——if 语句简介
前言 if 语句是最简单的选择结构.如果满足条件就执行设定好的操作,不满足条件就执行其他其他操作. 判断的定义 如果 条件满足,才能做某件事情, 如果 条件不满足,就做另外一件事情,或者什么也不做 判 ...
- 一、常用的Dos命令
# 查看目录下所有文件 dir # 切换目录 cd cd .. //返回上一级 # 清理屏幕 cls # 查询电脑ip地址 ipconfig # 退出终端 exit # 创建文件夹 md test # ...
- Linux学习笔记 一 第三章 Linux常用命令
第三章Linux常用命令 一.文件处理命令 1.命令格式 2.目录处理命令:ls 3.目录处理命令:mkdir 4.文件处理命令: touch
- Android Studio && GitHub 团队多人一起开发
曾几何时,花了两天的时间搞了合并项目,搞得乱七八糟der,但最终还是被我搞定了,too 乱 to 做笔记.过了几个月,也就是前几天,抱着从头开始的决心,再次尝试,然鹅并没有结果.今天,再一次重新开始, ...
- MIT 6.828 Lab04 : Preemptive Multitasking
目录 Part A:Multiprocessor Support and Cooperative Multitasking Multiprocessor Support 虚拟内存图 Exercise ...
- 浅析XML和JSON的区别
前言 今天做接口对接时,发现对方竟然是通过XML进行数据传输,当时冒出的第一个想法就是:WTF,这都什么年代了,还在用XML,是来搞笑的吧,JSON它不香吗? 想法归想法,但对接还是要完成的是吧?然后 ...
- 精确到小数点后n位的两种方法
引言:大家在写程序中多多少少会遇到这个问题,特别对一些初学者会出现这个问题,做个ACM竞赛的同学肯定都会用C语言的printf格式控制输出,但是习惯于用C++的同学也不是一点办法都没有啊,这篇blog ...
- exe调用DLL的方式
假设被调用的DLL存在一个导出函数,原型如下: void printN(int); 三种方式从DLL导入导出函数 生成DLL时使用模块定义 (.def) 文件 在主应用程序的函数定义中使用关键字__d ...
- 共享&img (给作者自己
--------------------------------------------------------- ------------------------------------------ ...
- 编译原理根据项目集规范族构造LR(0)分析表
转载于https://blog.csdn.net/Johan_Joe_King/article/details/79058597?utm_medium=distribute.pc_relevant.n ...