make的简介

 

程序

什么是 make?  当你写一个简单的程序,只有一到两个源文件的时候,输入  % cc file1.c file2.c  就没什么问题,但如果有很多源文件就会很烦人──编译的时间也会很长。  一个方法就是使用目标文件,只在源文件有改变的情况下才重新编译源文件。因此你可以这样做:  % cc file1.o file2.o ... file37.c ...  上次编译后,file37.c 发生了改变,但其他文件没有。这样做可以让编译过程快很多,但是也不能解决累人的输入问题。  或者我们可以使用一个 shell script 来解决输入问题,但是也需要重新编译所有文件,在大型项目上很没有效率。  如果有成百上千的源文件的话怎么办?如果我们在与很多人合作写程序,别人对源文件进行了修改,又没有告诉你,该怎么办?  也许我们可以把以上两种方法结合,写一种像 shell script 一样的东西。这种文件包含某种技巧可以决定什么时候该对源文件进行编译。现在所有我们要的就是一个程序可以懂得这种技巧,因为要懂得这种技巧,shell 还没那么大的能耐。  这个程序就叫 make。它读入一个文件,叫 makefile,这个文件决定了源文件之间的依赖关系。而且决定了源文件什么时候该编译什么时候不应该编译。例如,某个规则可以说 “ 如果 fromboz.o 比 fromboz.c 要旧,意思就是有人修改了 fromboz.c,因此我们需要重新编译这个文件。”这个 makefile 还有规则通知 make 该 怎么 重新编译源文件,因此 make 是一个强大得多的工具。  makefile 通常和相关的源文件保存在同一个目录下,可以叫做 makefile,Makefile 或者 MAKEFILE。大多数程序员会使用 Makefile 这个名字,因为这样可以让这个文件被放在目录列 表的顶端,可以很容易得看见。

使用 make 的例子

这是一个非常简单的 make 文件:  foo: foo.c  cc -o foo foo.c  包含两行,一行是依赖关系,一行是执行动作。  依赖关系的那一行包含了程序的名字 (叫做 target),紧跟着一个冒号,然后是空格,最后是源文件的 名字。当 make读入这一行的时候,会检查 foo 是否存在;如果存在,就比较 foo 和 foo.c 最后的修改时间有什 么不同。如果 foo 不存在,或者比 foo.c 要旧,就检查执行动作那一行看看该怎么做。换句话 说,就是 foo.c 需要重新编译的时候该怎么办。  执行动作那一行以一个 tab (按下 tab) 开始,然后是你在命令行下产生 foo 所执行的命令。如果 foo 过期了,或者不存在,make 就会 执行这个命令来产生 foo。换句话说,这就是重新编译 foo.c 的规则。  因此,当你输入 make 时,它会确定 foo 和 foo.c 在修改时间上是否同步。这个原则可以在 Makefile 里扩展到成百上千的目标文件上──实际上,在 FreeBSD 里,你只要在合适的目录下输入 make world 就可以编译整个操作系统!  makefile 另一个有用的特点就是目标文件不一定就是程序。例如,我们可以 有这样的 make 文件。  foo: foo.c  cc -o foo foo.c  install:  cp foo /home/me  我们可以输入如下的命令告诉 make 该执行哪个目标:  % make target  make 会只执行这个目标而忽略其他的目标。例如,如果我们输入 make foo,就只有 foo 被执行,必要的情况下重新编译 foo 而不会继续执行 install 这个目标。  如果我们只是输入 make 这个命令,make 总会寻找第一个目标,并且在执行完以后就不管其他的目标了。例如,如果我们输入 make foo,make 就会转到 foo 这个目标,在必要的情况下重新编译 foo,而不会执行 install 目标, 然后就停止了。  一定要注意,install 这个目标不依赖任何其他的东西!这意味着我们一旦输入 make install,这个目标下的所有命令都将被执行。这种情况下,foo 将被安装到用户的家目录下。应用程序的 makefile 正是这样写的,以便程序在正确编译后可以被安装到正确的目录。

 

  要尝试解释的话会比较容易让人混淆。如果你不太懂 make 是如何工作的,最好的办法就是先写一个简单的程序例如 “hello world” 以及和上面的例子相同的 make 文件再去实验。然后 再进一步,使用多个源文件,或者让你的源文件包含一个头文件。 touch 命令在这里就非常有用了──它能让在不改变文件内容的情况下改变文件的日期。

 

 

 

 

 

简单的 Makefile 文件

为便于不熟悉 make 的读者理解,本节提供一个简单的用法示例。Make 凭借本身的优势,可在所有的 Unix 系统中被找到。要了解关于Gnu make 的更多信息,请参考 Richard M. Stallman 和 Roland McGrath 编写的 GNU Make 手册。

Make 从 makefile(默认是当前目录下的名为‘Makefile’的文件)中读取项目的描述。makefile指定了一系列目标(比如可执行文件)和依赖(比如对象文件和源文件)的编译规则,其格式如下:

目标: 依赖
	命令

对每一个目标,make 检查其对应的依赖文件修改时间来确定该目标是否需要利用对应的命令重新建立。注意到,makefile 中命令行必须以单个的 TAB 字符进行缩进,不能是空格。

GNU Make 包含许多默认的规则(参考隐含规则)来简化 makefile 的构建。比如说,它们指定‘.o’文件可以通过编译‘.c’文件得到,可执行文件可以通过将‘.o’链接到一起获得。隐含规则通过被叫做make变量的东西所指定,比如 CC(C 语言编译器)和 CFLAGS(C程序的编译选项);在makefile文件中它们通过独占一行的 变量=值 的形式被设置。对 C++ ,其等价的变量是CXXCXXFLAGS,而变量CPPFLAGS则是编译预处理选项。

现在我们为上一节的项目写一个简单的 makefile 文件:

CC=gcc
CFLAGS=-Wall
hello: hello.o hello_fn.o
clean:
	rm -f hello hello.o hello_fn.o

该文件可以这样来读:使用 C 语言编译器 gcc,和编译选项‘-Wall’,从对象文件‘hello.o’和‘hello_fn.o’生成目标可执行文件 hello(文件‘hello.o’和‘hello_fn.o’通过隐含规则分别由‘hello.c’和‘hello_fn.c’生成)。目标clean没有依赖文件,它只是简单地移除所有编译生成的文件。rm命令的选项 ‘-f’(force) 抑制文件不存在时产生的错误消息。

另外,需要注意的是,如果包含main函数的cpp文件为A.cpp, makefile中最好把可执行文件名也写成 A。

要使用该 makefile 文件,输入 make。不加参数调用make时,makefile文件中的第一个目标被建立,从而生成可执行文件‘hello’:

$ make
gcc -Wall -c -o hello.o hello.c
gcc -Wall -c -o hello_fn.o hello_fn.c
gcc hello.o hello_fn.o -o hello
$ ./hello
Hello, world!

一个源文件被修改要重新生成可执行文件,简单地再次输入 make 即可。通过检查目标文件和依赖文件的时间戳,程序 make 可识别哪些文件已经修改并依据对应的规则更新其对应的目标文件:

$ vim hello.c (打开编辑器修改一下文件)
$ make
gcc -Wall -c -o hello.o hello.c
gcc hello.o hello_fn.o -o hello
$ ./hello
Hello, world!

最后,我们移除 make 生成的文件,输入 make clean:

$ make clean
rm -f hello hello.o hello_fn.o

一个专业的 makefile文件通常包含用于安装(make install)和测试(make check)等额外的目标。

本文中涉及到的例子都足够简单以至于可以完全不需要makefile,但是对任何大些的程序都使用 make 是很有必要的。

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值