文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>"make"使用入门(转)

"make"使用入门(转)

时间:2006-03-23  来源:rwen2012

"make"使用入门

原文作者:Suminder S. Ahuja

翻译:艾艾

正文:

  • 概述

  • makefile介绍

  • makefile组成

    • 注释

    • 显式规则

      • make的执行

      • 使用make的好处

    • 定义变量

      • 引用替换和计算变量名

      • 递归扩展和简单扩展变量

      • 给变量添加文本

      • 自动变量

      • 特定目标和特定模式变量值

    • 隐含规则

    • 指示

      • "Define" 指示

      • "Include" 指示

      • "Override" 指示

  • 命令回显

  • 伪目标

  • 在文件名中使用通配符

  • 命令中的错误

  • 并行执行

  • 用make更新归档文件

  • 结论

  • 附加参考

  • 关于作者

概述

make是UNIX®下的一个工具,用来自动创建程序并且进行优化. 当你开发的程序由许多组件或源文件组成时它特别有用.

一个叫makefile的描述符文件阐明了源文件之间的关系,并给出更新每一个文件的命令. 任何时候当源文件之一有所改动,make就调用 makefile自动重建这个程序. 因为仅重编译那些受改动影响的文件,因此节约了编译时间.同时也有助于降低用命令行建立这些条目时发生人为错误的可能性.

除了编译以外, make也是一个可用于程序安装和更改系统配置的有效工具.

makefile介绍

为每一个工程创建一个名为makefile的配置文件. 每次修改源程序后, 用简单的命令make调用makefile来执行必要的重编译. make在当前工作目录中按以下的顺序查找这个描述文件:

makefile

Makefile

缺省条件下, 简单的make命令只创建文件中第一个目标. make命令的其它一般用法如下.

make prog1

建立目标 "prog1"

make -f mymakefile

用 "mymakefile" 作配置文件建立源文件中的第一个目标

make -f mymakefile prog1

用 "mymakefile" 作配置文件建立目标 "prog1"

makefile组成

makefile包含的五个主要部分是: 注释, 显式规则, 变量定义, 隐式规则以及指示.

注释

makefile中以'#'开始到行末的内容是注释.一个注释可以延续到多行,只要在行末加上一个('/'),但这个反斜线不能被另一个反斜线所转义. 注释可以放在一行中的任何位置,在'#' 之前的内容不属于注释. 缺省的/bin/sh shell允许命令行注释,但不允许在定义指示的时候加注释.

显式规则

makefile由'规则'(rules)组成. 规则说明在何时和如何重建某些文件,这些文件又可能是其他一些特定文件的目标. 规则由三部分组成: 一个或多个目标(target), 零个或多个先决条件(prerequisites), 零个或多个命令(command).

target ... : prerequisites 

            command

           ...

           ...

目标是make创建的域的通常叫法;例如可执行文件或目标文件. 目标也可以是要执行的动作的名字, 例如, clean (见伪目标). 一旦任何先决条件变化将引起目标被创建. 如果目标存在且比它的先决条件新,则认为目标是"最新"的.

先决条件是一个或多个文件,作为创建目标的输入. 先决条件的目的是定义某些目标对某些源文件的依赖属性.

命令是在有先决条件的规则之中. 它是当任何先决条件改变时make创建或更新目标采取的动作. 一条规则可包含多个命令. 每个在规则中执行的命令由shell解释执行. 缺省情况下, make用/bin/sh shell. 宏SHELL = bin/sh将覆盖缺省shell.

make的执行

make遵循"依赖规则"概念; make 读取当前目录下的makefile,从处理第一个目标开始. make查找每个目标的依赖(先决条件)以知道它们是否也作为目标列了出来 .

make沿依赖链遍历整个递归链直到发现一个没有先决条件的目标,或者其先决条件没有规则. 一旦到达依赖链的末端, make便返回递归,在返回的过程执行每条目标规则中的命令. 对于遇到的所有有规则的先决条件, make采用同样的模式处理 .

