Makefile中的隐式规则

Makefile中的隐式规则

1、隐式规则中的变量

隐式规则中使用的变量分成两种:一种是命令相关的,如“CC”;一种是参数相关的,如“CFLAGS”。

与命令相关的变量


































































变量

含义

AR

函数库打开包程序。默认命令是“ar”

AS

汇编语言编译程序。默认命令是“as”

CC

C语言编译程序。默认命令是“cc”

CXX

C++语言编译程序。默认命令是“g++”

CO

从RCS文件中扩展文件程序。默认命令是“co”

CPP

C程序的预处理器(输出是标准输出设备)。默认命令是“$(CC)-E”

FC

Fortran和Ratfor的编译器和预处理程序。默认命令是”f77”

GET

从SCCS文件扩展文件的程序。默认命令是“get”

LEX

Lex方法分析器程序(针对于C或Ratfor)。默认命令是”lex”

PC

Pascal语言编译程序。默认命令是”pc”

YACC

Yacc文法分析器(针对C程序)。默认命令是“yacc”

YACCR

Yacc文法分析器(针对Ratfor程序)。默认命令是“yacc -r”

MAKEINFO

转换Texinfo源文件(.texi)到info文件程序。默认命令是“makeinfo”

TEX

从TeX源文件创建TeX
DVI文件的程序。默认命令是“tex”

WEAVE

转化Web到TeX的程序。默认命令是“weave”

TEXI2DVI

从Texinfo源文件创建TeX
DVI文件的程序。默认命令是“texi2dvi”

CWEAVE

转化C Web到TeX的程序。默认命令是“cweave”

TANGLE

转换Web到Pascal语言的程序,默认命令是”tangle“

CTANGLE

转换C Web到C。默认命令是”ctangle“

RM

删除文件命令。默认命令是”rm-f“

与参数相关的变量















































变量

含义

ARFLAGS

函数库打包程序AR命令的参数。默认值是“rv”

ASFLAGS

汇编语言编译参数(当明显地调用”.s”或”.S”文件时)

CFLAGS

C语言编译器参数

CXXFLAGS

C++语言编译器参数

COFLAGS

RCS命令参数

CPPFLAGS

C预处理器参数(C和Fortran编译器也会用到)

FFLAGS

Fortran语言编译器参数

GFLAGS

SCCS
”get“程序参数

LDFLAGS

连接器参数(如“ld”)

LFLAGS

Lex文法分析器参数

PFLAGS

Pascal语法编译器参数

RFLAGS

Ratfor程序的Fortran编译器参数

YFLAGS

Yacc文法分析器参数

2、使用模式规则

可以使用模式规则定义一个隐式规则。和一般规则类似,只是在模式规则中,目标的定义需要有“%”字符。“%”定义对文件名的匹配,表示任意长度的非空字符串。在依赖目标中同样可以使用“%”,只是依赖目标中“%”的取值,取决于其目标。




模式规则中“%”的展开和变量与函数的展开是有区别的,“%”的展开发生在变量和函数的展开之后。变量和函数的展开发生在make载入Makefile时,而“%”的展开则发生在运行时。

1),模式规则举例

模式规则中,至少在规则的目标中要包含“%”符号。

%.o
: %.c ; <command......>

其含义是,字指出了从所有的.c文件生成相应的.o文件的规则。如果要生成的目标是”a.o b.o”,那么

“%.c”就是”a.c b.c”。

%.o
: %.c

$(CC)
-c $(CFLAGS) $(CPPFLAGS)$< -o [email protected]

表示把所有的.c文件都编译成.o文件。

其中,“[email protected]”表示所有目标的集合,”$<”表示所有依赖目标的集合(在模式定义规则的情形下)。

2),自动化变量

自动化变量只应出现在规则的命令中。

Makefile的自动化变量




































































变量

含义

[email protected]

表示规则中的所有目标文件的集合。在模式规则中如果有多个目标,“[email protected]”就是匹配于目标中模式定义的集合

$%

仅当目标是函数库文件时,表示规则中的目标成员名,如果目标不是函数库文件(UNIX下是

.a,Windows是.lib),其值为空。

$<

依赖目标中的第一个目标名字,如果依赖目标是以模式(即”%“)定义的,则”$<”是符合模式的一系列的文件集 
注意,其是一个一个取出来的

$?

所有比目标新的依赖目标的集合,以空格分隔

$^

所有依赖目标的集合,以空格分隔。如如果在依赖目标中有多个重复的,则自动去除重复的依赖目标,只保留一份

$+

同”$^”,也是所有依赖目标的集合,只是它不去除重复的依赖目标。

$*

目标模式中“%”及其之前的部分

$(@D)

“[email protected]”的目录部分(不以斜杠作为结尾),如果”[email protected]”中没有包含斜杠,其值为“.”(当前目录)

$(@F)

“[email protected]”的文件部分,相当于函数”$(notdir
[email protected])”

$(*D)

同”$(@D)”,取文件的目录部分

$(*F)

同”$(@F)”,取文件部分,但不取后缀名

$(%D)

函数包文件成员的目录部分

$(%F)

函数包文件成员的文件名部分

$(<D)

依赖目标中的第一个目标的目录部分

$(<F)

依赖目标中的第一个目标的文件名部分

$(^D)

所有依赖目标文件中目录部分(无相同的)

$(^F)

所有依赖目标文件中文件名部分(无相同的)

$(+D)

所有依赖目标文件中的目录部分(可以有相同的)

$(+F)

所有依赖目标文件中的文件名部分(可以有相同的)

$(?D)

所有被更新文件的目录部分

$(?F)

所有被更新文件的文件名部分

3、老式风格的"后缀规则"


