在众多的make版本中, GNU make是最突出的, 它已成了当前的"标准"make. 所有的GNU/Linux平台上都有提供, 一些BSD的变种, Mac OS X甚至cygwin也都使用GNU Make. 所以选择GNU make学习, 编写makefile是不二选择.
关于GNU Make, 可以看看 这篇文章 . 它摘录自 o'reilly的《GNU Make项目管理》, 这本书china-pub上有得卖, 薄薄280面, 定价却要¥58, 在此鄙视一下东南大学出版社
![](http://www.cublog.cn/images/face/028.gif)
OK, 现在步入正题, 这里假设你使用C语言进行编程.
预备知识
首先我们必须具有一些预备知识: 你知道什么叫编译, 什么叫连接吗? 目标文件和可执行文件有什么区别? 一个C源程序是如何转化为可执行程序的? 以往的IDE往往对C初学者隐藏了这些基础概念. 要使用Make, 这些概念是要清楚的.
另外, 你需要对GNU/Linux上的编译器具有一定的了解——当然是gcc啦! 因为Makefile中的命令实际上是针对编译器的命令.
可以参考本人blog的这两篇文章:
GNU/Linux平台的C程序开发及程序运行环境
GCC笔记
几个要说明的词汇
目标(target): 在makefile指定要生成的目标, 它可以是可执行文件, 目标文件, 也可以只是一个标签.
先决条件(prerequisite): makefile中指定的针对要生成某个target所依赖的文件或标号.
命令(command): Make针对target利用makefile中指定的规则所调用的命令. 它可以是你在shell中能够指定的所有命令.
GNU Make的工作原理
Make 通过 makefile文件被告知它的工作: 要生成怎样的目标文件? 由哪些代码编译生成?所以学习GNU Make实际上就是学习Makefile的写法. 下面是一个简单的makefile:
hello: hello.c gcc hello.c -o hello |
我们熟悉的hello程序,
$ make
gcc hello.c -Wall -o hello
这样我们的hello可执行程序就出来了!
make的规则: target: prereq1 prereq2 commands |
target就是目标文件 , 它可能是,o文件, 可执行文件或标签中的一种.
关于target,有这样的约定:
如果某target被包含在执行make的命令行参数中, 则更新该target; 如果make没带参数, 则将第一个target作为默认目标进行更新.
prerequisites是生成target所需要的文件.
command是make调用gcc执行的指令. 注意, command以Tab键打头 , 不能是空格!
到了这里, 就可以理解Make的原理了:
make的基本思想: 对于一个target (由命令行所指定或默认第一个target), 如果它不存在, 或者它的prerequisites中有比它更新的, 那么执行command所指定的命令. 所谓"更新", 是指比别的文件更晚被修改, make通过timestamp来记录谁更新. |
makefile文件名
-
默认情况下, make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“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 作为文件名! |
命令行中调用Make命令
(1) $ make target-name
(2) $ make
(3) $ make non-exist-target
(4) $ make -n or $ make --just-print
(1) 如果在命令行中指定了target, 则make针对该target进行工作
(2) 如果未指定target, 则make对默认target进行操作.(Makefile中出现的第一个target)
(3) 如果指定的target不存在, 则make报错:
make: *** No rule to make target `non-exist-target'. Stop.
(4) 若加上 -n 或者 --just-print选项, make只是列出将要执行的命令, 并不执行它们. 这非常有用!
Makefile 的基本语法
Makefile 采用自上而下 (top-down)的组织, 最开始的target即"终极目标", 也是默认target. 观察make输出的命令可以发现, 它们的顺序与出现在Makefile中的命令刚好相反. 可以把Makefile中针对target的规则想象成C函数. 最开始的是main(), 然后依次调用相关的函数(即针对prereq调用相关的规则).
看看一个比较简单的Makefile规则:
target1 target2 target3 : prereq1 prereq2 command1 command2 command3 |
-
第一行列出了targets和prereqs, 注意目标与它们依赖的文件之间以" : "分隔. 目标或prereq之间以空格分隔.
-
在冒号左边可以有1个或多个targets, 在冒号右边可以有0个或者多个prerequisites. 如果prerequisite的数目为0, 则只有当对应的target不存在时才执行命令.
-
如果command不和目标, 先决条件在一行,那么它之前必须以Tab开头; 如果command与目标, 先决条件在一行, 那么它要以";"开头. Make将command传递给子shell去执行.
注意: 不要忘了在命令以Tab开头, 也别在不是命令开头的地方输入Tab, 否则Make会将它之后的字符当作命令. |
-
Make中的注释符为 "#". #之前可以有空格, 从#开始到行尾的所有字符都会被忽略. 注意: 如果你把#写在了命令中, 包括#在内的行都会传递给shell, 会有什么样的结果取决于你所用的shell.
-
可以在Makefile中使用转义字符 /, 我们都知道, 在命令行中, 可以使用 / 在下一行输入命令. 同样的, 在Makefile的所有行中, 都可以使用 / 来分割太长的语句.