Makefile的约定
1.基本的约定
本节讨论的是书写Makefile中需要的一些基本约定,由于不同版本make之间的一些差异。可能在GNU make环境中正常工作的Makefile,换成其它版本的make执行时会发生错误。为了最大可能的兼容不同版本的make,这里给出了一些基本的约定。
1. 所有的Makefile中应该包含这样一行:
SHELL = /bin/sh
这样做的目的是为了避免变量“SHELL”在有些系统上可能继承同名的系统环境变量而导致错误。虽然在GNU版本的make中不会出现这种问题(GNU make中变量“SHELL”的默认值是“/bin/sh”,它不同于系统环境变量“SHELL”)。
2. 小心处理后缀和隐含规则。不同make的可识别后缀和隐含规则存在不兼容,它可能会导致混乱或者错误。因此在特定Makefile中明确限定可识别的后缀是一个不错的注意。Makefile中应该这样做:
.SUFFIXES:
.SUFFIXES: .c .o
第一行首先取消掉make默认的可识别后缀列表,第二行通过特殊目标“.SUFFIXES”重新指定可识别的
后缀规则。
3. 小心处理规则中的路径。当需要处理指定目录的的文件时,需要明确指定路径。如“./”代表当前目录,“$(srcdir)”代表源代码目录。当没有指定明确路径时,意味着是当前目录。
目录“./”(当前目录,GNU的发布软件包中的“build”目录)和“$(srcdir)”的区别和重要,我们可以通过“configure”脚本的选项“--srcdir”指定源代码所在的目录(可参考GNU发布的软件包中的configure脚本)。当源代码目录和build目录不同时,规则:
foo.1 : foo.man sedscript
sed –e sedscript foo.man > $@
将执行失败,是因为“foo.man”和“sedscript”并不在当前目录(当然,处理这种错误的手段可能有很多,诸如使用变量“VPATH”等)。当前目录只是build目录,并不是软件包目录。
4. 使用GNU make的变量“VPATH”指定搜索目录。当规则只有一个依赖文件时。我们应该使用自动化变量“$<”和“$@”代替出现在命令的依赖文件和目标文件(其它版本的make,只在隐含规则中设置自动化变量“$<”)。对于一个这样的目标:
foo.o : bar.c
$(CC) – I. –I$(srcdir) $(CFLAGS) –c bar.o –o foo.o
我们在Makefile中应该是用这种方式来书写:
foo.o : bar.c
$(CC) – I. –I$(srcdir) $(CFLAGS) –c $< –o $@
另外,对于有多个依赖的规则,为了规则能被正确执行。应该在规则的命令行中明确的指定文件的完整路径名。例如第一个例子就可以这样写(需要在规则之前使用“VPATH”指定搜索目录):
foo.1 : foo.man sedscript
sed –e $(srcdir)/sedscript $(srcdir)/foo.man > $@
在GNU的发布软件包中,包括了很多非源代码的文件。诸如:“info”文件、“Autoconf”的输出文件、“Automake”、“Bison”或者“Flex”等文件。这些文件在发布时就在源代码的目录中。因此Makefile中对它们的重建也应该是在源代码目录,而不应该在build目录。
相反的,对于那些本来就不存在于源代码目录下的文件,也不应该将它们创建在源代码的目录下。要记住,make的过程不应该以任何方式修改源代码,或者改变源代码目录的结构。
2.规则命令行的约定
本节将讨论书写规则命令的一些约定,在书写多系统兼容的Makefile时,特别需要注意不同系统之间的命令的不兼容。这里对规则命令行做出了一些基本约定:
1. 书写Makefile时,规则的命令(包括其他的脚本文件,如:configure)应该是“sh”而不因该是“csh”所支持的。
2. 用于创建和安装的“configure”脚本和Makefile中的命令除下面所列出的意外,避免使用其它命令:
cat cmp cp diff echo egrep expr false grep install-info
ln ls mkdir mv pwd rm rmdir sed sleep sort tar test touch true
3. 在目标“dist”的命令行中可以使用压缩工具“gzip”。
4. 对于可使用的这些工具命令,尽量使用它的通用选项。不要使用那些只在特定系统上有效的选项。如:“mkdir -p”这个命令在Linux系统上能够很好的工作,但是其它很多系统却并不支持“mkdir”的“-p”选项。
5. 尽量不要在规则的命令行重创建符号连接文件(使用“ln”命令)。因为有些系统不支持(对于类Unix的系统我们基本上没有问题,可能这里所说的是MS-DOS系统的系统。我想大家也没有兴趣或者说没有必要在MS-DOS下写Makefile,所以这个限制基本可以不考虑)。
6. 重建或者安装目标(一般是伪目标)的命令行可使用编译器或者相关工具程序,应该使用一个变量来表示所要执行的命令。这样会比较方便,需要修改一个命令时,只需要更改变量的值就可以了。对于以下的这些命令程序:
ar bison cc flex install ld ldconfig lex
make makeinfo ranlib texi2dvi yacc
Makefile规则中的命令行中,使用以下这些变量来代替它们:
$(AR) $(BISON) $(CC) $(FLEX) $(INSTALL) $(LD) $(LDCONFIG) $(LEX)
$(MAKE) $(MAKEINFO) $(RANLIB) $(TEXI2DVI) $(YACC)
如果在规则的命令行需要使用“ranlib”或者“ldconfig