后缀规则是一个比较老式的定义隐含规则的方法。后缀规则会被模式规则逐步地取代。因为模式规则更强更清晰。为了和老版本的Makefile兼容,GNU
make同样兼容于这些东西。后缀规则有两种方式:"双后缀"和"单后缀"。


双后缀规则定义了一对后缀:目标文件的后缀和依赖目标(源文件)的后缀。如".c.o"相当于"%o :
%c"。单后缀规则只定义一个后缀,也就是源文件的后缀。如".c"相当于"% : %.c"。

后缀规则中所定义的后缀应该是make所认识
的,如果一个后缀是make所认识的,那么这个规则就是单后缀规则,而如果两个连在一起的后缀都被make所认识,那就是双后缀规则。例如:".c"
和".o"都是make所知道。因而,如果你定义了一个规则是".c.o"那么其就是双后缀规则,意义就是".c"是源文件的后缀,".o"是目标文件的
后缀。如下示例:

     .c.o:

            
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o [email protected] $<


后缀规则不允许任何的依赖文件,如果有依赖文件的话,那就不是后缀规则,那些后缀统统被认为是文件名,如:


     .c.o: foo.h

            
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o [email protected] $<


这个例子,就是说,文件".c.o"依赖于文件"foo.h",而不是我们想要的这样:


     %.o: %.c foo.h

            
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o [email protected] $<


后缀规则中,如果没有命令,那是毫无意义的。因为他也不会移去内建的隐含规则。


而要让make知道一些特定的后缀,我们可以使用伪目标".SUFFIXES"来定义或是删除,如:


     .SUFFIXES: .hack .win


把后缀.hack和.win加入后缀列表中的末尾。

    
.SUFFIXES:              
# 删除默认的后缀
     .SUFFIXES: .c .o .h    #
定义自己的后缀

先清楚默认后缀,后定义自己的后缀列表。


make的参数"-r"或"-no-builtin-rules"也会使用得默认的后缀列表为空。而变量"SUFFIXE"被用来定义默认的后缀列表,你可以用".SUFFIXES"来改变后缀列表,但请不要改变变量"SUFFIXE"的值。

 

    --by  
吴尚奇  Devil_box

时间: 2025-01-12 08:42:13

Makefile中的隐式规则的相关文章

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 的时候.它到底是执行哪个呢?一个可能是两个都执行,另一个就是执行第一个,因为默认的是执行第一个目标.下来我们来看看执行结果 我们看到

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

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

深入理解Scala中的隐式转换系统

博客核心内容: 1.Scala中的两种隐式转换机制以及隐式视图的定义方式 2.Scala中的隐式绑定可能所处的位置以及如何更好的使用隐式转换 3.Scala中的隐式转换相关操作规则 4.Scala中的隐式参数 5.Scala中的隐式类 6.Scala中的隐式对象 7.Scala中的两种隐式类型约束(结合Scala中的类型系统) 8.Predef类中的implicitly方法的用法介绍以及Ordering类型转化为Oredered类型的方式 1.Scala中的两种隐式转换机制以及隐式视图的定义方式

Scala 中的隐式转换 implicit

Scala语言中的隐式转换是一个十分强大的语言特性,主要可以起到两个作用: 一.自动进行某些数据类型的隐式转换 String类型是不能自动转换为Int类型的,所以当给一个Int类型的变量或常量赋予String类型的值时编译器将报错.所以,一下语句是错误的. val x: Int = "100" 如果需要将一个字符串类型的整形数值赋给Int,比如使用String.toInt方法,例如: v al x: Int = "100".toInt 如果想让字符串自动转换为整形,

javascript中的隐式类型转化

javascript中的隐式类型转化 #隐式转换 ## "+" 字符串和数字 如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作. 如果其中一个操作数是对象(包括数组),则首先对其调用`ToPrimitive`抽象操作,该抽象操作再调用`[[DefaultValue]]`,以数字作为上下文. `[1,2]+[3,4]=='1,23,4'` 原因,因为数组的valueOf操作无法得到简单的基本类型,于是它转而调用toString.因此上栗得到的是'1,23,4'

JavaScript中关于隐式转换的一些总结

JavaScript运算符中的隐式转换规律:一.递增递减运算符(前置.后置)1.如果包含的是有效数字字符串或者是有效浮点数字符串,则会将字符串转换(Number())为数值,再进行加减操作,返回值的类型是:number类型.2.如果不包含有效数字字符串,则会将字符串的值转换为NaN,返回值的类型是:number类型.3.如果是boolean类型,则先会把true或者false转换为1或者0,再进行加减操作,返回值的类型是:number类型.4.如果是null类型,则先会把null转换为0,在进行

Shell、Awk 中自动隐式类型转换的“坑”

1.问题: 在林林总总的编程语言里,弱类型的语言着实不少,一方面这种"动态类型"用起来很方便,而另一方面则"坑"你没商量~ 常见的 SQL.Shell.Awk 都会遇到各种暗藏的"隐式类型转换",下面就列举一些 shell.awk 里的自动隐式类型转换 case,防止掉坑. 注意 shell.awk 的变量为空 字符串.变量为空 未定义.初始值的隐式转换问题: # shell 下的字典排序比较 [email protected] 10:59:23

编写高质量代码改善C#程序的157个建议——建议47:即使提供了显式释放方法,也应该在终结器中提供隐式清理

建议47:即使提供了显式释放方法,也应该在终结器中提供隐式清理 在标准的Dispose模式中,我们注意到一个以~开头的方法,如下: /// <summary> /// 必须,防止程序员忘记了显式调用Dispose方法 /// </summary> ~SampleClass() { //必须为false Dispose(false); } 这个方法叫做类型的终结器.提供类型终结器的意义在于,我们不能奢望类型的调用者肯定会主动调用Dispose方法,基于终结器会被垃圾回收这个特点,它被