make--隐式规则 路径搜索及实例

一.隐式规则

问题一

.PHONY : all
all:
    @echo "command-1"
VAR:=test
all:
    @echo "all:$(VAR)"

make之后的结果如图所示

可以得出的结论是
A.makefile中出现同名目标时
依赖:所有的依赖将合并在一起,成为目标的最终依赖
命令:当多处出现同一目标时,make发出警告;所有之前定义的命令被最后定义的命令取代
注意:当使用include关键字包含其他文件时,需要确保被包含文件中的同名目标只有依赖,没有命令;否则,同名目标的命令将被覆盖

隐式规则
1.make提供了一些常用的,例行的规则实现
2.当相应目标的规则未提供时,make尝试隐式规则
3.make提供了生成目标文件的隐式规则
4.隐式规则会使用预定义变量完成编译工作
5.改变预定义变量将部分改变隐式规则的行为
6.当存在自定义规则时,不再使用隐式规则

深入理解隐式规则
A.当make发目标的依赖不存在时
1.尝试通过依赖名逐一查找隐式规则
2.并且通过依赖名推导可能需要的源文件

隐式规则的副作用
1.编译行为难以控制--大量使用隐式规则可能产生意想不到的编译行为
2.编译效率低下--make从隐式规则和自定义规则中选择最终使用的规则
隐式规则链
当依赖的目标不存在时,make会极力组合各种隐式规则对目标进行创建,进而产生意料之外的编译行为---需要名为N.o的目标:N.y->N.c>N.o
查看隐式规则

隐式规则的禁用
A.局部禁用
1.在makefile中自定义规则
2.在makefile在定义模式(如:%.o:%.p)
B.全局禁用
make -r

后缀规则的简介
1.后缀规则是旧式的“模式规则”
2.可以通过后缀描述的方式自定义规则

双后缀规则--定义一对文件后缀(依赖文件后缀和目标文件后缀),如:.cpp<==>%.o:%.cpp
单后缀规则--定义单个文件后缀(源文件后缀),如.c<==>%:%.c
关于后缀规则的注意事项
1.后缀规则中不允许有依赖
2.后缀规则必须有命令,否则无意义
3.后缀规则逐步被模式规则取代

小结:
1.当多处出现同一目标的命令时,只有最后定义的命令有效
2.make提供了一系列的而隐式规则可使用
3.当makefile中未定义相关规则时,尝试使用隐式规则
4.隐式规则中可能使用make中的预定义变量
5.改变预定义变量可部分改变预定义规则的行为
6.隐式规则可能造成意想不到的编译行为
7.在实际工程项目中尽量不使用隐式规则
8.后缀规则是一种旧式的模式规则
9.后缀规则正逐步被模式规则取代

二.路径搜索

A.常用的源码管理方式


项目中的makefile必须能够正确的定位源文件和依赖文的文件,最终编译可执行程序代码如下图

如图所示:inc文件夹是头文件,而src文件夹是源文件,makefile文档程序如图所示,make之后的结果如图所示

生成该结果的原因是在当前文件夹中不存在func.c
特殊的预定义变量VPATH(全大写)
1.VPATH变量的值用于指示make如何查找文件
2.不同文件夹可作为VPATH的值同时出现
3.文件夹的名字之间需要用分隔符进行区分

make对于VPATH值的处理方式
1.当前文件找不到需要的文件时,VPATH会被使用
2.make会在VPATH指定的文件夹中依次搜索文件
3.当多个文件夹存在同名时,选择第一次搜索到的文件
注意事项:
1.VPATH只能决定make的搜索路径,无法决定命令的搜索路径
2.对于特定的编译命令(gcc),需要独立指定编译搜索路径
3.

对之前示例的修改及运行结果如图所示

VPATH存在的问题--当inc文件夹意外出现源文件(C/Cpp文件),那么可能产生编译错误
替换方案:vpath关键字(全小写)
1.为不同类型的文件指定不同的搜索路径
2.语法--在Directory中搜索符合Pattern的规则的文件

运行的实例及运行结果如图所示

取消搜索规则:
1.取消已经设置的某个搜索规则
.vpath Pattern

2.取消所有已经设置的规则
.vpath

三 路径搜索的几个问题

问题1:当VPATH和vpath同时出现时,make会如何处理

运行的实例及结果图

当把src2中的func.c改成func.cpp再次进行make
运行的结果

对比得出的结论
1.make首先在当前文件夹搜索需要的文件
2.如果失败
a.make优先在vpath指定的文件夹中搜索目标文件
b.当vpath搜索失败时,转而搜索VPATH指定的文件夹

问题2--当使用vpath对同一个Pattern指定多个文件夹时,make会如何处理

实例及运行结果如图所示

结论:
1.make首先在当前文件夹搜索需要的文件
2.如果失败
a.make以自上而下的顺序搜索vpath指定的文件夹
b.当找到目标文件,搜索结束

问题3--通过VPATH指定搜索路径后,make如何决定目标文件的最终位置

将第一次运行的结果生成的app.out放置src文件夹下的运行make结果图如图所示

结论:
1.当app.out完全不存在--make在当前文件夹下创建app.out
2.当src文件夹中存在app.out--所有目标和依赖的新旧关系不变,make不会重新创建app.out;当依赖文件被更新,make在当前文件夹下创建app.out

