GNU编码标准引用私有程序接受他人的奉献修改日志(ChangeLogs)与其它实现的兼容性Makefile惯例Makefile的通用惯例Makefile中的工具为用户提供的标准目标为指明命令而提供的变量为安装目录而提供的变量配置是如何进行的使用C以外的语言格式化你的源代码为你的工作写注释清晰地使用C语言成分命名变量和函数使用非标准的特征适用于所有程序的程序行为格式化错误信息库的行为适用于GNU的移植性命令行界面标准为程序制作文档制作发行包GNU编码标准GNU编码标准@author{RichardStallman}@author{lastupdated03Feb1993}Copyright(C)1992,1993FreeSoftwareFoundationPermissionisgrantedtomakeanddistributeverbatimcopiesofthismanualprovidedthecopyrightnoticeandthispermissionnoticearepreservedonallcopies.Permissionisgrantedtocopyanddistributemodifiedversionsofthismanualundertheconditionsforverbatimcopying,providedthattheentireresultingderivedworkisdistributedunderthetermsofapermissionnoticeidenticaltothisone.Permissionisgrantedtocopyanddistributetranslationsofthismanualintoanotherlanguage,undertheaboveconditionsformodifiedversions,exceptthatthispermissionnoticemaybestatedinatranslationapprovedbyFreeSoftwareFoundation.本文由王立翻译.1999.11.9引用私有程序不要在任何情况下,为你在的GNU中的工作或者在工作中引用Unix的源代码(或者任何其它私有程序)。如果你对一个Unix程序内容有一些模糊的记忆,这并不因为着你绝对写程序来模仿它,但请试图在内部使用不同的代码行来组织它,因为这将使你工作的结果在细节上与Unix版本有所不同。例如,Unix工具通常进行了优化以使用最少的内存;如果你更希望提高速度,你的程序将会有很大的不同。你可以在内核中保存整个输入文件并且在内存中扫描而不是使用stdio。使用比Unix程序更新的、更明智的算法。不使用暂时文件。在一遍扫描而不是两遍扫描中完成任务(我在assembler(汇编器)中这样做了)。或者相反,强调简单性而不是速度。对于一些应用程序来说,今天的计算机只要使用简单的算法就够了。或者注重一般性。例如,Unix程序通常使用静态的表格和固定大小的字符串,这导致了不可改变的限制;用动态分配来代替。确认你的程序处理了输入文件为空和其它滑稽的情况。为增加扩展性而增加一种程序语言并且用那种语言完成程序的一个部分。或者把程序的一部分修改成独立的库。或者用一个简单的废物收集器而不是在释放内存的时候精确地进行跟踪,或者使用诸如obstacks这样的新的GNU工具。接受他人的奉献如果其他人发给你一段添加到你正在编写程序中的代码,我们需要准许使用它的法律文书--我们将需要从你那里取得同样的法律文书。程序的每个重要的贡献者都必须签署某种法律文书以使得我们可以给程序一个清晰的标题。仅有主要作者是不够的。所以,在把来自于他人的任何共享添加到程序中之前,告诉我们以便我们可以做出安排以获取文书。在你实际地使用贡献之前,请等待直到我们告诉你我们已经收到了签署的文书。这即适用于你发行程序之前也适用于发行之后。如果你收到了一个修正bug的补丁,并且它们做了主要的修改,我们就需要为他提供法律文书。你不需要为这里或者那里的少数几行修改提供文书,因为对于达到版权目的没有意义。还有,如果你从建议中获得的仅仅是一些想法,而不是你实际上使用的代码,你也不需要文书。例如,如果你写了一个程序的不同解决方案,你并不需要获得许可文书。我知道这是十分麻烦的;它对我们来说也十分麻烦。但如果你不等待,你就可能误入歧途,如果这个贡献者的雇主不肯签署弃权声明怎么办?你可能不得不再次把代码剔除出来!最糟糕的情况是如果你忘记告诉我们其它的贡献者,我们可能会因此而窘迫地出现在法庭上。修改日志(ChangeLogs)为每个目录维护一个修改日志,以记述对这个目录下源文件的修改。这样做的目的是使得在将来寻找bug的人可以指导大致是那些修改导致了错误。通常,一个新的bug可以在最近进行的修改中被找到。更重要的事,修改日志有助于消除程序的不同部分之间在概念上的不一致性;它们可以告诉我们概念冲突产生的历史。使用Emacs命令M-xadd-change在修改日之中创建一个新的条目。一个条目应该包含一个星号、被修改的文件的名称以及被扩在括号内的、被修改了的函数、变量或者任何东西。括号之后是冒号和对你对函数或变量的修改的说明。用空行把无关的条目分隔开。如果两个条目反映了同一个修改,因而它们一同工作,那就不要在它们之间使用空行。如果后续的条目针对的是相同的文件,那么你可以忽略文件名的星号。下面是一些例子:*register.el(insert-register):Returnnil.(jump-to-register):Likewise.*sort.el(sort-subr):Returnnil.*tex-mode.el(tex-bibtex-file,tex-file,tex-region):Restartthetexshellifprocessisgoneorstopped.(tex-shell-running):Newfunction.*expr.c(store_one_arg):Roundsizeupformove_block_to_reg.(expand_call):RoundupwhenemittingUSEinsns.*stmt.c(assign_parms):Roundsizeupformove_block_from_reg.在这里没有必要叙述修改的完整目录和它们是如何协同工作的。把这些说明作为注释放到代码中更好一些。这就是说为什么只要给出“Newfunction”就够了;在源代码中,与函数放在一起的注释说明了它是做什么的。然而,有时为一大堆修改写上一行文字以描述它们的整体目的是有用的。在概念上,你可以把修改日志看作解释原始版本与当前版本的不同的“undo列表”。人们可以阅读当前的版本;他们不需要修改日志告诉他们其中有什么。他们从修改日之中得到的是关于早期版本的不同的清晰解释。在你以简单的方式修改函数的调用顺序,并且你修改了所有对函数的调用时,不必为所有的调用创建单独的条目。只要在被调用的函数的条目中写“Allcallerschanged.”即可。在你仅仅修改了注释或者文档字符串的时候,为该文件写一个条目,而不必提到函数,就足够了。只要写Docfix.。不必为文档文件维护修改日志。这是因为文档不那么容易受到难以修正的错误的影响。文档不是由那些必须以精确地工程方式相互作用的部分组成的;要修改一个错误,你不需要知道这个错误传播的历史。与其它实现的兼容性作为一个特例,对于GNU中的工具程序和库,它们应该和BerkeleyUnix相应的部分向上兼容,如果标准C定义了它们的行为,那它们应该和标准C向上兼容,如果POSIX规范定义了它们的行为,那它们也应该与POSIX规范向上兼容。当这些标准发生冲突的时候,为每个标准提供兼容模式是有用的。标准C和POSIX禁止进行任何形式的扩展。自由地进行你的扩展,并且把选项`--ansi'或`--compatible'包括进来以关闭你的扩展。但是如果扩展很可能导致任何实际程序或者脚本的崩溃,那么它可能实际上不是向上兼容的。尝试一下重新定义它的界面。当一个特征仅仅被用户(而不会被程序或者命令文件)所使用的时候,并且在Unix中它完成得并不好,请自由地用完全不同并且更好的方式代替它。(例如,用Emacs代替vi。)但同时提供兼容模式仍然是很好的。(现在有自由的vi实现,所以我们提供了它。)欢迎提供BerkeleyUnix没有提供的有用功能。Unix中没有的附加功能可能是有用的,但我们优先复制那些Unix已经有的功能。Makefile惯例本章叙述为GNU程序书写Makefile的惯例。Makefile的通用惯例每个Makefile都应该包含这一行:SHELL=/bin/sh以避免那些由从环境中继承SHELL变量的系统带来的麻烦。(GNUmake永远不会出现这个问题。)不要假定`.'出现在用于寻找可执行的命令的路径中。当你需要在make期间运行作为你的包的一部分的程序时,如果程序是作为make的一部分而创建的,请确保它使用了`./',或者如果文件是不会被改变的源代码的一部分,请确保它使用了`$(srcdir)/'。如果运行`configure'时使用了选项`--srcdir',那么`./'与`$(srcdir)/'之间的区别就十分重要。一下形式的规则:foo.1:foo.mansedscriptsed-esedscriptfoo.manfoo.1将在当前目录不是源代码目录的情况下导致错误,这是因为`foo.man'和`sedscript'不在当前目录中。在使用GNUmake的时候,由于不论源文件在那里,`make'的自动变量`$'都将表示它,所以在只存在一个依赖文件的情况下,依靠`VPATH'来寻找源文件仍然是可行的。(许多版本的make只在隐含规则中设置`$'。)如下的makefile目标:foo.o:bar.c$(CC)-I.-I$(srcdir)$(CFLAGS)-cbar.c-ofoo.o将被如下目标所替代:foo.o:bar.c$(CC)$(CFLAGS)$-o$@以便使`VPATH'能够正确地工作。当目标含有多的依赖文件时,显式地使用`$(srcdir)'让规则正常工作的最简单办法。例如,上述为`foo.1'而提供的目标最好被写作:foo.1:foo.mansedscriptsed-s$(srcdir)/sedscript$(srcdir)/foo.manfoo.1Makefile中的工具书写能够在sh,而不是在csh,中运行的Makefile命令(以及任何shell脚本,例如configure)。不要使用任何ksh或者bash特殊的功能。为创建和安装而提供的configure脚本和Makefile规则不要直接使用任何工具,除了以下的几个之外:catcmpcpechoegrepexprgreplnmkdirmvpwdrmrmdirsedtesttouch坚持使用这些程序通常支持的选项。例如,因为许多系统不支持`mkdir-p',尽管它可能有些方便,但不要使用它。为创建和安装而提供的Makefile规则还可以使用编译器和相关的程序,但应该通过make变量以便用户对它们进行替换。下面是一些我们所说的相关的程序:arbisonccflexinstallldlexmakemakeinforanlibtexi2dviyacc在你使用ranlib的时候,你应该测试它是否存在,并且仅仅在它存在的情况下运行它,以使得发布版本在那些没有ranlib的系统中也能够工作。如果你使用了符号连接,你应该为没有符号连接的系统实现一个替代手段。你可以在只打算用于特定系统的Makefile的部分(或者脚本)中使用你能够确认在那些系统上存在的工具。为用户提供的标准目标所有的GNU程序应该在它们的Makefile中含有下列目标:`all'编译整个程序。它应该是缺省目标。这个目标不需要重新创建任何文档文件;Info文