一旦所有先决条件规则运行完了, make最后返回第一个目标 . 如果目标不存在, 或者目标比它现在的先决条件生成的早, make运行命令来生成目标, 如以下是一个makefile的例子 (例 1.0).

# Example 1.0

# Linking object files

prog1 : main.o file1.o \

        file2.o display.o

           cc -o prog1 main.o file1.o \

                      file2.o display.o

# Compiling source files

main.o : main.c mydefs.h

    cc -c main.c

file1.o : file1.c mydefs.h

    cc -c file1.c

file2.o : file2.c command.h

    cc -c file2.c

display.o : display.c command.h

    cc -c display.c

# Compiling source files

..PHONY : clean

clean :

            rm prog1 *.o

# End of makefile 

注意: 参考命令回显.

在前面的例子中, 我们已经给变量objs赋了值.

objs    = main.o file1.o file2.o display.o

一旦变量定义好了, 它的值可以用$(variable)或 ${variable}提取出来. 然而, 如果圆括号遗漏了, 那么只有变量名的第一个字符被用到. 因此:

·$(objs)得到变量objs的值.

·$objs 得到变量 o 的值(如果有变量o).

make能灵活的使用未定义的变量; 这种情况下值返回空串. 在设定一个变量前, make可以用快捷符'?='检查它是否已被设置. 下面的例子检查 foo是否已经被设置:

foo ?= bar

如果没有, make 将分配给它一个值.

引用替换和计算变量名

还有两个引用变量的高级特性是引用替换和计算变量名.

·引用替换

引用替换用你指定的值替换变量的值. 它的格式象这样:'$(var:x=y)', 意思是取得变量 var的值, 用y替换变量值中每个单词结尾处的x, 并取代结果字串. 下面的例子设定bar为a.c b.c c.c:

foo := a.o b.o c.o

bar := $(foo:.o=.c)

·计算变量名

在变量名内部可以引用另一个变量; 这称为计算变量名.

例:

a = b
b = c
x  :=  $($(a))

本例赋x值为'c'. $(a)展开为 'b', 所以$($(a))即$(b); 而 $(b)展开为'c'.

递归扩展与简单扩展变量

变量有两种方法获得值, 递归扩展变量和简单扩展变量.

递归扩展变量

简单扩展变量

行赋值用'=' 或 用 "define" 指示

用行':='赋值

值的指定是逐字被装配的.

变量在定义时一次扫描获得其值

不论何时变量被替代都展开对其他变量的参考.

不包含对其它变量的参考; 包含它们被定义的值.

例:

        foo = $(bar)

        bar = $(yep)

        yep = hello

命令:

        all :;echo $(foo)

将显示'hello'.  $(foo)将展开为$(bar), $(bar)展开为$(yep)最终展开为'hello'.

例:

        a :=  foo          

        b :=  $(a) bar

        a :=  hello

等价于:

        b :=  foo bar           

        a :=  hello

执行是有目的的,却导致make运行速度很慢, 因为每当变量扩展时在此定义中的引用都要执行一遍.

更容易预测复杂的makefile的编写.

给变量添加更多文本

我们常需要给一个已存在的变量添加更多的文本. 快捷操作符 '+=' 提供了这种灵活性. 在下面这个例子中, 先取得objs的值然后给这个值加上文本file3.o :

objs  +=  file3.o

这样我们就能够设定objs为main.o file1.o file2.o display.o file3.o:

objs =  main.o file1.o file2.o display.o

objs +=  file3.o

自动变量

基于规则的目标和先决条件,此类变量的值在每条已执行的规则中都各不相同. 在下一节隐式规则的例1.2中, '$@' 用于目标文件名, '$+' 用于源文件名.

通用的自动变量包括以下这些.

$@

规则目标的文件名

$%

目标成员名, 此时目标是一个归档成员

$<

第一个先决条件名

$?

所有比目标新的先决条件名

$^

全体用空格符分隔的先决条件名

