详细内容见 《GNU make》 16 Makefile Conventions 章节。
本章描述 GNU 程序编写 makefile 的约定。使用 Automake 将帮助您编写遵循这些约定的 Makefile。
一、makefile的通用约定
每个 Makefile 都应该包含这一行。
SHELL = /bin/sh
以避免在SHELL变量可能从环境继承的系统上出现问题(这从来都不是 GNU make 的问题)。因此,只使用特定Makefile中需要的后缀显式地设置后缀列表是一个好主意,如下所示:
.SUFFIXES:
.SUFFIXES: .c .o
第一行清除后缀列表,第二行引入所有后缀,这些后缀可能受此 Makefile 中的隐式规则的约束。
不要假设 . 在命令执行的路径中。当您需要在生成过程中运行作为包一部分的程序时,请确保它使用 ./(如果程序是作为 make 的一部分构建)或 $(srcdir)/(如果文件是源代码的不变部分)。如果没有这些前缀之一,则使用当前搜索路径。
./ (构建目录)和 $(srcdir)/ (源目录)之间的区别很重要,因为用户可以使用C选项在单独的目录中进行构建配置。以下形式的规则:
foo.1 : foo.man sedscript
sed -f sedscript foo.man > foo.1
目录不是源目录时将失败,因为 foo.man 和 sedscript 在源目录中。
当使用 GNU make 时,在存在单个依赖文件的情况下,依靠 ‘VPATH’ 查找源文件将起作用,因为 make 自动变量 ‘$<
’ 将表示源文件,无论它在哪里(许多版本的 make 仅在隐式规则中设置 ‘$<
’)。像这样的Makefile目标:
foo.o : bar.c
$(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o
应该写成:
foo.o : bar.c
$(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@
以便A能正常工作。当目标有多个依赖项时,使用显式B是使规则正常工作的最简单方法。例如,上面对于A的目标最好写成:
foo.1 : foo.man sedscript
sed -f $(srcdir)/sedscript $(srcdir)/foo.man > $@
GNU发行版通常包含一些不是源文件的文件,例如Info文件,以及来自Autoconf、Automake、Bison或Flex的输出。由于这些文件通常出现在源目录中,所以它们应该始终出现在源目录中,而不是在构建目录中。因此,更新这些文件的Makefile规则应该将更新后的文件放到源目录中。
但是,如果一个文件没有出现在发行版中,那么 Makefile 就不应该将它放在源目录中,因为在通常情况下构建程序不应该以任何方式修改源目录。
至少要让构建和安装目标(以及它们的所有子目标)使用并行 make 正确地工作。
二、makefile中的实用程序
编写Makefile命令(以及任何shell脚本,如 configure)以在 sh(传统的Bourne shell和posix shell)下运行,而不是在csh下运行。不要使用 ksh 或 bash 的任何特殊功能,也不要使用传统 Bourne sh 中未广泛支持的 posix 功能。
用于构建和安装的配置脚本和Makefile规则不应该直接使用任何实用工具,除了这些:
awk cat cmp cp diff echo egrep expr false grep install-info ln ls
mkdir mv printf pwd rm rmdir sed sleep sort tar test touch tr true
像 gzip 这样的压缩程序可以在 dist 规则中使用。
通常,坚持使用这些程序的广泛支持(通常是posix指定的)选项和功能。例如,不要使用 ‘mkdir -p’,尽管它可能很方便,因为有一些系统根本不支持它,与其他系统一起,并行执行它是不安全的。要了解已知的不兼容性列表,请参见Autoconf中的 ‘Portable Shell’ 节。
避免在 makefile 中创建符号链接是一个好主意,因为有一些文件系统不支持它们。
用于构建和安装的Makefile规则也可以使用编译器和相关程序,但应该通过 make 变量来实现,以便用户可以替换其他选项。以下是我们所说的一些程序:
ar bison cc flex install ld ldconfig lex
make makeinfo ranlib texi2dvi yacc
使用下列 make 变量来运行这些程序:
$(AR) $(BISON) $(CC) $(FLEX) $(INSTALL) $(LD) $(LDCONFIG) $(LEX)
$(MAKE) $(MAKEINFO) $(RANLIB) $(TEXI2DVI) $(YACC)
当您使用 ranlib 或 ldconfig 时,如果系统没有有问题的程序,则应确保不会发生任何不良情况。忽略该命令中的错误,并在命令之前打印一条消息,告诉用户该命令的失败并不意味着问题(自动配置 ‘AC_PROG_RANLIB’ 宏可以对此有所帮助)。
如果使用符号链接,则应为没有符号链接的系统实现回退。
可以通过 Make 变量使用的其他实用程序包括:
chgrp chmod chown mknod
在 Makefile 部分(或脚本)中使用其他实用程序是可以的,这些实用程序只适用于您知道存在这些实用程序的特定系统。
三、用于指定命令的变量
详细内容见 《makefile 变量》。
四、DESTDIR:分阶段安装支持
DESTDIR 是附加到每个已安装的目标文件之前的变量,如下所示:
$(INSTALL_PROGRAM) foo $(DESTDIR)$(bindir)/foo
$(INSTALL_DATA) libfoo.a $(DESTDIR)$(libdir)/libfoo.a
变量 DESTDIR 由用户在 make 命令行上指定为绝对文件名。例如:
make DESTDIR=/tmp/stage install
DESTDIR 应该只在 install* 和 uninstall* 目标中得到支持,因为这是唯一有用的目标。
如果您的安装步骤通常会安装 /usr/local/bin/foo 和 /usr/local/lib/libfoo.a,那么在上面的示例中调用的安装将会安装 /tmp/stage/usr/local/bin/foo 和 /tmp/stage/usr/local/lib/libfoo.a。
这种方式将变量 DESTDIR 预放在每个目标上提供了分段安装,在分段安装中,已安装的文件不会直接放置到预期的位置,而是复制到一个临时位置(DESTDIR)。但是,安装的文件保持它们的相对目录结构,任何嵌入的文件名都不会被修改。
你根本不应该在 Makefile 中设置 DESTDIR 的值;然后,默认情况下,这些文件被安装到它们预期的位置。另外,指定A不应该以任何方式改变软件的操作,所以它的值不应该包含在任何文件内容中。
DESTDIR支持通常用于包创建。对于希望了解给定包将在何处安装的用户,以及允许通常没有安装到受保护区域的权限的用户在获得这些权限之前进行构建和安装,这也很有帮助。最后,对于stow等工具来说,它也很有用,在stow中,代码安装在一个地方,但使用符号链接或特殊的挂载操作使其看起来像是安装在其他地方。因此,我们强烈建议 GNU 软件包支持 DESTDIR,尽管这不是绝对的要求。
五、安装目录变量
详细内容见 《makefile 变量》。
六、用户标准目标
详细内容见 《GUN make》 16.6 Standard Targets for Users 章节。