分享
 
 
 

GNU 编码标准 Part 2

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

Makefile惯例

本章叙述为GNU程序书写Makefile的惯例。

Makefile的通用惯例

每个Makefile都应该包含这一行:

SHELL = /bin/sh

以避免那些由从环境中继承SHELL变量的系统带来的麻烦。(GNU make永远不会出现这个

问题。)

不要假定`.'出现在用于寻找可执行的命令的路径中。当你需要在make期间运行作为你的

包的一部分的程序时,如果程序是作为make的一部分而创建的,请确保它使用了`./',

或者如果文件是不会被改变的源代码的一部分,请确保它使用了`$(srcdir)/'。

如果运行`configure'时使用了选项`--srcdir',那么`./'与 `$(srcdir)/'之间的区别

就十分重要。一下形式的规则:

foo.1 : foo.man sedscript

sed -e sedscript foo.man > foo.1

将在当前目录不是源代码目录的情况下导致错误,这是因为`foo.man'和`sedscript' 不

在当前目录中。

在使用GNU make的时候,由于不论源文件在那里,`make'的自动变量`$<' 都将表示它,

所以在只存在一个依赖文件的情况下,依靠`VPATH'来寻找源文件仍然是可行的。(许多

版本的make只在隐含规则中设置`$<'。)如下的makefile目标:

foo.o : bar.c

$(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o

将被如下目标所替代:

foo.o : bar.c

$(CC) $(CFLAGS) $< -o $@

以便使`VPATH'能够正确地工作。当目标含有多的依赖文件时,显式地使用`$(srcdir)'

让规则正常工作的最简单办法。例如,上述为`foo.1'而提供的目标最好被写作:

foo.1 : foo.man sedscript

sed -s $(srcdir)/sedscript $(srcdir)/foo.man > foo.1

Makefile中的工具

书写能够在sh,而不是在csh,中运行的Makefile命令(以及任何shell脚本,例如 con

figure)。不要使用任何ksh或者bash特殊的功能。

为创建和安装而提供的configure脚本和Makefile规则不要直接使用任何工具,除了以下

的几个之外:

cat cmp cp echo egrep expr grep

ln mkdir mv pwd rm rmdir sed test touch

坚持使用这些程序通常支持的选项。例如,因为许多系统不支持`mkdir -p',尽管它可

能有些方便,但不要使用它。

为创建和安装而提供的Makefile规则还可以使用编译器和相关的程序,但应该通过make

变量以便用户对它们进行替换。下面是一些我们所说的相关的程序:

ar bison cc flex install ld lex

make makeinfo ranlib texi2dvi yacc

在你使用ranlib的时候,你应该测试它是否存在,并且仅仅在它存在的情况下运行它,

以使得发布版本在那些没有ranlib的系统中也能够工作。

如果你使用了符号连接,你应该为没有符号连接的系统实现一个替代手段。

你可以在只打算用于特定系统的Makefile的部分(或者脚本)中使用你能够确认在那些

系统上存在的工具。

为用户提供的标准目标

所有的GNU程序应该在它们的Makefile中含有下列目标:

`all'

编译整个程序。它应该是缺省目标。这个目标不需要重新创建任何文档文件;Info文件

被包含在发布版本中,同时,只有在用户明确地要求创建DVI文件的时候才创建DVI文件

`install'

编译程序并且把可执行文件、库文件等文件复制到它们在实际应用中应该存在的位置。

如果存在一个可以检测程序是否被正确地安装了的简单测试,本目标将首先运行这个测

试。

如果文件的安装目录不存在,该命令将创建这样的目录。它们包括由变量prefix和 exe

c_prefix的值指明的目录,以及需要的所有目录。完成该任务的一种方式是按照后面所

说明的方式通过目标installdirs来完成。

在任何用户安装man手册的命令之前使用`-',以使得make忽略所有的错误。错误将在那

些没有安装Unix man手册文档系统的系统中出现。

安装Info文件的方式是用$(INSTALL_DATA)把它们复制到`$(infodir)'中。(参见为指明

命令而提供的变量),并且如果有程序install-info存在,那么就运行它。install-in

