1、编写Makefile
UNIX系统上很多软件包都是使用make程序和Makefile文件来实现自动编译的,make程序的目的就是自动确定一个软件包的哪些部分需要重新编译,并用特定的明令去编译他们,准确的使用make可以大大减少编译程序所花费的时间,因为它可以消除不必要的再编译.
要使用make,必须编写一个makefile文件,他描述了软件包中各个文件之间的联系,提供了更新每个文件的命令.在一个软件包中,通常是可执行文件由连接目标文件而更新,而目标文件由编译源文件而更新.
当一个适当的makefile存在时,每次我们改变某些源文件,用简单的shell命令:make
将足以完成所有必须的重新编译,make程序利用makefile的数据和每个文件更新最新一次更改的时间来确定哪些文件需要更新;对每一个需要更新的文件,make程序使用makefile中定义的命令来更新它.
如果make程序没有使用-f选项指定一个makefile.make将在当前目录下按顺序寻找下列文件:GNUmakefile,makefile,Makefile.推荐使用Makefile.因为他的第一个字母是大写,通常列在目录的文件列表的最前面.
下面说明编写makefile文件的规则:
Makefile文件中包含者一些目标,对每一个目标,提供了与这个目标有相关性的其他目标或文件的名字及实现这个目标的一组命令.所谓目标就是make程序要完成的一项任务,目标通常是文件名,也可以不是;所谓相关性,即某目标的完成依赖于其他一些目标或文件,下面举一个简单的Makefile文件的例子:
#以#开头的是注释行
#一个简单的Makefile例子
prog : prog.o subprog.o
gcc -0 prog prog.o subprog.o
prog.o: prog.c prog.h
gcc -c -I -o prog.o prog.c
subprog.o: subprog.c
gcc -c -o subprog.o subprog.c
clean:
rm -f prog *.0
上面的Makefile中共定义了四个目标:prog, prog.o,subprog.o,clean.目标从每行的最左边开始写,,后面跟一个冒号(:),如果有与这个目标相关性的其他目标和文件,把他们列在冒号的后面,并以空格隔开。然后另起一行开始写实现这个目标的一组shell命令。
一般情况下,调用make命令可输入:make target
target是Makefile文件中定义的目标之一,如果省略了target,make就生成Makefile文件中定义的第一个目标。对于上面的Makefile例子,单独的make命令就等价于:make prog
make为它执行的每一条命令生成一个新的shell.其结果是,被该shell执行的命令只在单一的命令行中有效。特别是cd命令,它只能影响他所在的命令行,如在下列的命令种:
cd ../lib
gcc –o subprog.o subprog.c
对第二行,第一行的cd命令是无效的。要想在编译subprog.c之前进入../lib目录,可使用如下命令:
cd ../lib;gcc –o subprog.o subprog.c
在Makefile中,可使用续行号(\)将一个单独的命令行续成几行。但要注意在续行号后面不能跟任何字符。
Make在检查一个目标是否已经过时并需要更新时是采用按相关性递归的方法。Make在构建一个目标之前要生成该目标所依赖的所有文件、并递归地前进,从而确保这些文件是最新的。Make采用如下步骤去生成一个目标:
1. 如果一个目标不是作为一个文件存在,他就是过时了。命令make target总是执行该任务
2. make检查所有与目标有相关性的目标。
3. 递归从地层向上、对所有已过时的目标进行更新;只有当一个目标所依赖的所有目标都已是最新的时候,这个目标才可以进行更新
来通过上面的Makefile文件例子来看一下目标更新的过程。现在假设修改了文件subprog.c,用如下命令来更新目标prog: make prog
由于目标prog依赖于目标prog.o和subprog.o.我们必须检查目标prog.o和subprog.o是否过时。目标prog.o依赖于prog.c和prog.h。检查目标文件prog.o和源文件prog.c和prog.h的日期,发现prog.o比他所依赖的源文件要新,即并不过时。在检查subprog.o,他依赖于subprog.c.由于我们编辑了subprog.c文件,他的日期比目标文件subprog.o的日期要心。即subprog.o过时了。我们用定义目标subprog.o的shell命令来更新它:
gcc –c –o subprog.o subprog.c
由于目标subprog.o过时并更新,导致目标prog已经过时,要完成make prog任务,必须用定义prog的一组shell命令来更新它:
gcc –o prog prog.o subprog.o
如果我们第一次编译上面的软件,则因为prog、prog.o、subprog.o等目标文件不存在,按照约定,所有目标prog、prog.o和subprog.o都是过时的,都必须更新。即必须从底向上执行这些目标的所有命令。
在上面的Makefile例子中,还定义了一个目标clean.clean目标是Makefile中常见的一种专用目标,即删除所有的目标模块。
另一个常用的目标模块是install。他通常将编译完成的可执行文件和程序运行所需的其他文件拷贝到指定的安装目录中,并设置相应的保护。
为了简化命令的编写,在Makefile中可以定义一些宏(macro)和使用几个预定义的缩写。
下面是几个很常用的缩写:
$@ 代表该目标的全名
$* 代表已经删除了后缀的目标名
$< 代表该目标的第一个相关目标名
按照这样的缩写:前面的Makefile例子可改写成:
#以#开头的是注释行
#一个简单的Makefile例子
prog : prog.o subprog.o
gcc –o $@ prog.o subprog.o
prog.o: prog.c prog.h
gcc -c -I -o $@ $<
subprog.o: subprog.c
gcc -c -o $@ $*.c
clean:
rm -f prog *.0
一个宏定义从一行的最左边开始书写,具有如下格式:
macro-name=macro-body
当make 处理该Makefile时,就用macro-bodt代替$(macro-name)串。如上面的Makefile的例子可用定义宏的方法使之更简洁清晰:
#以#开头的是注释行
#一个简单的Makefile例子
DEPENDS=prog.o subprog.o
prog :$(DESPENDS)
gcc –o $@ $(DEPENDS)
prog.o: prog.c prog.h
gcc -c -I -o $@ $<
subprog.o: subprog.c
gcc -c -o $@ $*.c
clean:
rm -f prog *.0
在定义一组编译选项时,宏定义也是很有用的,如下的宏定义了两个编译选项
CFLAGS=-DDEBUG –g
我们可以在Makefile中用如下的命令编译用于调试的目标文件
gcc –c $(CFLAGS) –o prog.o subprog.o
如果在Makefile文件中没有给出某一个目标的相关目标构造这一目标的命令,make程序将适用隐含规则。Make程序预定义了一些隐含规则,每个隐含规则适用于一个目标类型和他相关类型的组合。
隐含规则通过后缀规则实现的。带有那些后缀的目标隐含规则是由make程序的内置目标.SUFFIXES的相关目标列表定义的。缺省的后缀烈表是:..out、.a、.ln、.o、.c、.cc、.C、.p、.f、.F、.r、.y、.l、.s、.S、.mod、.sym、.def、.h。在所有的隐含规则中尤许的目标或相关类型必须是上列类别中的一种。
如果不想使用make的隐含规则,可以自己定义自己的后缀规则,如下所示:
.c.o
gcc -c -g -DDEBUG -DHELP_FIFLE=\”help\” -o $*.o $<
后缀规则适用于所有的UNIX版本的Make程序,GNU的make程序提供了一种更方便的规则定义方式,称为模式规则。模式规则的格式类似Makefile中的一般的定义,但它使用百分号(%)作为通配符,如下所示:
%.o:%.c
gcc $(CFLAGS) -c $<
表示从.c文件生成.o文件的规则。
模式规则不依赖于后缀列表。
2、使用automake和autoconf产生Makefile
参照这篇文章轻松产生Makefile文件