四 小结:

1.VPATH变量用于指示make如何查找文件
2.make会在VPATH指定的文件夹中依次搜索文件
3.vpath关键字可以为不同类型的文件指定不同的搜索路径
4.vpath比VPATH更灵活易用,可动态设置/取消搜索路径
5.尽量使用vpath为不同文件指定搜索路径
6.不要在源码文件夹中生成目标文件
7.为编译得到的结果创建独立的文件夹

原文地址:https://blog.51cto.com/13475106/2354209

时间: 2024-11-13 21:56:05

make--隐式规则 路径搜索及实例的相关文章

Makefile中的隐式规则

Makefile中的隐式规则 1.隐式规则中的变量 隐式规则中使用的变量分成两种:一种是命令相关的,如"CC":一种是参数相关的,如"CFLAGS". 与命令相关的变量 变量 含义 AR 函数库打开包程序.默认命令是"ar" AS 汇编语言编译程序.默认命令是"as" CC C语言编译程序.默认命令是"cc" CXX C++语言编译程序.默认命令是"g++" CO 从RCS文件中扩展文件

第15课 - make的隐式规则(上)

第15课 - make的隐式规则(上) 1. 问题 如果把同一个目标的命令拆分的写到不同地方,会发生什么? 执行make all 这个实验表明了:如果同一个目标的命令拆分的写到不同地方,那么 make 会覆盖之前的目标对应的命令,使用最新出现的目标对应的命令. makefile 中出现同名目标时 - 依赖: 所有的依赖将合并在一起,成为目标的最终依赖 - 命令: 当多处出现同一目标的命令时,make 发出警告 所有之前定义的命令被最后定义的命令取代 注意:当使用 include 关键字包含其它文

makefile(06)_隐式规则

15.Make的隐式规则 15.1.命令覆盖 问题1:通过各目标的命令拆分写到不同的地方,会发生什么?Makefile中出现同名目标时:依赖:所有的依赖将合并到一起,成为目标的最终依赖命令:当多处出现同一目标的命令时,make发出警告,所有之前定义的命令被最后的命令取代.注意:当使用include包含其他文件(makefile)时,需要确保被包含的文件中的同名目标只有依赖,没有命令:否则,同名目标的命令将被覆盖! 15.2.隐式规则 Make中提供了一些常用的,例行的规则实现,当目标的规则未提供

make 的隐式规则(十一)

如果我们将同一个目标的命令拆分的写到不同地方,会发生什么呢?我们来看看下面的代码 .PHONY : all all :     @echo "command-1" VAR := test          all :     @echo "all : $(VAR)" 我们来分析下,这份代码中有两个目标 all,那么我们在执行 make 的时候.它到底是执行哪个呢?一个可能是两个都执行,另一个就是执行第一个,因为默认的是执行第一个目标.下来我们来看看执行结果 我们看到

JSP中的EL隐式对象

一 介绍 JSP表达式语言(Expression Language),简称EL,为存取变量.表达式运算和读取内置对象等内容提供了新的操作方式.目的:为了使JSP写起来更加简单.表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法. ${ param. username } 等价于 <%=request. getParameter("username") %> ${ requestScope.userlist } 等

从头认识java-13.9 隐式和显示的创建类型实例

对于上一章节擦除引起的问题与解决的方法有读者提出过于简单.这里解释一下:由于笔者本身也遇不到对应的问题.仅仅是凭空想像一些有可能的问题,基于水平有限,因此上一章节写的比較简单,欢迎广大读者踊跃提意见,我会尽量改进. 回归到这一章节,这里我们将讨论隐式和显示的创建类型实例. 1.隐式建类型实例 我们上一章节提到以下有问题的代码: package com.ray.ch11; public class Test<T> { public void test(Object object){ // Sys

构造函数、原型对象、实例、隐式原型的理解

(欢迎一起探讨,如果有什么地方写的不准确或是不正确也欢迎大家指点,最后留了一个疑问,欢迎各位大神来探讨~) PS: 内容中的__proto__可能会被markdown语法导致显示为proto. 建议将构造函数中的方法都定义到构造函数的原型中,由该构造函数创建的实例的方法都会指向同一个方法.(在内部声明的话,每创建一个实例都会重新实例化函数,每个实例中的函数的指向是不同的:如果定义在全局中,且有很多方法,这样毫无封装性可言.) 一.属性和方法 构造函数可以定义三种属性和方法: 对象属性/对象方法:

隐式转换构造函数、仿函数、转换函数实例

class B { public: //隐式转换 B(int i) { cout << i << endl; data = i; } //仿函数 bool operator() (int i) { cout << i << endl; return i > 0; } //转换函数 operator string() { return "class_string"; } private: int data; }; int main()

模板显式、隐式实例化和(偏)特化、具体化的详细分析(转)

这么多叫法,其实就是三种. 1. 显示实例化 2. 隐式实例化 3. 特化(=具体化).偏特化 一.实例化 1.显示.隐式实例化 什么是实例化:一个通过使用具体值替换模板参数,从模板产生的普通类,函数或者成员函数的过程. 显示实例化:通过名字可见,就是清楚的表明你要实例化的类型 隐式实例化:通过编译器自己推测判断要实例化的类型. 比如一个模板: template<class T> //函数模板实现  void swap(T &a, T &b) {     T temp;