fo是一个脚本,它编辑Info `dir'文件以把给定的Info文件添加或者更新目录项的脚本

;它将是Texinfo包的一个部分。下面是用于安装一个Info文件一个简单规则:

$(infodir)/foo.info: foo.info

# There may be a newer info file in . than in srcdir.

-if test -f foo.info; then d=.; \

else d=$(srcdir); fi; \

$(INSTALL_DATA) $$d/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.

# We use `$(SHELL) -c' because some shells do not

# fail gracefully when there is an unknown command.

if $(SHELL) -c 'install-info --version' \

>/dev/null 2>&1; then \

install-info --infodir=$(infodir) $$d/foo.info; \

else true; fi

`uninstall'

删除所有由`install'目标创建的所有安装的文件(但不包括那些由诸如`make all' 之

类的目标创建的,没有被安装的文件)。

`clean'

从当前目录中删除所有在创建程序过程中创建的文件。不要删除那些纪录配置情况的文

件。有些文件可能是在创建过程中创建的,但因为它们是和发布版本一起发布的,通常

不是在创建过程中创建的,这样的文件也需要保留下来。

如果`.dvi'文件不是发布版本的一部分,就删除它们。

`distclean'

从当前目录中删除所有在程序的配置和创建过程中创建的文件。如果你解包源代码并且

在没有添加任何其它文件的情况下创建程序,`make distclean'将仅仅保留那些出现在

发布版本中的文件。

`mostlyclean'

类似于`clean',可能不会删除少数人们通常不希望重新编译的文件。例如,GCC的 `mo

stlyclean'目标不会删除`libgcc.a',这是因为很少需要重新编译并且重新编译将花费

大量的时间。

`realclean'

从当前目录中删除所有可以由Makefile重新创建的文件。这通常包括所有由distclean删

除的文件,以及:由Bison生成的C源文件、标记表(tags tables)、Info文件等等。

然而有一个例外:即使`configure'可以通过使用Makefile中的规则重新创建,`make r

ealclean' 也不会删除`configure'。更一般地说,`make realclean'将不会删除为了运

行`configure' 而存在的任何东西,并且随后开始创建程序。

`TAGS'

为本程序更新标记表(tags table)。

`info'

生成所有需要的Info文件。书写该规则的最佳方式是:

info: foo.info

foo.info: foo.texi chap1.texi chap2.texi

$(MAKEINFO) $(srcdir)/foo.texi

你必须在Makefile中定义变量MAKEINFO。它应该运行程序makeinfo,该程序是Texinfo发

布版本的一部分。

`dvi'

Generate DVI files for all TeXinfo documentation. For example:

dvi: foo.dvi

foo.dvi: foo.texi chap1.texi chap2.texi

$(TEXI2DVI) $(srcdir)/foo.texi

你必须在Makefile中定义变量TEXI2DVI。它应该运行程序texi2dvi,该程序也是Texinf

o 发布版本的一部分。作为另一个选择,只要写依赖文件并且允许GNU Make提供这个命

令就行了。

`dist'

为本程序创建一个发布版本tar文件。该tar文件将被设置以使得在tar文件中的文件名以

子目录名开头,这个子目录名是包用于发布的名字。这个名字可以包含版本号。

例如,GCC版本1.40的发布tar文件将被解包到名为`gcc-1.40'的子目录中。

完成该任务的最简单方式是以适当的名称创建一个子目录,使用ln或者cp把正确的文件

安装到该目录中,而后tar这个子目录。

目标dist应该显式地依赖于发布版本中所有的非源文件,以确保它们在发布版本中都不

是过时的。参见 制作发布包

`check'

(如果有的话)执行自检测。用户必须在运行测试之前,但不必在安装程序之前创建程

序;你应该写下自检测以便它们在程序创建之后而没有被安装之前进行工作。

对于那些适用于以下的目标的程序,建议你按照常用的名字提供它们。

installcheck

(如果有的话)执行安装监测。用户必须在运行该检测之前创建并且安装程序。你不应

该假定`$(bindir)' 出现在搜索路径中。

installdirs

添加一个名为`installdirs'的目标,以便创建安装文件的目录和它们的父目录。有一个