$+

类似于'$^', 但是重复的先决条件会以它们在 makefile中列出的次序多次列出。

特定目标和特定模式的变量值

·特定目标变量值

根据make所建目标的不同,这个功能可以为相同的变量赋不同的值. 该值在目标的命令脚本的上下文中局部可用. 格式如下:

target ... : variable-assignment

下面的语句在prog1以及它的先决条件的命令脚本中设置CFLAGS为-g :

prog1 : CFLAGS = -g

prog1 : main.o file1.o file2.o display.o

·特定模式变量值

此特征让你为任何匹配这种特别模式的目标定义一个变量. 模式表示为 '%'. 接下来的例子中,对于所有匹配模式%.o的目标分配给CFLAGS值-o:

%.o : CFLAGS = -o

(更多信息请参考 附加参考.)

隐式规则

隐式规则告诉make如何采用惯例方法,这样就不必在每次用到时都要详细指定它们. 其中一条隐式规则是用cc -c命令更新文件'.o',其源文件是相应的'.c'文件. 用隐式规则, 前一个例子中的makefile可以写成下面的形式(例 1.2).

 

# Example 1.2

#1

# Defining the compiler

CC=gcc

#2

# Defining the object (objs)  variable

objs = main.o file1.o file2.o display.o

#3

# Linking object files

prog1 : $(objs)

        $(CC) -o $@ $+

        echo prog1 : make complete

#4

# Tell make how to build .o from .c files

%.o:%.c

          $(CC) -c $+

#5

# Compiling source files.

main.o : mydefs.h

file1.o : mydefs.h

file2.o : command.h

display.o : command.h

#6

# Removing the executable and object files

..PHONY : clean

clean :

         rm prog1 $(objs)

         echo clean : make complete

# End of makefile

 

注意:

1.编译器变量提供了对同一个makefile使用不同的编译器的灵活能力.

2.变量objs定义为全体目标文件.

3.'$@'自动变量意思是目标, '$+' 意思是全体以空格分隔的先决条件.

4.模式规则告诉 make如何转换*.c 文件为 *.o 文件.

5.make有一个内建模式将*.h文件转换为依赖*.o文件.

6.make删除现有目录下的prog1和全部对象文件 (见 伪目标).

以隐含规则建立的命令用到某些预定义的变量, 这些变量分成两类: 一类是程序名 (象 CC) 另一类是对应这些程序的特定变量 (如 CFLAGS).

如下是一些内建规则中用作程序名的变量.

AR

存档文件维护程序, 缺省是 ar

AS

做汇编的程序, 缺省是 as

CC

编译C程序的程序, 缺省是 cc

CXX

编译C++程序的程序 , 缺省是 g++

RM

删除文件命令, 缺省是 rm -f

下列一些变量它们的值是程序附加的参数.

ARFLAGS

给归档维护程序的标志; 缺省是 rv

ASFLAGS

给汇编器的额外标志

CFLAGS

给C编译器的额外标志

CXXFLAGS

给C++编译器的额外标志

指示

"Define" 指示

define指示给变量赋值. define指示与跟着的变量名在同一行. 变量值在下一行. 最后一行的endef表示define结束. define作用类似于'=', 举例如下:

define two-lines

echo foo

echo $(bar)

endef

普通变量赋值和define指示的区别在于普通赋值不能含换行符, 而在define的值里分割行的换行符成为变量值的一部分.

以上例子功能等同于:

two-lines = echo foo; echo $(bar)

以分号分开的两条命令作用很象两条分别的shell命令. 然而, 注意到分在两行make将调用两次shell, 对每一行运行一次独立的子shell.

"Include" 指示

指示include告诉make暂停读取当前makefile转而读取每一个列出的文件. 读完以后, make 在指示中出现的地方重新读取makefile. 格式如下:

include filenames...

filenames可以含shell文件名模式.

