Makefile Conventions
- Makefiles通用规范
- Makefiles中的常用工具
- DESTDIR
- 安装目录相关的变量
- 标准目标
- Prefer an info file in . to one in srcdir.
- Run install-info only if it exists.
- Use ‘if’ instead of just prepending ‘-‘ to the
- line so we notice real errors from install-info.
- Use ‘$(SHELL) -c’ because some shells do not
- fail gracefully when there is an unknown command.
Makefiles通用规范
每个Makefile都应该包含如下内容:
1 | SHELL = /bin/sh |
对SHELL变量进行赋值是为了避免在一些系统上SHELL环境变量设置错误导致出现问题。
不同的make程序可能有不兼容的后缀列表和隐含规则,因此有时可能造成误解甚至误用。为此,最好的方法是显式设置后缀列表,如下所示:
1 | .SUFFIXES: |
上面第一行清除后缀列表,第二行声明隐含规则可能处理的后缀列表。
在命令执行中,不要假设.是路径。当你需要在make编译期间运行一个程序时,如果那个程序是make构建出来的,请确保使用./作为前缀;如果该程序位于源码目录下,请使用$(srcdir)/作为前缀。如果不使用这些前缀,默认的搜索路径将是当前路径。
区分./(构建目录)与$(srcdir)/(源码目录)是十分重要的,因为用户可能在构建时使用’--srcdir’选项指定非当前目录的源码作为输入。如下例:
1 | foo.1 : foo.man sedscript |
如果构建目录与源码目录不同,则构建将失败,因为foo.man和sedscript位于源码目录。
当使用GUN make是,依赖于’VPATH’去指定源码文件搜索路径,这样在使用”$\<”这条隐含规则时,其所所代表的含义是指搜索目录下所有的源文件。一个Makefile的例子是:
1 | foo.o : bar.c |
应该被这样改写:
1 | foo.o : bar.c |
为了让”VPATH”正常工作,当构建目标有多个依赖项时,使用$(srcdir)去指定源码路径是一个更简单容易的方法,例如,对于如上的构建目标foo.1最好被写成如下这样:
1 | foo.1 : foo.man sedscript |
在GNU的源码分发标准下,通常不仅仅包含源码文件,可能还包含信息文件和Autoconf、Automake、Bison或者Flex的输出文件。这些文件通常都位于源码目录下,因此,Makefile规则在更新它们的时候也应将更新后的文件放到源码目录。
Makefiles中的常用工具
写Makefile文件,应该保证其中使用的命令是能在sh(包含传统的Bourne shell和POSIX shell)下运行的,而不是csh,不能使用ksh、bash所支持的特殊特性。
在写configure脚本和Makefile规则时,能够直接在其中使用的工具包含如下:
1 | awk cat cmp cp diff echo egrep expr false grep install-info ln ls |
如gzip这样的压缩程序能够在dist规则中使用。
通常,不要使用具有平台差异性的命令,如’mkdir -p’,这样使用虽然很方便,但对于有些系统而言不支持,并且也是非多线程安全的。要了解更多这样的例子可参考 Portable Shell Programming。
对于符号链接来说,也应该避免在Makefile中创建,因为有些文件系统不支持符号链接。
在Makefile规则中,可以方便地使用变量来表示如下这些程序:
1 | ar bison cc flex install ld ldconfig lex |
可表示为:
1 | $(AR) $(BISON) $(CC) $(FLEX) $(INSTALL) $(LD) $(LDCONFIG) $(LEX) |
当你使用ranlib或ldconfig时,你应该确保系统中存在这些程序并且能正常工作。
DESTDIR
DESTDIR是一个为每个安装目标文件预先准备的变量,如下:
1 | $(INSTALL_PROGRAM) foo $(DESTDIR)$(bindir)/foo |
make通过命令行传入DESTDIR变量,如下:
1 | make DESTDIR=/tmp/stage install |
在安装阶段,安装程序将会将目标文件复制到/tmp/stage/usr/local/bin/foo和/tmp/stage/usr/local/lib/libfoo.a位置,而非/usr/local/bin/foo和/usr/local/lib/libfoo.a。但/usr/local/bin/foo和/usr/local/lib/libfoo.a会成为符号链接,链接到被安装的实际位置。
安装目录相关的变量
安装目录应该总是以变量的形式设置,这样就可以很容易将目标文件安装到非标准目录。关于这些变量的标准名字和值将在下面给出,基于标准文件系统层次。
如下两个变量为设置根目录的变量。
prefix
prefix默认值应是/usr/local。当构建完全的GNU系统时,prefix将为空,/usr也将成为一个指向/的符号链接。
exec_prefix
exec_prefix的默认值为$(prefix)
可执行文件总是被安装到如下目录中。
bindir
默认值是/usr/local/bin,被写成$(exec_prefix)/bin
sbindir
默认值是/usr/local/sbin,被写成$(exec_prefix)/sbin
libexecdir
默认值是/usr/local/libexec,被写成$(exec_prefix)/libexec
所有包的libexecdir都是一样的,因此你应该将你的数据安装到其下的一个子目录,如$(libexecdir)/package-name/machine/version.
如下目录用于指定不同种类的数据应放的位置。
datarootdir
平台无关的只读文件存放位置,通常为/usr/local/share,写成$(prefix)/share
datadir
平台无关的只读文件存放位置,正常为/usr/local/share,写为$(datarootdir)
sysconfdir
系统配置文件目录,/usr/local/etc,写成$(prefix)/etc
sharedstatedir
程序运行时会修改的体系无关目录。/usr/local/com,写成$(prefix)/com
localstatedir
程序运行时会修改,/usr/local/var,写成$(prefix)/var
runstatedir
/var/run,写成$(localstatedir)/run
includedir
头文件目录,/usr/local/include,写成$(prefix)/include
oldincludedir
/usr/include
docdir
文档安装目录,/usr/local/share/doc/yourpkg,写成$(datarootdir)/doc/yourpkg
infodir
信息文件安装目录,/usr/local/share/info,写成$(datarootdir)/info
libdir
库文件目录,/usr/local/lib,写成$(exec_prefix)/lib
srcdir
被编译的s源码文件目录
标准目标
在Makefiles中,通常应该有如下这些目标。
all
编译整个程序
install
编译程序和复制可执行文件、库文件和其它文件到它们的安装位置
```
do-install-info: foo.info installdirs$(NORMAL_INSTALL)
Prefer an info file in . to one in srcdir.
if test -f foo.info; then d=.; \ else d="$(srcdir)"; fi; \ $(INSTALL_DATA) $$d/foo.info \ "$(DESTDIR)$(infodir)/foo.info"
Run install-info only if it exists.
Use ‘if’ instead of just prepending ‘-‘ to the
line so we notice real errors from install-info.
Use ‘$(SHELL) -c’ because some shells do not
fail gracefully when there is an unknown command.
$(POST_INSTALL) if $(SHELL) -c 'install-info --version' \ >/dev/null 2>&1; then \ install-info --dir-file="$(DESTDIR)$(infodir)/dir" \ "$(DESTDIR)$(infodir)/foo.info"; \ else true; fi
```
uninstall
删除安装文件
install-strip
像install,但在安装时会strip可执行文件
```
install-strip:$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ install
```
clean
删除当前目录下的所有文件
dist
为这个程序创建一个用于发布的tar文件
check
自检,在编译后,安装前做检查
installdirs
用于创建安装目录的目标
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 yxhlfx@163.com
文章标题:Makefile Conventions
本文作者:红尘追风
发布时间:2016-11-19, 23:32:46
原始链接:http://www.micernel.com/2016/11/19/MakefileConventions/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。