GNU make 学习笔记(一)

来源:互联网 发布:mac wps app 编辑:程序博客网 时间:2024/05/11 16:25
   
目标(target)通常是要产生的文件的名称,目标是可执行文件或OBJ文件。目标也可是一个执行的动作名称,诸如‘clean’。
依赖是用来输入从而产生目标的文件,一个目标经常有几个依赖。
命令是Make执行的动作,一个规则可以含有几个命令,每个命令占一行。注意:每个命令行前面必须是一个Tab字符,即命令行第一个字符是Tab。这是不小心容易出错的地方。
通常,如果一个依赖发生变化,则需要规则调用命令对相应依赖和服务进行处理从而更新或创建目标。但是,指定命令更新目标的规则并不都需要依赖,例如,包含和目标‘clean’相联系的删除命令的规则就没有依赖。
规则一般是用于解释怎样和何时重建特定文件的,这些特定文件是这个详尽规则的目标。Make需首先调用命令对依赖进行处理,进而才能创建或更新目标。当然,一个规则也可以是用于解释怎样和何时执行一个动作。
一定要牢记:Make并不知道命令是如何工作的,它仅仅能向您提供保证目标的合适更新的命令。Make的全部工作是当目标需要更新时,按照您制定的具体规则执行命令。
例如:clean :
         rm edit main.o kbd.o command.o display.o /
           insert.o search.o files.o utils.o
目标‘clean’不是一个文件,仅仅是一个动作的名称。正常情况下,在规则中‘clean’这个动作并不执行,目标‘clean’也不需要任何依赖。一般情况下,除非特意告诉make执行‘clean’命令,否则‘clean’命令永远不会执行。注意这样的规则不需要任何依赖,它们存在的目的仅仅是执行一些特殊的命令。象这些不需要依赖仅仅表达动作的目标称为假想工作目标。(切记,make无法区分文件形式的工作目标与假想工作目标)
  假想工作目标的使用:
1、以“假想工作目标”作为“假想工作目标”的必要条件;
2 、可以将假想的工作目标作为内置在makefile里的shell脚本来用,用法:以假想工作目标作为另一个工作目标的必要条件。
 
make处理makefile文件的过程
缺省情况下,make开始于第一个目标(假想目标的名称前带‘.’)。这个目标称为缺省最终目标。
其它规则的处理根据它们的目标是否和缺省最终目标的依赖相关联来判断。如果一些规则和缺省最终目标无任何关联则这些规则不会被执行,除非告诉Make强制执行(如输入执行make clean命令)。
 
使用变量简化makefile文件
例如:
在makefile文件中使用名为objects, OBJECTS, objs, OBJS, obj, 或 OBJ的变量代表所有OBJ文件已是约定成俗。在这个makefile文件我们定义了名为objects的变量,其定义格式如下:
objects = main.o kbd.o command.o display.o /
          insert.o search.o files.o utils.o
