第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. My_Tomcat_Host 靶机

    1:扫描网段: 发现主机IP为192.168.1.203 2:nmap 扫描端口信息 发现8080端口开启了http服务  22ssh服务 3:尝试ssh连接是需要密码的,然后访问8080端口 4:发 ...

  2. 【期外】 (一)关于LSH :局部敏感哈希算法

    LSH是我同学的名字,平时我会亲切的称呼他为离骚,老师好,左移(leftshift),小骚骚之类的,最近他又多了一个新的外号:局部敏感哈希(Locally sensitive hashing). 好了 ...

  3. hdfs常用api(java)

    1.下载文件到本地 public class HdfsUrlTest { static{ //注册url 让java程序识别hdfs的url URL.setURLStreamHandlerFactor ...

  4. Android 在代码中修改TextView的DrawableRight等方向上的图片

    在XML文件中可以对TextView进行设置: android:drawableTop="@drawable/XXX" android:drawableBottom="@ ...

  5. Spring @Transactional事物配置无效原因

    spring @transaction不起作用,Spring事物注意事项 1. 在需要事务管理的地方加@Transactional 注解.@Transactional 注解可以被应用于接口定义和接口方 ...

  6. windows 下apache开启FastCGI

    1.首先去(http://www.apachelounge.com/download/)下载一个合适的mod_fcgid  文件.     2.将解压后的文件改为mod_fcgid.dll 并复制到a ...

  7. Linux之lldptool工具

    1. 描述当我们想在操作系统里面查看网口和交换机连接的状态信息,我们可以使用lldptool这个工具2.LLDP协议LLDP是Link Layer Discovery Protocol 链路层发现协议 ...

  8. Java中校验身份证号合法性(真伪),获取出生日期、年龄、性别、籍贯

    开发过程中有用的身份证号的业务场景,那么校验身份证的合法性就很重要了,另外还有通过身份证获取出生日期.年龄.性别.籍贯等信息, 下面是本人在开发中用到的关于校验身份证真伪的工具类,可以直接拿来使用,非 ...

  9. DBeaver链接kerberos安全认证的Phoenix集群

    DBeaver链接kerberos安全认证的Phoenix集群 最近公司的CDH集群,启动了kerberos安全认证,所有的用户验证全部需要依赖kerberos来进行.之前的裸奔集群,总算有了一些安全 ...

  10. 区块链入门到实战(30)之Solidity – 基础语法

    一个 Solidity 源文件可以包含任意数量的合约定义.import指令和pragma指令. 让我们从一个简单的 Solidity 源程序开始.下面是一个 Solidity 源文件的例子: prag ...