举个例子, 如果你有三个 '.mk' 文件, 'x.mk', 'y.mk', 及 'z.mk', 并且$(bar)是展开为 bish bash, 那么下列表达式:

include foo *.mk $(bar)

等价于:

include foo x.mk y.mk z.mk bish bash

include指示的一个用法是分配一个公共变量定义集给被各自"makefile"文件处理的程序 .

"Override" 指示

override 指示可以设置makefile中已经用命令参数设置过的变量. 格式如下:

override variable = value

给在命令行中定义的变量添加文本, 用:

override variable += more text

此指示被发明来做更改或增加用户在命令行中指定的值. 举例来说, 假定你总是希望C编译器用-g开关, 但是你又不想让用户象通常一样用命令参数指定其他开关. 你可以用override指示:

override CFLAGS += -g

命令回显

make在一行被执行前先显示它, 叫做回显. 以'@'起始的命令则不回显 . echo也可以用来指示makefile的进度. 如下所示:

echo prog1 : make complete

加上-n标志, make只回显命令但不真正执行它们. 只有这种情况, 即使命令以 '@' 开头亦会显示. 为防止一切回显, 可以用-s标志. 输出就如同每条命令都以'@'开头.

伪目标

伪目标不是一个文件名而是由一个显式请求引起的动作. 在伪目标中的命令不创建任何目标, 但每次目标发生重建时命令都要执行. 举例如下:

clean :

            rm prog1 *.o

当命令象下面这样显式的调用时,将删除 prog1及所有目标文件:

make clean

因为rm不是创建一个名为 clean的文件, 可能这个文件根本不曾存在. 但如果某人确实在这个目录下建了名为clean的文件, 伪目标将停止工作. 文件clean在没有先决条件时将不可避免的被认为是最近更新的, 它的命令也不会执行.

为避免这个问题, 目标被定义为 .PHONY. 在下面的例子中, make clean 将运行命令而不论是否真有名clean 的文件:

.PHONY  :  clean

clean  :

           rm  prog1  *.o

在文件名中用通配符

单个文件名用通配符可指代多个文件. make在目标先决条件, 命令和变量中用到通配符 '*', '?', 以及'[...]'. 通配符可以用在规则命令中, 这些命令被shell展开. 例如, 这是删除所有目标文件的规则:

clean:

        rm *.o

当你定义变量时通配符是不会展开的. 即, 如果你这样写:

objects = *.o

那么变量对象的值是真实的字符串 '*.o'.

命令中的错误

命令执行完以后, make 检查退出状态以验证其已经成功完成, 同时发送下一条命令到新shell. 如果返回错误, make 放弃当前规则,很可能放弃所有规则. 要忽略命令行中的错误, 在行开头加上'-'号 (在初始的tab后). '-'号在命令传递给shell执行前丢弃. 下面的例子即使rm不能删除文件它也继续运行, :

clean:

        -rm  -f  *.o

类似的特性也可以通过在make后加-i参数实现; 全体规则中的全部命令的错误都被忽略.

并行执行

缺省情况下, make一次只运行一条命令, 在执行下一条命令前等待上一条命令执行结束. make用'-j'选项可以同时执行多条命令. '-j'选项后缀的整数指定一次可以运行作业的数量.

用make更新归档文件

被叫做成员的归档文件通常用作链接的子程序库. 它们由程序ar维护. 格式如下:

archive(member)

make中独立的文件成员可以作为目标或先决条件. 在下面的例子中, 是要通过复制文件foo.o在归档sublib中创建成员foo.o :

sublib(foo.o)  :  foo.o

           ar  cr  sublib foo.o

结论

本文是使用makefile入门教程, 内容涉及所有知识面. make还有许多特性可以在下列参考中发现. 用你自己的新makefile试一试.

相关阅读 更多 +
排行榜 更多 +
Event Horizon

Event Horizon

飞行射击 下载
Counter Terrorist Sniper Shoot

Counter Terrorist Sniper Shoot

飞行射击 下载
Special Agent

Special Agent

飞行射击 下载