然后,在每一个需要列举OBJ文件的地方,我们使用写为`$(objects)'形式的变量代替
edit : $(objects)
        cc -o edit $(objects)
个人认为,这里解释为宏定义会更好一些。
   变量的定义:
         命名的格式:$()或者${}将变量名括住,还有许多特殊的变量是make自动定义的,这些变量中若干变量是可供用户来控制make行为,其余变量则是供make用来根用户的makefile文件沟通。
 
makefile文件的内容
以‘#’开始的行是注释行。注释行在处理时将被make忽略,如果一个注释行在行尾是‘/’则表示下一行继续为注释行,这样注释可以持续多行。除在define指令内部外,注释可以出现在makefile文件的任何地方,甚至在命令内部(这里shell决定什么是注释内容)。
 
makefile文件的命名
缺省情况下,当make寻找makefile文件时,它试图搜寻具有如下的名字的文件,按顺序:‘GNUmakefile’、‘makefile’和‘Makefile’。我们推荐使用‘Makefile’,因为它基本出现在目录列表的前面,后面挨着其它重要的文件如‘README’等。
 
包含其它的makefile文件
    include filenames...  #注意该行不能以Tab字符开始
只有在所有make寻求丢失的makefile文件的努力失败后,make才能断定丢失的makefile文件是一个致命的错误。如果您希望对不存在且不能重新创建的makefile文件进行忽略,并且不产生错误信息,则使用-include指令代替include指令,格式如下:
-include filenames...
这种指令的作用就是对于任何不存在的makefile文件都不会产生错误(即使警告信息也不会产生)。如果希望保持和其它版本的make兼容,使用sinclude指令代替-include指令。
 
变量MAKEFILES
环境变量MAKEFILES主要在make递归调用过程中起通讯作用。一些用户喜欢在登录时自动设置临时的环境变量MAKEFILES,而makefile文件在该变量指定的文件无效时才使用。这是非常糟糕的主意,因为许多makefile文件在这种情况下运行失效。最好的方法是直接在makefile文件中写出具体的include指令。
个人认为:从这段话中,可以看出,尽量不要使用MAKEFILES这个变量,而是直接用include这个指令。
 
makefile文件重新生成的过程
如果一个makefile文件可以从其它文件重新生成,一定注意让make更新makefile文件之后再读取makefile文件。如果在makefile文件中指定依据双冒号规则使用命令重建一个文件,但没有提供依赖,则一旦make运行就会重建该文件。同样,如果在makefile文件中指定依据双冒号规则使用命令重建的一个makefile文件,并且不提供依赖,则一旦make运行就会重建该makefile文件,然后重新读入所有makefile文件,然后再重建该makefile文件,再重新读入所有makefile文件,如此往复陷入无限循环之中,致使make不能再完成别的任务。如果要避免上述情况的发生,一定注意不要依据双冒号规则使用命令并且不提供依赖,重建任何makefile文件。注意make不能找到或创建makefile文件不是错误,makefile文件并不是运行make必须的。
因为即使您使用‘-t’特别指定,‘-t’或‘ - -touch’选项对更新makefile文件不产生任何影响, makefile文件仍然会更新,所以当您使用‘-t’或‘- -touch’选项时,您不要使用过时的makefile文件来决定‘touch’哪个目标。同样,因为‘-q' (或 ‘- -question') 和 ‘-n' (或 ‘- -just-print')也能不阻止更新makefile文件,所以过时的makefile文件对其它的目标将产生错误的输出结果。如,‘make -f mfile -n foo’命令将这样执行:更新‘mfile’,然后读入,再输出更新‘foo’的命令和依赖,但并不执行更新‘foo’,注意,所有回显的更新‘foo’的命令是在更新后的‘mfile’中指定的。在实际使用过程中,您一定会遇见确实希望阻止更新makefile文件的情况。如果这样,您可以在makefile文件命令行中将需要更新的makefile文件指定为目标,如此则可阻止更新makefile文件。一旦makefile文件名被明确指定为一个目标,选项‘-t’等将会对它发生作用。如这样设定,‘make -f mfile -n foo’命令将这样执行:读入‘mfile’,输出更新‘foo’的命令和依赖,但并不执行更新‘foo’。回显的更新‘foo’的命令包含在现存的‘mfile’中。
 
编写规则
有两种例外的情况:以句点(‘.’)开始的目标不是缺省最终目标(如果该目标包含一个或多个斜杠‘/’,则该目标也可能是缺省最终目标);另一种情况是格式规则定义的目标不是缺省最终目标。
 
规则的语法
因为美元符号已经用为变量引用的开始符,如果您真希望在规则中使用美元符号,您必须连写两次,‘$$’。一条规则可以告诉make两件事情:何时目标已经过时,以及怎样在必要时更新它们。
 
在文件名中使用通配符
Make中的通配符和Bourne shell中的通配符一样是‘*’、‘?’和‘[…]’。例如:‘*.C’指在当前目录中所有以‘.C’结尾的文件。
字符‘~’在文件名的前面也有特殊的含义。如果字符‘~’单独或后面跟一个斜杠‘/’,则代表您的home目录。如‘~/bin’扩展为‘/home/bin’。如果字符‘~’后面跟一个字,它扩展为home目录下以该字为名字的目录,如‘~John/bin’表示‘home/John/bin’。
通配符另一个特点是如果通配符前面是反斜杠‘/’,则该通配符失去通配能力。如‘foo/*bar’表示一个特定的文件其名字由‘foo’、‘*’和‘bar’构成。
 
函数wildcard
通配符在规则中可以自动扩展,但设置在变量中或在函数的参数中通配符一般不能正常扩展。如果您需要在这些场合扩展通配符,您应该使用函数wildcard。
个人认为:实际上wildcard的作用就是使通配符在设置变量或函数参数的时候,具有通配符的功能。
 
VPATH:所有依赖的搜寻路径
如果一个作为目标或依赖的文件在当前目录中不存在,make就会在VPATH指定的目录中搜寻该文件。在VPATH变量定义中,目录的名字由冒号或空格分开。目录列举的次序也是make 搜寻的次序。
例如:
    VPATH = src:../headers
指定了两个目录,‘src’和‘…/headers’,make也按照这个次序进行搜寻。使用该VPATH的值,下面的规则,
    foo.o : foo.c
在执行时就象如下写法一样会被中断:
foo.o : src/foo.c
然后在src目录下搜寻foo.c。
 
缺点:
     make将会为他所需要的任何文件搜索VPATH列表中的每个目录,如果在多个目录中出现同名的文件,则make只会去第一歌被找到的文件,有时会出现问题。此时可以使用vpath命令。
vpath命令:
总共由三种形式的vpath指令:

    1)、vpath pattern directories
    对一定格式类型的文件名指定一个搜寻路径。搜寻的路径由一列要搜寻的目录构成,目录由冒号(在MS-DOS、MS-WINDOWS系统中用分号)或空格隔开,和VPATH变量定义要搜寻的路径格式一样。
    2)、vpath pattern
    清除和一定类型格式相联系的搜寻路径。
    3)、vpath
    清除所有前面由vapth指令指定的搜寻路径。
一个vpath的格式,pattern是一个包含一个’%’的字符串。该字符串必须和正搜寻的一个依赖的文件名匹配,字符%可和任何字符串匹配。
例如以下代码:
vpath %.c foo
vpath %   blish
vpath %.c bar
表示搜寻`.c'文件先搜寻目录`foo'、然后`blish',最后`bar';如果是如下代码:
vpath %.c foo:bar
vpath %   blish
表示搜寻`.c'文件先搜寻目录‘foo'、然后‘bar',最后‘blish'。

个人认为:vpath指令实际上是VPATH指令的功能扩展。我在aa目录下建立一个子目录bb,Makefile文件在aa目录下,c文件在bb目录下,
vpath %.c bb  
执行完成后,生成的文件在aa目录下。同样,把指令改为VPATH= bb,效果相同。

 
   
原创粉丝点击