makefile学习笔记
make处 理Makefile的过程也分为两个阶段:
· 首先从前到后读取所有规则,建立起一个完整的依赖关系图
·然后从缺省目标或者命令行指定的目标开始,根据依赖关系图选择适当的规则执行,执 行Makefile中的规则并不是从前到后按顺序执行,也不是所有规则 都要执行一遍。首先更新它的所有条件;所有 条件中只要有一个条件被更新了,目标也必须随之被更新。
写Makefile都是以目标为中心,一个目标依赖于若干条件,现在换个角度,如下以条件为中 心 (makefile目的是让make建立依赖关系图,只要把所有的依赖关系描 述清楚就ok)
main.o stack.o:stack.h
main.o stack.o maze.o:main.h
main.o maze.o:maze.h
注:在make的命令行中指定一个目标(例如clean),则更新这个目标,如果不指定目标则更 新Makefile中第一条规则的目标(缺省目标)。
小常识:命令前面加@和-字符:如果make执行的命令前面加了@字符,则 不显示命令本身而只显示它的结果;make执行的命令如果出错就 立刻终止,不再执行后续命令,但如果命令前面加了-号,即使这条命令出错,make也会继续执 行后续命令。通常rm命令和mkdir命令前面要加-号。
Makefile(里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。)
默认情况,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到了解释这个文件。在这三个文件名中,最好使用“Makefile”这个文件名,第一个字符为大写有一种显目的感觉。最好不要用“GNUmakefile”,这个文件是GNU的make识别的。有另外一些make只对全小写的“makefile”文件名敏感,但是基本上来说,大多数的make都支持“makefile”和“Makefile”这两种默认文件名。
当然,你可以使用别的文件名来书写Makefile,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“--file”参数,如:make -f Make.Linux或make --file Make.AIX。
一: 显式规则。
显式规则说明如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
规则包含两个部分,一个是依赖关系,一个是生成目标的方法。
target.o : target.c target.h
gcc -c target.c -o target.o
文件target.o依赖于target.c和target.h的文件,如果target.c和target.h的文件日期比target.o文件日期新,或是target.o不存在,那么依赖关系发生。
二、隐晦规则(make的隐含规则 数据库可以用make -p命令打印)。
一个目标依赖的所有条件不一定非得写在一条规则中,也可以拆开写(若一个目标拆开写多条规则,其中只允许一条规则有命令列表,其它规则应该没有命令列 表,否则make会报警告并且采用最后一条规则的命令列表)。
target.o : target.h
target.o : target.c
gcc -c target.c -o target.o
make有自动推导的功能,利用隐晦规则可以简略书写Makefile。
上述等价于:target.o:target.h (没有编译命令时,makefile会尝试内建的隐含命令)
隐含规则中使用的变量分成两种:一种是命令相关的,如“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”。 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”。
关于命令参数的变量: 下面的这些变量都是相关上面的命令的参数。如果没有指明其默认值,那么其默认值都是空。
ARFLAGS 函数库打包程序AR命令的参数。默认值是“rv”。 ASFLAGS 汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)。 CFLAGS C语言编译器参数。 CXXFLAGS C 语言编译器参数。 COFLAGS RCS命令参数。 CPPFLAGS C预处理器参数。( C 和 Fortran 编译器也会用到)。 F, FLAGS Fortran语言编译器参数。 GFLAGS SCCS “get”程序参数。 LDFLAGS 链接器参数。(如:“ld”) LFLAGS Lex文法分析器参数。 PFLAGS Pascal语言编译器参数。 RFLAGS Ratfor 程序的Fortran 编译器参数。 YFLAGS Yacc文法分析器参数。
三、变量的定义。
在Makefile中我们要定义一系列的变量,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置。
3.1 如环境中定义了环境变量MAKEFILES,make会把这个变量中的值做一个类似于include的动作。这个变量中的值是其它的Makefile,用空格分隔。它和include不同的是,从这个环境变中引入的Makefile的“目标”不会起作用,如果环境变量中定义的文件发现错误,make也会不理。建议不要使用这个环境变量,这个变量被定义后,当你使用make时,所有的Makefile都会受到它的影响。
3.2 常规变量(“替代”原理)
变量声明时需要赋初值,在使用时,要在变量名前加“$”符号,最好"()"或是“{}”把变量给包括起来。若要使用真实的“$”字符,需用“$$”表示。
有如下3种:1、变量赋值成一个常量(vars = program.o foo.o utils.o);2 变量赋值成变量(变量是可以使用后面的变量来定义)(vars1 = $(vars2));3 变量赋值成变量(变量只能使用前面的变量来定义)(vars1 := $(vars));4根据条件赋值(以前不存在赋值则赋值)(vars3 ?= $(vars))
注:"="和还有追加的意思。变量之前没被定义,“ =”会自动变成“=”,如果有,那么“ =”会继承前次操作的赋值符。若前次是“:=”,那么“ =”会以“:=”作为其赋值符。
上述已经说明了:makefile第一步是建立起一个完整的依赖关系图(“=”在第一步只建立关系,“:=”在第一步遇值展开)
一个变量的值从定义它的’=‘或者’:=‘后边的第一个非空字符开始,直到注释或者换行前结束。(如下定义空格)
nullstring :=
space := $(nullstring) #end
3.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的,可能不兼容其它版本make,应尽量避免使用"$*"。
在上述所列出来的自动量变量中。四个变量($@、$<、$%、$*)在扩展时只会有一个文件,而另三个的值是一个文件列表。这些自动化变量还可以取得文件的目录名或 是在当前目录下的符合模式的文件名,只需要搭配上"D"或"F"字样。这是 GNU make中老版本的特性,在新版本中,我们使用函数"dir"或"notdir"就可以做到了。"D"的含义就是Directory,就是目录,"F"的 含义就是File,就是文件。例:$(@D)"相当于函数"$(notdir $@)"。、$(@F)
3.4 make命令行设置参数
若变量是make的命令行参数设置的,那么Makefile中对这个变量的赋值会被忽略。想在Makefile中设置这类参数的值,可以使用“override”指示符。其语法是:
override para=value 或者override :para=value
例子:
(1)override gao += abc (2) gao += abc
all: all:
@echo $(gao) @echo $(gao)
同时执行:make gao=12345 (1)结果是 12345 abc;(2)结果是 12345
3.5 目标变量和模式变量
目标变量为某个目标设置局部变量(作用范围只在这条规则以及连带规则中,不会影响规则链以外的全局变量的值)。
模式变量是我们可以给定一种“模式”,可以把变量定义在符合这种模式的所有目标上(make的“模式”一般是至少含有一个“%”的)。
target: PATA = -g 不管全局的$(PATA)的值是什么,在prog目标,以及其所引发的所有$(CFLAGS)的值都是“-g”。
%.o : PATA= -O 所有符合以[.o]结尾的目标中规则中$(PATA)的值都是“-O”。
3.6 变量高级用法
1.替换变量中共有部分,格式:“$(var:a=b)”或是“${va:a=b}”。含义:把变量“var”中所有以“a”字串“结尾”(“结尾”即“空格”或者“结束符”)的“a”替换成“b”字串。
2.“静态模式”替换。 $(val:%.o=%.c),这依赖于被替换字串中的有相同的模式.
四、文件指示
1.在一个Makefile中引用另一个Makefile,就像C语言中的include一样
在Makefile中引用其他Makefile文件的方法是,使用inclue filename.mk.
2.根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样
“函数”与“条件语句”一同使用
ifdef
do_sort func := sort
else
func := strip endif
bar := a d b g q c
foo := $($(func) $(bar))
这个示例中,如果定义了“do_sort”,那么$(foo)意思就是对%(bar)排序。没有定义“do_sort”,那么%(foo)意思就是对bar调用strip函数。
3.还有就是定义一个多行的命令(define和endef)
define指示符后面跟的是变量的名字,其工作方式和“=”操作符一样。变量的值可以包含函数、命令、文字,或是其它变量。因为命令需要以[Tab]键开头,所以如果你用define定义 的命令变量中没有以[Tab]键开头,那么make就不会把其认为是命令。
define two-lines
echo foo
echo $(bar)
endef
5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“\#”。