称为`mkinstalldirs'的脚本可以为此提供便利;在Texinfo包中可以找到它。你可以使

用象下面那样的规则:

# Make sure all installation directories (e.g. $(bindir))

# actually exist by making them if necessary.

installdirs: mkinstalldirs

$(srcdir)/mkinstalldirs $(bindir) $(datadir) \

$(libdir) $(infodir) \

$(mandir)

为指明命令而提供的变量

Makefile应该提供变量以覆盖某些命令、选项等等。

特别地,你应该通过变量来运行大部分工具程序。因此,如果你使用了Bison,就定义一

个缺省值是通过`BISON = bison' 来设定的变量BISON,并且在你需要使用Bison的所有

地方通过$(BISON)引用它。

在这种方式下,文件管理工具:ln、rm、mv等等并不需要通过变量引用,这是因为用户

不需要用其它程序来替代它们。

每个程序名变量都应该有一个对应的变量以便为程序提供选项。把`FLAGS'附加到程序名

变量名的后面就是选项变量名--例如,BISONFLAGS。(名字CFLAGS是这项规则的一个例

外,但因为它是标准的而保留了它。)在任何运行预处理器的编译命令中使用CPPFLAGS

,在任何进行连接的编译命令和任何对ld的直接使用中使用LDFLAGS。

如果存在一些为了正确地编译某些文件而必须使用的C编译器选项,不要把它们包括在C

FLAGS中。用户希望能够自由地指明CFLAGS的值。替代的方式是:通过在编译命令行中显

式地给出这些必要的选项或者通过定义一条隐含规则,从而以独立于CFLAGS的方式把选

项传递给C编译器。

CFLAGS = -g

ALL_CFLAGS = -I. $(CFLAGS)

.c.o:

$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<

把选项`-g'包括在CFLAGS中,因为它对于正确的编译来说并不是必要的。你可以认为它

仅仅是关于缺省值的一个建议。如果包被设置成在缺省的状态下由GCC编译,那么你可能

还需要把`-O' 包括在CFLAGS的缺省值之中。

把CFLAGS放在编译命令行的最后,就是在其它包含了编译选项的变量之后,以便于用户

使用CFLAGS 来覆盖其它的选项。

每个Makefile都应该定义变量INSTALL,它是把一个文件安装到系统中的基本命令。

每个Makefile还应该定义变量INSTALL_PROGRAM和INSTALL_DATA。(两者的缺省值都应该

是 $(INSTALL)。)而后,Makefile应该使用这些变量作为实际安装的命令,分别用于安

装可执行文件和不可执行的文件。按照下面的方式使用这些变量:

$(INSTALL_PROGRAM) foo $(bindir)/foo

$(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a

总是把文件名,而不是目录名,作为安装命令的第二个参数。为每个需要安装的文件使

用独立的命令。

为安装目录而提供的变量

安装目录总是应该通过变量来命名,以易于把包安装在其它非标准的位置。这些变量的

标准名字是:

`prefix'

用于构造下列变量的缺省值的前缀。prefix的缺省值应该是`/usr/local'(至少现在是

它)。

`exec_prefix'

用于构造下列某些变量的缺省值的前缀。exec_prefix的缺省值应该是$(prefix)。

一般来说,$(exec_prefix)指的是用于储存与机器有关的文件(比如说可执行文件和子

程序库)的目录,而$(prefix)则被直接用于其它目录。

`bindir'

用于储存用户可以运行的可执行程序的目录。一般来说应该是`/usr/local/bin',但应

该被写作 `$(exec_prefix)/bin'。

`libdir'

用于安装由程序运行,而不是由用户运行的可执行文件的目录。Object文件和object代

码库也应该被储存在这个目录。提供该目录的意图是为了储存适用于特殊机器结构,但

又不必出现在命令路径中的文件。libdir的值通常是 `/usr/local/lib',但应该被写作

`$(exec_prefix)/lib'。

`datadir'

用于安装程序在运行时需要访问的只读数据文件的目录。该目录用于储存与使用的机器

独立的文件。它通常是 `/usr/local/lib',但应该被写作`$(prefix)/lib'。

