学习记录(对应文档的p51-p78)
六、call函数
用途:写一个非常复杂的表达式。定义许多参数,用call函数向表达式传递参数
$(call <expression>, <parm1>, <parm2>, <parm3>...)
执行时,expression参数中的变量,如$(1),会被参数parm1取代
七、origin函数
告知变量的来源
$(origin <variable>)
为什么要判断变量是哪来的?原因:
假设 Makefile 包了一个定义文件 Make.def,在Make.def 中定义了一个变量“bletch”,
有一个环境变量“bletch”。此时,我们想判断一下,如果变量来源于环境,那么我们就把
之重定义了,如果来源于 Make.def 或是命令行等非环境的,那么我们就不重新定义它。
ifdef bletch
ifeq "$(origin bletch)" "environment"
bletch = barf, gag, etc.
endif
八、shell函数
可以用操作系统命令以及字符串处理命令 awk,sed 等等命令来生成
一个变量,如:
contents := $(shell cat foo)
files := $(shell echo *.c)
九、控制make的函数
1、error
$(error <text ...>)
产生一个致命的错误,<text ...>是错误信息。注意,error函数不会在一被使用就会
产生错误信息,所以如果你把其定义在某个变量中,并在后续的脚本中使用这个变量,那么
也是可以的。例如:
示例一:
ifdef ERROR_001
$(error error is $(ERROR_001))
endif
示例二:
ERR = $(error found an error!)
.PHONY: err
err: ; $(ERR)
示例一会在变量 ERROR_001 定义了后执行时产生 error 调用,而示例二则在目录 err
被执行时才发生 error调用。
2、warning
$(warning <text ...>)
第十部分 make的运行
一、make的退出码
0 成功
1 出现任何错误
2 使用了make的-q选项,且make使得一些目标不需要更新
二、指定Makefile
有个Makefile文件hchen.mk,需要执行
make -f hchen.mk
三、指定目标
make的环境变量MAKECMDGOALS,存放指定的终极目标
例子:
sources = foo.c bar.c
ifneq ( $(MAKECMDGOALS),clean)
include $(sources:.c=.d)
endif
输入的命令不是“make clean”,那么 makefile 会自
动包含“foo.d”和“bar.d”这两个makefile。
GNU这种开源软件发布时,makefile都包含了编译、安装、打包等功能
使用通用伪目标名称的好处:规范(不用解释,大家都懂)、实用、专业(不是初学者)
四、规则检查
不想让Makefile执行,只是检查一下命令,使用make的参数:
“-n”
“--just-print”
“--dry-run”
“--recon”
上面这几个参数只打印命令,可用来调试Makefile
“-t”
“--touch”
上面这个参数的意思就是把目标文件的时间更新,但不更改目标文件。也就是说,make 假
装编译目标,但不是真正的编译目标,只是把目标变成已编译过的状态。
“-q”
“--question”
这个参数的行为是找目标的意思,也就是说,如果目标存在,那么其什么也不会输出,
当然也不会执行编译,如果目标不存在,其会打印出一条出错信息
“-W <file>”
“--what-if=<file>”
“--assume-new=<file>”
“--new-file=<file>”
这个参数需要指定一个文件。一般是是源文件(或依赖文件),Make 会根据规则推导来
运行依赖于这个文件的命令,一般来说,可以和“-n”参数一同使用,来查看这个依赖文件
所发生的规则命令。
另外一个很有意思的用法是结合“-p”和“-v”来输出 makefile 被执行时的信息(这
个将在后面讲述)
五、make的参数
GNU make 3.80版参数
“-b”
“-m”
这两个参数的作用是忽略和其它版本 make 的兼容性。
“-B”
“--always-make”
认为所有的目标都需要更新(重编译) 。
“-C <dir>”
“--directory=<dir>”
指定读取 makefile 的目录。如果有多个“-C”参数,make 的解释是后面的路径以前面
的作为相对路径,并以最后的目录作为被指定目录。如: “make –C ~hchen/test –C prog”
等价于“make –C ~hchen/test/prog”。
“—debug[=<options>]”
输出 make 的调试信息。它有几种不同的级别可供选择,如果没有参数,那就是输出最简单
的调试信息。下面是<options>的取值:
a —— all,输出所有的调试信息。(会非常的多)
b —— basic,只输出简单的调试信息。即输出不需要重编译的目标。
v —— verbose,在 b 选项的级别之上。输出的信息包括哪个 makefile 被解析,不
需要被重编译的依赖文件(或是依赖目标)等。
i —— implicit,输出所以的隐含规则。
j —— jobs,输出执行规则中命令的详细信息,如命令的 PID、返回码等。
m —— makefile,输出 make 读取 makefile,更新 makefile,执行 makefile 的信
息。
第十一部分 隐含规则
“隐含规则”会使用系统变量,如系统变量“CFLAGS”可以控制编译时的编译器参数。
一、使用隐含规则
foo : foo.o bar.o
cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
make会自动推导如何生成foo.o和bar.o
二、隐含规则一览
取消预设值的隐含规则,make的参数-r或--no-builtin-rules
1、编译C程序的隐含规则
.o的目标自动找对应的.c文件,生成命令$(CC) -c $(CPPFLAGS) $(CFLAGS)
2、编译C++程序的隐含规则
.o的目标自动找对应的.cc文件,生成命令$(CXX) -c $(CPPFLAGS) $(CFLAGS)
3、Pascal
.o的目标自动找对应的.p文件,生成命令$(PC) -c $(PFLAGS)
4、编译Fortran/Ratfor
5、预处理Fortran/Ratfor
6、Modulate-2
7、汇编和汇编预处理的规则
.o的目标自动找对应的.s文件,默认使用编译器as,生成命令$(AS) $(ASFLAGS)
.s的目标自动找对应的.S文件,默认使用C预编译器cpp,生成命令$(AS) $(ASFLAGS)
8、链接Object
“<n>”目标依赖于“<n>.o”,通过运行 C 的编译器来运行链接程序生成(一般是
“ld”) ,生成命令“$(CC) $(LDFLAGS) <n>.o $(LOADLIBES) $(LDLIBS)”。这个规
则对于只有一个源文件的工程有效,同时也对多个 Object 文件(由不同的源文件生成)的
也有效。
9、Yacc C
10、Lex C
11、Lex Ratfor
12、从 C 程序、Yacc文件或 Lex 文件创建Lint 库的隐含规则
三、隐含规则使用的变量
1、关于命令的变量
AR 函数库打包程序,默认命令是ar
AS 汇编语言编译程序,as
CC C语言编译程序,cc
CXX C++语言编译程序,gcc
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”。
TEXI2DVI 从 Texinfo源文件创建军 TeX DVI 文件的程序。默认命令是“texi2dvi”。
WEAVE 转换 Web 到TeX 的程序。默认命令是“weave”。
CWEAVE 转换 C Web 到 TeX 的程序。默认命令是“cweave”。
TANGLE 转换 Web 到Pascal 语言的程序。默认命令是“tangle”。
CTANGLE 转换 C Web 到 C。默认命令是“ctangle”。
RM 删除文件命令。默认命令是“rm –f”。
2、关于命令参数的变量
四、隐含规则链
如果文件[.c]存在,直接调用 C的编译器的隐含规则
如果没有[.c]文件,但有一个[.y]文件,那么 Yacc 的隐含规则会被调用,生成[.c]文件,
然后,再调用 C 编译的隐含规则最终由[.c]生成[.o]文件,达到目标
通常,一个被 makefile 指定成目标或是依赖目标的文件不能被当作中介。但可
以明显地说明一个文件或是目标是中介目标,使用伪目标“.INTERMEDIATE”来强制声明。
(如:.INTERMEDIATE : mid )
五、定义模式规则
1、模式规则介绍
至少在规则的目标定义中要包含"%",否则,就是一般的规则。
2、模式规则示例
下面这个例子表示了,把所有的[.c]文件都编译成[.o]文件.
%.o : %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
其中,"$@"表示所有的目标的挨个值,"$<"表示了所有依赖目标的挨个值。
3、自动化变量
目的:从不同的依赖文件生成相应的目标
$@ 目标文件集
$% 仅当目标是函数库文件中,表示规则中的目标成员名
例子:目标是"foo.a (bar.o)",那么,"$%"就是"bar.o","$@"就是"foo.a"。
如果目标不是函数库文件,其值为空。
$< 依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将
是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$? 所有比目标新的依赖目标的集合。以空格分隔。
$^ 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,只保留一份。
$+ 这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$* 这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的
模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。
如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的
后缀是 make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因
为".c"是 make 所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是 GNU make 的
4、模式的匹配
% 茎
5、重载内建隐含规则
六、老式风格的“后缀规则”
七、隐含规则搜索算法
后缀规则在 Makefile 被载入内存时,会被转换成模式规则
目标T 搜索分7步
第十二部分 使用make更新函数库文件
函数库文件也就是对 Object 文件(程序编译的中间文件)的打包文件。在 Unix 下,一
般是由命令"ar"来完成打包工作。
一、函数库文件的成员
一个函数库文件由多个文件组成,指定函数库文件及其组成:
archive(member)定义一个目标和依赖,为ar服务,如:
foolib(hack.o) : hack.o
ar cr foolib hack.o
二、函数库成员的隐含规则
make执行的命令大致如下:
cc -c bar.c -o bar.o
ar r foo.a bar.o
rm -f bar.o
三、函数库文件的后缀规则
使用后缀规则和隐含规则,生成函数库打包文件
.c.a:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o
四、注意
在进行函数库打包文件生成时,小心使用 make 的并行机制("-j"参数)
如果多个ar 命令在同一时间运行在同一个函数库打包文件上,就很有可以损坏这个函数库文件。
在 make未来的版本中,应该提供一种机制来避免并行操作发生在函数打包文件上。
第十三部分 后序
make 以文件的依赖性为基础
make 不仅可以编译程序,也可以完成其他工作,因为规则中的命令可以是shell下的任何命令
可以在Makefile中写其他命令:tar、awk、mail、sed、cvs、compress、ls、rm、yacc、rpm、ftp
可以实现的功能:程序打包、备份、制作程序安装包、提交代码、使用程序模板、合并文件