现在的位置: 首页 > 综合 > 正文

makefile 手册摘要

2012年01月10日 ⁄ 综合 ⁄ 共 2790字 ⁄ 字号 评论关闭

GUN make的执行过程分为两个阶段。
第一阶段:读取所有的makefile文件(包括“MAKIFILES”变量指定的、指示符“include”指定的、以及命令行选项“-f(--file)”指定的makefile文件),内建所有的变量、明确规则和隐含规则,并建立所有目标和依赖之间的依赖关系结构链表。
在第二阶段:根据第一阶段已经建立的依赖关系结构链表决定哪些目标需要更新,并使用对应的规则来重建这些目标。

make的执行过程如下:
1. 依次读取变量“MAKEFILES”定义的makefile文件列表
2. 读取工作目录下的makefile文件(根据命名的查找顺序“GNUmakefile”,“makefile”,“Makefile”,首先找到那个就读取那个)
3. 依次读取工作目录makefile文件中使用指示符“include”包含的文件
4. 查找重建所有已读取的makefile文件的规则(如果存在一个目标是当前读取的某一个makefile文件,则执行此规则重建此makefile文件,完成以后从第一步开始重新执行)
5. 初始化变量值并展开那些需要立即展开的变量和函数并根据预设条件确定执行分支
6. 根据“终极目标”以及其他目标的依赖关系建立依赖关系链表
7. 执行除“终极目标”以外的所有的目标的规则(规则中如果依赖文件中任一个文件的时间戳比目标文件新,则使用规则所定义的命令重建目标文件)
8. 执行“终极目标”所在的规则

变量取值
变量定义解析的规则如下:
IMMEDIATE = DEFERRED
IMMEDIATE ?= DEFERRED
IMMEDIATE := IMMEDIATE
IMMEDIATE += DEFERRED or IMMEDIATE
define IMMEDIATE
DEFERRED
Endef
当变量使用追加符(+=)时,如果此前这个变量是一个简单变量(使用 :=定义的)则认为它是立即展开的,其它情况时都被认为是“延后”展开的变量。

书写规则是我们需要注意的几点:
1. 规则的命令部分有两种书写方式:a. 命令可以和目标:依赖描述放在同一行。命令在依赖文件列表后并使用分号(;)和依赖文件列表分开。b. 命令在目标:依赖的描述的下一行,作为独立的命令行。当作为独立的命令行时此行必须以[Tab]字符开始。在Makefile中,在第一个规则之后出现的所有以[Tab]字符开始的行都会被当作命令来处理。
2. Makefile中符号“$”有特殊的含义(表示变量或者函数的引用),在规则中需要使用符号“$”的地方,需要书写两个连续的(“$$”)。
3. 前边已提到过,对于Makefile中一个较长的行,我们可以使用反斜线“\”将其书写到几个独立的物理行上。虽然make对Makefile文本行的最大长度是没有限制的,但还是建议这样做。不仅书写方便而且更有利于别人的阅读(这也是一个程序员修养的体现)。

wildcard使用:通配PATH下.o文件
一般我们可以使用“$(wildcard *.c)”来获取工作目录下的所有的.c文件列表。复杂一些用法;可以使用“$(patsubst %.c,%.o,$(wildcard *.c))”,首先使用“wildcard”函数获取工作目录下的.c文件列表;之后将列表中所有文件名的后缀.c替换为.o。这样我们就可以得到在当前目录可生成的.o文件列表。因此在一个目录下可以使用如下内容的Makefile来将工作目录下的所有的.c文件进行编译并最后连接成为一个可执行文件:
#sample Makefile
objects := $(patsubst %.c,%.o,$(wildcard *.c))
foo : $(objects)
cc -o foo $(objects)

@禁止命令回显
如果规则的命令行以字符“@”开始,则make在执行这个命令时就不会回显这个将要被执行的命令。典型的用法是在使用“echo”命令输出一些信息时。如:
@echo 开始编译XXX模块......
执行时,将会得到“开始编译XXX模块......”这条输出信息。如果在命令行之前没有字符“@”,那么,make的输出将是:
echo编译XXX模块......
编译XXX模块......

Makefile中命令行书写规则
Makefile中书写在同一行中的多个命令属于一个完整的shell命令行,书写在独立行的一条命令是一个独立的shell命令行。因此:在一个规则的命令中,命令行“cd”改变目录不会对其后的命令的执行产生影响。就是说其后的命令执行的工作目录不会是之前使用“cd”进入的那个目录。如果要实现这个目的,就不能把“cd”和其后的命令放在两行来书写。而应该把这两条命令写在一行上,用分号分隔。这样它们才是一个完整的shell命令行。如:
foo : bar/lose
cd bar; gobble lose > ../foo
如果希望把一个完整的shell命令行书写在多行上,需要使用反斜杠(\)来对处于多行的命令进行连接,表示他们是一个完整的shell命令行。例如上例我们以也可以这样书写:
foo : bar/lose
cd bar; \
gobble lose > ../foo

部分标准的伪目标和空目标命名:

all
作为Makefile的顶层目标,一般此目标作为默认的终极目标。

clean
这个伪目标定义了一组命令,这些命令的功能是删除所有由make创建的文件。

mostlyclean
和“clean”伪目标功能相似。区别在于它所定义的删除命令不会全部删除由make生成的文件。比如说不需要删除某些库文件。

�distclean
realclean
clobber

同样类似于伪目标“clean”,但它们所定义的删除命令所删除的文件更多。可以包含非make创建的文件。例如:编译之前系统的配置文件、链接文件等。

install
将make成功创建的可执行文件拷贝到shell 环境变量“PATH”指定的某个目录。典型的,应用可执行文件被拷贝到目录“/usr/local/bin”,库文件拷贝到目录“/usr/local/lib”目录下。

print
打印出所有被更改的源文件列表。

tar
创建一个tar文件(归档文件包)。

shar
创建一个源代码的shell文档(shar文件)。

dist
为源文件创建发布的压缩包,可以使各种压缩方式的发布包。

TAGS
创建当前目录下所有源文件的符号信息(“tags”)文件,这个文件可被vim使用。
� check
� test
对Makefile最后生成的文件进行检查。
这些功能和目标的对照关系并不是GNU make规定的。你可以在Makefile中定义任何命名的伪目标。但是以上这些都被作约定,所有开源的工程中这些特殊的目标的命名都是按照这种约定来的。既然绝大多数程序员都遵循这种约定,自然我们也应该按照这种约定来做。否则在别人看来这样Makefile只能算一个样例,不能作为正式版本。

抱歉!评论已关闭.