`statedir'

用于安装程序在运行时需要修改的数据文件的目录。这些文件应该与使用的机器类型独

立,并且应该可以在网络安装的情况下载不同的机器之间共享。它通常应该是`/usr/lo

cal/lib',但应该被写作`$(prefix)/lib'。

`includedir'

用于储存将被用户程序以C预处理指令`#include'引入的头文件的目录。它通常应该是

`/usr/local/include',但应该被写作`$(prefix)/include'。

除了GCC以外,大部分编译器并不在`/usr/local/include'中寻找头文件。所以以这种方

式安装头文件仅仅适用于GCC。但有些库被设计成与其它编译器共同工作。它们应该在两

个地方安装它们的头文件,一个由includedir 给出,另一个由oldincludedir给出。

`oldincludedir'

为除了GCC之外的其它编译器安装头文件的目录。这通常应该是`/usr/include'。

Makefile命令应该检测oldincludedir的值是否为空。如果为空,Makefile命令就不应该

试图使用 oldincludedir;Makefile命令应该放弃对头文件的第二个安装。

除非头文件来自于同一个包,包不应该替换已经存在的头文件。因此,如果你的Foo包提

供了一个头文件`foo.h',并且如果它没有出现在oldincludedir目录中或者oldinclude

dir目录中的`foo.h'也是来自与Foo包,那么Foo包就应该把头文件安装到oldincludedi

r中。

为了判定`foo.h'是否来自于Foo包,可把一个特殊的字符串作为注释的一部分放在文件

中,而后用grep搜索这个字符串。

`mandir'

(如果存在)本包安装man手册的目录。它应该包含对应于正确的手册部分的后缀-- 对

于一个工具来说通常是`1'。它一般是`/usr/local/man/man1',但你应该把它写成:`$

(prefix)/man/man1'。

`man1dir'

安装man手册第一部分的目录。

`man2dir'

安装man手册第二部分的目录。

`...'

如果包需要把man手册安装到手册系统的多个部分,就用这些名字来代替`mandir'。

不要把man手册作为GNU软件的主要文档。用Texinfo书写文档来代替它。Man手册只是因

为人们在Unix,它只是一个次要的应用程序,上运行GNU软件才存在的。

`manext'

作为需要安装的man手册的文件的扩展名。它应该是一个点加上一个适当的数字;通常它

应该是:`.1'。

`man1ext'

将被安装到man手册第一部分的文件的扩展名。

`man2ext'

将被安装到man手册第二部分的文件的扩展名。

`...'

如果包需要把man手册安装到手册系统的多个部分,就用这些名字代替`manext'。

`infodir'

为本包安装Info文件的目录。在缺省状态下,它应该是`/usr/local/info',当它应该被

写成 `$(prefix)/info'。

`srcdir'

用于编译源代码的目录。该变量的值通常是由configureshell脚本插入的。

例如:

# Common prefix for installation directories.

# NOTE: This directory must exist when you start the install.

prefix = /usr/local

exec_prefix = $(prefix)

# Where to put the executable for the command `gcc'.

bindir = $(exec_prefix)/bin

# Where to put the directories used by the compiler.

libdir = $(exec_prefix)/lib

# Where to put the Info files.

infodir = $(prefix)/info

如果你的程序在一个标准的用户给定的目录中安装了大量的文件,可能把为程序特别提

供的文件存放到子目录中会有用一些。如果你这样做了,你应该改写install规则以创建

这些子目录。

不要指望用户会把子目录名包括在上面列出的变量的值中。为安装目录提供统一的变量

名集合的意图是使得用户可以为一些不同的GNU包指明完全相同的值。为了使这些规定变

得有用,所有的包都必须这样设计以便在用户这样做的时候它们将能够有效地工作。

配置是如何进行的

每个GNU发布版本都应该还有一个名为configure的shell脚本。你需要把你希望在那种机

器和系统上编译程序作为参数告诉这个脚本。

脚本configure必须记录配置信息以便它们可以影响编译工作。

这样做的一种方式是把一个诸如`config.h'的标准名字和为选定的系统匹配的正确配置

文件连接起来。如果你使用了这种技术,发布版本中就不应该包含名为

[1] [2] 下一页

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有