Author:Onceday Date: 2023年12月26日
漫漫长路,才刚刚开始…
本文主要翻译自《GNU编码标准》(GNU Coding Standards)一文。
参考文档:
《GNU编码标准》(GNU Coding Standards)是由GNU项目制定的一系列详细的编码准则和最佳实践。这些标准旨在确保GNU软件的质量和维护性,并且为开发者提供一致的编程风格和实践。GNU编码标准的内容不仅仅局限于代码风格,还包括软件设计、文档、版权和其他开发实践。以下是主要的章节和它们的内容大纲:
all
, install
, clean
等。configure
脚本的作用,它是自动配置源代码包以适应不同系统的工具。除了上述章节,GNU编码标准还可能包括附录和其他相关的信息,旨在帮助开发者更好地理解和实施这些标准。遵循这些标准有助于确保GNU软件的质量,同时促进开源社区成员之间的协作。
(1) 不要引用专有程序,在任何情况下都不要在GNU工作中引用Unix源代码或任何其他专有程序!如果对Unix程序的内部结构有一个模糊的记忆,那么可以按照不同的实现方式和需求进行重新组织,确保Unix版本的细节与新代码无关且不相似。
(2) 接收贡献代码,如果正在开发的程序受自由软件基金会的版权保护,那么当其他人发送给一段代码以添加到程序中时,我们需要法律文件来使用它:就像我们最初要求开发人员签署文件一样。每个对程序做出重要贡献的人都必须签署某种法律文件,以便我们对程序有明确的所有权,只有主要作者是不够的。不过,不需要为这里或那里的几行代码更改提供法律文件,这种情况下可以忽略。
(3) 商标使用,请不要在GNU软件包或文档中包含任何商标标记,商标标记是关于某商标的声明。GNU项目无意去使用商标,法律也要求对于其他已存在的商标,要避免使读者误认为我们程序和商标之间存在关联。
例如,由于Objective C
是(或至少曾经是)一个商标,因此我们表述为Objective C语言的编译器
而不是Objective C编译器
。后者可能是前者的一种较短的表达方式,但可能被误解为Objective C
商标下面的编译器,相比之下Objective C语言的编译器
则是描述了一种语言的编译器,和“Objective C
”商标无关。
此外,也不要在GNU软件或文档中使用win
作为Microsoft Windows
的缩写。在黑客术语中,称某事为win
是一种赞扬。如果您愿意的话,您可以自由地赞美Microsoft Windows
,但是请不要在GNU软件包中这样做。请把Windows
全写,或者缩写成w.
。
当你想使用一种可以快速编译和运行的语言时,最好的语言是C
。C++
也可以,但请不要大量使用模板。如果你编译Java,它也是如此。当不需要最高效率时,自由软件社区中常用的其他语言,如Lisp
、Scheme
、Python
、Ruby
和Java
,也可以。
由GNU Guile
实现的Scheme
在GNU系统中扮演着特殊的角色:它是扩展用C/C++
编写的程序的首选语言,也是一种适用于广泛应用程序的优秀语言。越多的GNU
组件使用Guile
和Scheme
,就有越多的用户能够扩展和组合它们(参见GNU Guile
参考手册中的“Emacs原理”部分)。
许多程序被设计成可扩展的:它们包括一个比C语言更高级别的解释器。通常很多程序也是用这种语言编写的。Emacs编辑器开创了这种技术。GNU软件的标准可扩展性解释器是Guile (https://www.gnu.org/software/guile/)
,它实现了Scheme语言(一种特别干净和简单的Lisp方言)。Guile
还包括GTK+/GNOME
的绑定,使得在Guile中编写现代GUI功能变得实用。我们并不排斥用其他“脚本语言”(如Perl和Python
)编写的程序,但是使用Guile是实现GNU系统整体一致性的途径。
除了偶尔的例外,GNU的实用程序和库应该满足以下兼容性:
当这些标准发生冲突时,为每个标准提供兼容模式是很有用的。标准C和POSIX禁止许多类型的扩展。无论如何,您可以自由地制作扩展,并包含--ansi
,--posix
或--compatible
选项来关闭它们。
然而,如果扩展有很大的机会破坏任何实际的程序或脚本,那么它就不是真正的向上兼容。因此,您应该尝试重新设计它的界面,使其向上兼容。如果定义了环境变量POSIXLY_CORRECT
(即使它是用空值定义的),许多GNU程序会抑制与POSIX冲突的扩展。如果合适的话,请让你的程序识别这个变量。
当一个特性只由用户使用(而不是由程序或命令文件使用),并且在Unix中做得很差时,可以自由地用完全不同的、更好的东西完全替换它(例如,将vi
替换为Emacs
)。但是提供一个兼容的功能也是不错的(有一个免费的vi
克隆,所以我们提供它)。
附加的有用功能是受欢迎的,无论是否有先例。
许多已经存在的GNU工具支持许多比对应Unix工具更方便的扩展。在实现程序时是否使用这些扩展是一个困难的选择。
一方面,使用扩展可以使程序更简洁。另一方面,除非其他GNU工具可用,否则人们将无法构建程序。
这可能会导致程序在更少种类的机器上工作。对于某些扩展,可能很容易同时提供这两种选择。例如,您可以使用“关键字”INLINE
定义函数,并将其定义为宏,以扩展为内联或不内联,具体取决于编译器。
一般来说,如果您可以直接不使用扩展,那么最好不要使用它们,但如果它们能带来一个较大的改进,则使用它们。
这条规则的一个例外是运行在各种系统上的大型、已建立的程序(如Emacs)。在这样的程序中使用GNU扩展会使许多用户不高兴,所以我们不这样做。
另一个例外是作为编译组成部分使用的程序:任何必须用其他编译器编译才能进一步引导GNU编译工具的程序。如果它们需要GNU编译器,那么没有人可以在没有安装它们的情况下编译它们。这在某些情况下会非常麻烦。
“Pre-standard C”指的是在ANSI C标准建立之前存在的C语言版本。C语言的第一个标准化版本被称作ANSI C,或者是C89/C90,因为它分别在1989年和1990年被美国国家标准化组织(ANSI)和国际标准化组织(ISO)批准。所以,“pre-standard C”指的是1989年之前的C语言,通常基于丹尼斯·里奇(Dennis Ritchie)在1970年代初在贝尔实验室(AT&T Bell Labs)开发的原始版本。
1989年,标准C语言已经普及到可以在程序中使用它的特性。有一个例外: 永远不要使用标准C的“三元表达式”特性。
并不是所有平台都完全支持1999和2011版的标准C。如果您的目标是支持GCC以外编译器的编译,则不应该要求这些C语言特性。当编译器支持这些特性时,可以有条件地使用它们。如果您的程序只打算用GCC进行编译,那么如果GCC支持这些特性,当它们提供实质性的好处时,您就可以使用这些特性。
然而,在大多数程序中支持前标准C编译器是很容易的,所以如果您知道如何做到这一点,请放心。为了支持前标准C:
int int
foo (int x, int y) ==> foo (x, y)
... int x,y;
将标准原型中编写的函数定义将定义写成右边这样的前标准格式,并且配备如下的原型:
int foo (int, int);
无论如何,在头文件中都需要这样的声明,以便在调用函数的所有文件中获得原型的好处。一旦你有了声明,你通常不会因为用前标准C的风格来写函数定义而有任何损失。
此技术不适用于比int
更小的整数类型。如果您认为参数的类型比int
更窄,则将其声明为int
。在一些特殊情况下,这种技术很难使用。例如,如果一个函数参数需要保存系统类型dev_t
,你就会遇到麻烦,因为dev_t
在某些机器上比int
短;但是你不能用int
代替,因为在某些机器上dev_t
比int
更宽。
在非标准定义中,没有一种类型可以安全地在所有机器上使用。支持非标准C并传递这样一个参数的唯一方法是使用Autoconf
检查dev_t
的宽度并相应地选择参数类型。这可能不值得这么麻烦。
为了支持不识别原型的前标准编译器,您可能需要使用像这样的预处理器宏:
/* Declare the prototype for a general external function. */
#if defined (__STDC__) || defined (WINDOWSNT)
#define P_(proto) proto
#else
#define P_(proto) ()
#endif
当支持在构建程序时已经知道的配置选项时,我们更喜欢使用if(…)
而不是条件编译,因为在前一种情况下,编译器能够对所有可能的代码路径执行更广泛的检查。
比如下面的两个例子(倾向于使用左边的例子):
if (HAS_FOO) #ifdef HAS_FOO
... ...
else <=== #else
... ...
像GCC这样的现代编译器将在这两种情况下生成完全相同的代码,我们已经在几个项目中使用了类似的技术,并取得了很好的成功。当然,前一种方法假设HAS_F00
被定义为0
或1
。虽然这不是解决所有可移植性问题的灵丹妙药,也不总是合适的,但是遵循这个策略可以为GCC开发人员每年节省许多时间,甚至几天。
对于像GCC中的REVERSIBLE_CC_MODE
这样的类函数宏,不能简单地在if(…)
语句中使用,有一个简单的解决方法。只需引入另一个宏HAS_REVERSIBLE_CC_MODE
,如下例所示:
#ifdef REVERSIBLE_CC_MODE
#define HAS_REVERSIBLE_CC_MODE 1
#else
#define HAS_REVERSIBLE_CC_MODE 0
#endif
本章描述编写健壮软件的约定。它还描述了错误消息的一般标准、命令行接口以及库应该如何表现。
GNU工程将其他组织发布的标准视为建议,而不是命令。我们考虑这些标准,但我们并不“服从”它们。在开发一个GNU程序时,当客观地说使GNU系统整体更好时,您应该实现外部标准的规范。当它没有,你不应该。在大多数情况下,遵循已发布的标准对用户来说是方便的——这意味着他们的程序或脚本将更易于移植。
例如,GCC实现了标准C中指定的几乎所有的特性。如果它不这样做,C程序开发人员会不高兴的。GNU实用程序大多遵循POSIX.2
的规范,如果我们的程序不兼容,Shell
脚本编写者和用户会不高兴。但是我们并没有严格地遵循这两个规范,并且在某些特定的点上我们决定不遵循它们,以便为用户提供更好的GNU系统。
例如,标准C说几乎所有C的扩展都是被禁止的。多么的愚蠢!GCC实现了许多扩展,其中一些扩展后来被采纳为标准的一部分。如果您希望这些结构按照标准的“要求”给出错误消息,您必须指定--pedantic
,实现它只是为了我们可以说“GCC是标准的100%实现”,而不是因为实际上有任何理由使用它。
POSIX.2
指定df
和du
在默认情况下必须以512字节为单位输出大小。用户想要的是1k的单位,这就是我们默认做的。如果您想要POSIX“要求”的荒谬行为,则必须设置环境变量POSIXLY_CORRECT
(最初将其命名为POSIX_ME_HARDER
)。
当GNU实用程序支持长命名的命令行选项以及将选项与普通参数混合在一起时,它们也偏离了POSIX.2
规范。这个与POSIX
的小不兼容性在实践中从来都不是问题,而且非常有用。
特别是,不要仅仅因为一个标准说它是“禁止的”或“弃用的”就拒绝一个新特性或删除一个旧特性。
通过动态分配所有数据结构,避免对任何数据结构(包括文件名、行、文件和符号)的长度或数量进行任意限制。在大多数Unix实用程序中,“长行被静默截断”。这在GNU实用程序中是不可接受的。
读取文件的实用程序不应该删除NUL
字符或任何其他非打印字符。程序应该在多字节字符编码下正常工作,比如UTF-8。您可以使用libiconv
来处理一系列编码。检查每个系统调用是否有错误返回,除非您知道希望忽略错误。
在失败的系统调用所导致的每个错误消息中包含系统错误文本(来自strerror
或同等内容),以及文件的名称(如果有的话)和实用程序的名称。仅仅“无法打开foo.c
”或“启动失败”是不够的。
检查对malloc
或realloc
的每次调用,看看它是否返回NULL
。检查realloc
,即使你要把块变小,在一个块大小四舍五入到2幂次方的系统中,如果你要求更少的空间,realloc可能会得到一个不同的块。必须预料到free会改变被释放的块的内容。你想从block中获取的任何东西,都必须在调用free之前获取。
如果malloc在非交互式程序中失败,则将其设置为致命错误。在交互式程序(从用户那里读取命令的程序)中,最好中止命令并返回到命令读取器循环。这允许用户杀死其他进程以释放虚拟内存,然后再尝试执行该命令。
使用getopt_long
来解码参数,除非参数语法不合理。
如果要在程序执行期间写入静态存储,请使用显式的C代码对其进行初始化。这样,重新启动程序(不重新加载它),或它的一部分,将重新初始化这些变量。为不会改变的数据保留C初始化声明。
尽量避免使用低级接口来模糊Unix数据结构(如文件目录、utmp
或内核内存的布局),因为这些接口不太可能兼容。如果需要查找目录中的所有文件,请使用readdir
或其他高级接口。这些都被GNU兼容地支持。
首选的信号处理工具是BSD信号的变体,以及POSIX sigaction
函数,另外一个USG signal
接口是一个较差的设计。
如今,使用POSIX信号函数可能是使程序可移植的最简单方法。如果您使用signal
,那么在运行GNU libc version 1
的GNU/Linux
系统上,您应该包含bsd/signal.h
而不是signal.h
,以便获得bsd
行为。这取决于你是否支持信号只有USG
行为的系统,或者放弃它们。
在检测“不可能”情况的错误检查中,只要中止即可。通常没有必要打印任何消息。这些检查表明存在错误。任何想要修复错误的人都必须阅读源代码并运行调试器。所以用源代码中的注释来解释这个问题。相关数据将在变量中,这些变量很容易用调试器检查,因此没有必要将它们移到其他地方。
不要使用错误计数作为程序的退出状态。这不起作用,因为退出状态值被限制为8位(0到255)。单次运行程序可能有256个错误,如果您尝试返回256作为退出状态,父进程将看到0作为状态,并且看起来程序成功了。
如果您创建临时文件,请检查TMPDIR
环境变量,如果定义了该变量,则使用指定的目录而不是/tmp
。此外,请注意,在全局可写目录中创建临时文件时可能存在安全问题。在C语言中,你可以通过这样创建临时文件来避免这个问题:
fd = open (filename, O_WRONLY | O_CREAT | O_EXCL, 0600);
或者使用Gnulib
中的mkstemps
函数(参见Gnulib
中的mkstemps
一节)。在bash
中,使用set -C
(长名称noclobber
)来避免这个问题,可以防止已存在的文件被重定向操作覆盖。启用这个选项后,如果你尝试用重定向操作符 >
去覆盖一个已经存在的文件,Bash将会阻止这个操作并显示一个错误信息。
此外,mktemp
实用程序是从shell
脚本创建临时文件的更通用的解决方案。
尝试使库函数可重入。如果他们需要做动态存储分配,至少要尽量避免除malloc本身之外的任何不可重入性。
这里有一些库的名称约定,以避免名称冲突。
选择库的名称前缀,长度大于两个字符。所有外部函数和变量名都应该以这个前缀开头。此外,在任何给定的库成员中应该只有一个,这通常意味着将每个外部符号和变量放在单独的源文件中。
当两个外部符号总是一起使用时,可以产生一个例外,因为没有一个合理的程序可以使用其中一个而不使用另一个,所以它们可以放在同一个文件中。
未记录的用户入口点外部符号的名称应该以_
开头。_
后面应该跟所选库的名称前缀,以防止与其他库冲突。如果您愿意,可以将这些外部符号与用户入口点放在相同的文件中。
静态函数和变量可以随意使用,不需要符合任何命名约定。
来自编译器的错误信息应该是这样的:
sourcefile:lineno: message
如果你想提到列号,使用以下格式之一:
sourcefile:lineno:column: message
sourcefile:lineno.column: message
行号应该从文件开头的1开始,列号应该从行开头的1开始,选择这两种约定是为了兼容性。假设空格和所有ASCII打印字符的宽度相等,并假设制表符每8列停止一次,计算列数。对于非ascii
字符,在UTF-8
语言环境中应使用Unicode
字符宽度,GNU libc
和GNU gnulib
提供了合适的wcwidth
函数。
错误消息还可以给出错误文本的起始和结束位置。有几种格式可以避免冗余信息,例如重复的行号。以下是可能的格式:
sourcefile:line1.column1-line2.column2: message
sourcefile:line1.column1-column2: message
sourcefile:line1-line2: message
当错误分布在多个文件时,您可以使用以下格式:
file1:line1.column1-file2:line2.column2: message
来自其他非交互式程序的错误消息应该是这样的(有合适的源文件时):
program:sourcefile:lineno: message
或者像这样(没有相关的源文件时):
program: message
如果你想提到列号,使用这种格式:
program:sourcefile:lineno:column: message
在交互式程序(从终端读取命令的程序)中,最好不要在错误消息中包含程序名。指示哪个程序正在运行的地方是在提示符中或在屏幕布局中。当同一程序使用来自终端以外源的输入运行时,它不是交互式的,最好使用非交互式样式打印错误消息。
当字符串消息跟在程序名和/
或文件名后面时,不应该以大写字母开头,因为那不是句子的开头。从概念上讲,句子从一行的开头开始。此外,它不应该以句号结束。
来自交互式程序的错误消息和其他消息(如用法消息)应该以大写字母开头。但它们不应该以句号结束。
请不要让实用程序的行为依赖于调用它时使用的名称。有时使用不同的名称创建到实用程序的链接是有用的,并且不应该改变它的功能。因此,如果您将foo链接到ls,那么无论使用哪个名称来调用它,程序的行为都应该相同。
相反,应该使用运行时选项或编译开关,或者两者都使用,以在可选行为中进行选择。您还可以构建具有不同默认行为的程序的两个版本,并以两个不同的名称安装它们。
同样,请不要让命令行程序的行为取决于它作为标准输出或标准输入获得的输出设备的类型。设备独立是系统设计的一个重要原则;不要仅仅为了避免别人时不时地输入一个选项而牺牲它(使用终端时错误消息语法的变化是可以的,因为这是人们不依赖的附带问题)。
如果您认为一种行为在输出到终端时最有用,而另一种行为在输出到文件或管道时最有用,那么通常最好将默认行为设置为对输出到终端有用的行为,并为另一种行为提供选项。您还可以用不同的名称构建程序的两个不同版本。
在某些情况下输出二进制数据的程序有一个例外。将这样的输出发送到终端是无用的,而且会引起麻烦。如果这样的程序通常将其输出发送到标准输出,那么在这种情况下,它应该检测输出是否为终端,并给出错误消息。-f
选项应该覆盖这个异常,从而允许输出到终端。
兼容性要求某些程序依赖于输出设备的类型。如果ls
或sh
不能以所有用户期望的方式这样做,那将是灾难性的。在某些情况下,我们使用不依赖于输出设备类型的首选替代版本来补充程序。例如,我们提供了一个与ls
非常相似的dir
程序,只是它的默认输出格式始终是多列格式。
程序可能需要找到启动时使用的可执行文件,以便重新启动相同的程序。它可能需要查找在运行时使用的相关文件,无论是源文件还是通过构建构造的文件。
找到它们的方法从argv[0]开始。
如果该字符串包含斜杠,则按照惯例,它是可执行文件的文件名,其目录部分是包含可执行文件的目录。当没有通过PATH
找到程序时,就会出现这种情况,这通常意味着它是构建的,但没有安装,并从构建目录运行。程序可以使用argv[0]
文件名重新启动自己,并可以在其目录部分查找相关文件。如果该文件名不是绝对的,那么它是相对于程序启动的工作目录的。
如果argv[0]
不包含斜杠,则它是通过PATH找到的可执行文件的命令名。程序应该在PATH的目录中搜索该名称,解释.
作为程序启动时的当前工作目录。
如果这个过程找到了可执行文件,我们调用在调用目录中找到的目录。程序应该检查该目录中是否存在它需要的相关文件。
如果程序的可执行文件通常是在主构建目录的子目录中构建的,并且主构建目录包含关联文件(可能包括子目录),则程序应该查看调用目录的父目录,检查主构建目录应该包含的关联文件和子目录。
如果调用目录不包含所需的内容,但可执行文件名是符号链接,则程序应尝试使用链接目标的包含目录作为调用目录。
如果这个过程没有找到一个有效的调用目录(通常是通过path找到的已安装程序的情况),那么程序应该在程序的makefile安装它们的目录中查找相关文件。
在argv[0]
中提供有效信息是一种约定,不能保证。运行其他程序(如shell
)的行为良好程序会遵循惯例,在启动其他程序时,您的代码也应该遵循它。但是,总是有可能启动程序会在argv[0]
中给出一个无意义的值。
因此,任何需要知道其可执行文件或其他相关文件的位置的程序,都应该提供用户环境变量来显式地指定这些位置。
不要给那些以启发式方式搜索相关文件或以这种方式调用它们自己的可执行文件的程序以特权,比如setuid
位。将该特权限制为在硬编码安装位置(如/usr
和/etc
)下查找相关文件的程序。
当您编写提供图形用户界面的程序时,请使用GTK+
工具包或GNUstep
工具包使其与X
窗口系统一起工作,除非该功能特别需要一些替代方案(例如,“在控制台模式下显示jpeg图像”)。
另外,请提供一个命令行接口来控制该功能。在许多情况下,图形用户界面可以是调用命令行程序的单独程序,这样就可以通过脚本完成相同的工作。
也请考虑提供一个D-bus
接口,供其他正在运行的程序使用,比如在GNOME
中。GNOME
过去使用CORBA
来实现这一点,但这正在逐步淘汰。此外,考虑提供一个库接口(供C语言使用),或者提供一个键盘驱动的控制台接口(供用户从控制台模式使用)。
一旦您开始提供功能和图形界面,就不会有太多额外的工作。
请使您的程序与屏幕阅读器等访问技术互操作(参见https://www.gnu.org/accessibility/accessibility.html
)。如果使用GTK+,这应该是自动的。
对于程序的命令行选项,遵循POSIX
指南是一个好主意。最简单的方法是使用getopt
来解析它们。请注意,GNU版本的getopt
通常允许在参数中的任何位置使用选项,除非使用了特殊参数--
。这不是POSIX
所指定的,它是一个GNU
扩展。
请定义长命名的选项,这些选项等价于单字母unix
风格的选项。我们希望通过这种方式使GNU更加用户友好,使用GNU函数getopt_long
很容易做到这一点。
长命名选项的优点之一是它们可以在程序之间保持一致。例如,用户应该能够期望任何具有verbose
选项的GNU程序的“verbose”选项被精确地拼写为--verbose
。为了达到这种一致性,当你为你的程序选择选项名称时,请查看常见的长选项名称表(原文4.10章)。
作为普通参数给出的文件名只作为输入文件通常是个好主意,任何输出文件都可以使用选项来指定(最好是-o
或--output
)。即使您允许将输出文件名作为兼容性的普通参数,也要尝试提供一个选项作为指定它的另一种方式。这将导致GNU实用程序之间有更多的一致性,并减少用户需要记住的特性。
所有程序都应该支持两个标准选项:--version
和--help
。CGI程序应该接受这些命令行选项,如果作为PATH_INFO
,例如,在浏览器中访问http://example.org/p.cgi/--help
应该输出与从命令行调用p.cgi --help
相同的信息。
(1) --version
版本信息。--version
选项应该指示程序在标准输出中打印有关其名称、版本、来源和合法状态的信息,然后成功退出。其他选项和参数应该被忽略,一旦看到它,程序不应该执行其正常功能。
第一行是为了让程序容易解析,版本号从最后一个空格后开始。此外,它还包含该程序的规范名称,格式如下:
GNU Emacs 19.30
程序的名称应该是一个常量字符串,不要从argv[0]
计算它。其思想是声明程序的标准或规范名称,而不是其文件名。还有其他方法可以查找在PATH中找到命令的精确文件名。
如果程序是一个较大包的附属部分,则在括号中提到包的名称,如下所示:
emacsserver (GNU Emacs) 19.30
如果包的版本号与程序的版本号不同,可以在右括号之前提到包的版本号。
如果您需要提及与包含此程序的包分开分发的库的版本号,您可以通过为每个您想要提及的库打印额外的版本信息行来实现。对这些行使用与第一行相同的格式。
请不要“仅仅为了完整性”而提及程序使用的所有库——那会产生很多无益的混乱。只有当您在实践中发现库版本号对调试非常重要时,才请提及库版本号。
在版本号后面的一行或几行,应该是一个版权声明。如果需要多个版权声明,请将每个声明放在单独的一行。
接下来的一行应该说明许可证,最好使用下面的缩写之一,并简要说明该程序是自由软件,并且用户可以自由地复制和更改它。还要提到的是,没有保证,在法律允许的范围内。请参阅下面推荐的措辞。
在输出的最后加上程序主要作者的列表是可以的,这是一种给予荣誉的方式。
下面是一个遵循这些规则的输出示例:
GNU hello 2.3
Copyright (C) 2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
当然,您应该根据您的程序修改它,填写适当的年份、版权所有者、程序名称和对发布条款的引用,并根据需要更改其余的措辞。
这个版权声明只需要提到最近的修改年份,而不需要列出以前版本的修改年份。如果不方便的话,您不必在这些通知中提到程序的名称,因为它出现在第一行。(源文件中的版权声明规则不同,参见GNU维护者信息中的“版权声明”)。
以上文字的翻译必须保持版权声明的有效性(参见原文第5.8节[国际化],第41页)。如果翻译的字符集支持它,则应将(C)
替换为版权符号,如下所示:
把“版权”这个词用英文写得一模一样。不要把它翻译成另一种语言。国际条约承认英文Copyright
一词,翻译成其他语言不具有法律意义。
最后,这里是我们建议的许可证缩写表。任何缩写都可以后跟’ v{version}[+] ‘,表示该特定版本,或稍后的版本’ + ',如上所示(GPLv3+
,version
为3
)。在GNU许可证的情况下,总是以这种方式指出允许的版本。
在GPL的额外许可的例外情况下,我们使用/
作为分隔符,版本号可以像往常一样跟在许可证缩写后面,如下面的示例所示。
GPL GNU General Public License, https://www.gnu.org/licenses/gpl.html.
LGPL GNU Lesser General Public License, https://www.gnu.org/licenses/lgpl.html.
GPL/Ada GNU GPL with the exception for Ada.
Apache The Apache Software Foundation license, https://directory.fsf.org/wiki/License:Apache2.0.
Artistic The Artistic license used for Perl,
https://directory.fsf.org/wiki/License:ArtisticLicense2.0.
Expat The Expat license, https://directory.fsf.org/wiki/License:Expat.
MPL The Mozilla Public License, https://directory.fsf.org/wiki/License:MPLv2.0.
OBSD The original (4-clause) BSD license, incompatible with the GNU GPL,
https://directory.fsf.org/wiki/License:BSD_4Clause.
PHP The license used for PHP, https://directory.fsf.org/wiki/License:PHPv3.01.
public domain
The non-license that is being in the public domain,
https://www.gnu.org/licenses/license-list.html#PublicDomain.
Python The license for Python, https://directory.fsf.org/wiki/License:Python2.0.1.
RBSD The revised (3-clause) BSD, compatible with the GNU GPL,
https://directory.fsf.org/wiki/License:BSD_3Clause.
X11 The simple non-copyleft license used for most versions of the X Window System,
https://directory.fsf.org/wiki/License:X11.
Zlib The license for Zlib, https://directory.fsf.org/wiki/License:Zlib.
关于这些许可的更多信息和更多的信息都在GNU许可网页上,https://www.gnu.org/licenses/license-list.html
。
保持自由程序自由的另一个方面是鼓励开发自由插件,而不鼓励开发专有插件。许多GNU程序根本没有插件之类的东西,但是那些有插件的程序应该遵循这些实践。
首先,一般的插件体系结构设计应该将插件与原始代码紧密地联系在一起,这样插件和基本程序就成了一个扩展程序的一部分。为
例如,GCC的插件接收并修改GCC的内部数据结构,因此很明显形成了一个带有基本GCC的扩展程序。
其次,您应该要求插件开发人员确认他们的插件是在适当的许可下发布的。这应该通过一个简单的程序性检查来实现。
再次以GCC为例,插件必须定义全局符号plugin_is_GPL-compatible
,从而断言该插件是在gpl兼容许可下发布的
(参见GCC内部介绍中的“插件”一节)。
通过将此检查添加到您的程序中,您并没有创建新的法律要求。GPL本身要求插件必须是自由软件,以兼容的方式获得许可。只要您遵循上述第一条规则,将插件与您的原始程序紧密联系在一起,GPL和AGPL已经要求这些插件必须在兼容的许可证下发布。插件中的符号定义,或者在您的程序中最有效的任何等价的定义,使得任何可能分发专有插件的人都难以合法地为自己辩护。如果这方面的案件上了法庭,我们可以指出这个符号作为插件开发人员理解许可证有这个要求的证据。
OID(对象标识符)1.3.6.1.4.1.11591已被分配给GNU项目(感谢Sergey Poznyakoff)。它们用于SNMP、LDAP、X.509证书等。网站https://www.alvestrand.no/objectid
(自愿)列出了许多OID分配。
如果您需要一个新的GNU包插槽,请编写maintainers@gnu.org
。以下是当前分配的弧线列表:
1.3.6.1.4.1.11591 GNU
1.3.6.1.4.1.11591.1 GNU Radius
1.3.6.1.4.1.11591.2 GnuPG
1.3.6.1.4.1.11591.2.1 notation
1.3.6.1.4.1.11591.2.1.1 pkaAddress
1.3.6.1.4.1.11591.3 GNU Radar
1.3.6.1.4.1.11591.4 GNU GSS
1.3.6.1.4.1.11591.5 GNU Mailutils
1.3.6.1.4.1.11591.6 GNU Shishi
1.3.6.1.4.1.11591.7 GNU Radio
......(省略其他节点)
如果一个程序通常只使用几兆内存,那么就不要费心去减少内存的使用。例如,如果由于其他原因对超过几兆长的文件进行操作是不切实际的,那么将整个输入文件读入内存以对其进行操作是合理的。
但是,对于像cat
或tail
这样可以有效地操作非常大的文件的程序,避免使用人为地限制它可以处理的文件大小的技术是很重要的。如果一个程序按行工作,并且可以应用于任意用户提供的输入文件,那么它应该只在内存中保留一行,因为这不是很难,并且用户希望能够操作大于内存容量的输入文件。
如果你的程序创建了复杂的数据结构,只要把它们放在内存中,如果malloc
返回NULL
,就会给出一个致命错误。
内存分析工具(如valgrind
)可能很有用,但不要仅仅为了避免错误警报而使程序复杂化。例如,如果内存直到进程退出之前都在被使用,那么不要释放它,简单地等待进程退出后自动回收即可。
当/usr
和/etc
是只读文件系统时,程序应该准备好运行。因此,如果程序管理日志文件、锁定文件、备份文件、评分文件或任何其他为内部目的而修改的文件,这些文件不应该存储在/usr
或/etc
中。
有两个例外。/etc
用于存储系统配置信息,当程序的任务是更新系统配置时,修改/etc
中的文件是合理的。此外,如果用户明确要求修改目录中的一个文件,那么程序将其他文件存储在同一目录中是合理的。
下面是GNU程序使用的长选项表。这当然是不完整的,但我们的目标是列出新程序可能想要兼容的所有选项。如果您使用的名称不在表中,请发送bug-standards@gnu.org
一个名称列表,并说明其含义,以便我们更新该表。
'after-date'
'-N' in 'tar'.
'all'
'-a' in 'du', 'ls', 'nm', 'stty', 'uname', and 'unexpand'.
'all-text'
'-a' in 'diff'.
'almost-all'
'-A' in 'ls'.
'append'
'-a' in 'etags', 'tee', 'time'; '-r' in 'tar'.
'archive'
'-a' in 'cp'.
'archive-name'
'-n' in 'shar'.
'arglength'
'-l' in 'm4'.
'ascii'
'-a' in 'diff'.
'assign'
'-v' in 'gawk'.
'assume-new'
'-W' in 'make'.
'assume-old'
'-o' in 'make'.
'auto-check'
'-a' in 'recode'.
'auto-pager'
'-a' in 'wdiff'.
'auto-reference'
'-A' in 'ptx'.
'avoid-wraps'
'-n' in 'wdiff'.
'background'
For server programs, run in the background.
'backward-search'
'-B' in 'ctags'.
'basename'
'-f' in 'shar'.
'batch'
Used in GDB.
'baud'
Used in GDB.
'before'
'-b' in 'tac'.
'binary'
'-b' in 'cpio' and 'diff'.
'bits-per-code'
'-b' in 'shar'.
'block-size'
Used in 'cpio' and 'tar'.
'blocks'
'-b' in 'head' and 'tail'.
'break-file'
'-b' in 'ptx'.
'brief'
Used in various programs to make output shorter.
'bytes'
'-c' in 'head', 'split', and 'tail'.
'c++'
'-C' in 'etags'.
'catenate'
'-A' in 'tar'.
'cd'
Used in various programs to specify the directory to use.
'changes'
'-c' in 'chgrp' and 'chown'.
'classify'
'-F' in 'ls'.
'colons'
'-c' in 'recode'.
'command'
'-c' in 'su'; '-x' in GDB.
'compare'
'-d' in 'tar'.
'compat'
Used in 'gawk'.
'compress'
'-Z' in 'tar' and 'shar'.
'concatenate'
'-A' in 'tar'.
'confirmation'
'-w' in 'tar'.
'context'
Used in 'diff'.
'copyleft'
'-W copyleft' in 'gawk'.
'copyright'
'-C' in 'ptx', 'recode', and 'wdiff'; '-W copyright' in 'gawk'.
'core'
Used in GDB.
'count'
'-q' in 'who'.
'count-links'
'-l' in 'du'.
'create'
Used in 'tar' and 'cpio'.
'cut-mark'
'-c' in 'shar'.
'cxref'
'-x' in 'ctags'.
'date'
'-d' in 'touch'.
'debug'
'-d' in 'make' and 'm4'; '-t' in Bison.
'define'
'-D' in 'm4'.
'defines'
'-d' in Bison and 'ctags'.
'delete'
'-D' in 'tar'.
'dereference'
'-L' in 'chgrp', 'chown', 'cpio', 'du', 'ls', and 'tar'.
'dereference-args'
'-D' in 'du'.
'device'
Specify an I/O device (special file name).
'diacritics'
'-d' in 'recode'.
'dictionary-order'
'-d' in 'look'.
'diff'
'-d' in 'tar'.
'digits'
'-n' in 'csplit'.
'directory'
Specify the directory to use, in various programs. In 'ls', it
means to show directories themselves rather than their contents.
In 'rm' and 'ln', it means to not treat links to directories
specially.
'discard-all'
'-x' in 'strip'.
'discard-locals'
'-X' in 'strip'.
'dry-run'
'-n' in 'make'.
'ed'
'-e' in 'diff'.
'elide-empty-files'
'-z' in 'csplit'.
'end-delete'
'-x' in 'wdiff'.
'end-insert'
'-z' in 'wdiff'.
'entire-new-file'
'-N' in 'diff'.
'environment-overrides'
'-e' in 'make'.
'eof'
'-e' in 'xargs'.
'epoch'
Used in GDB.
'error-limit'
Used in 'makeinfo'.
'error-output'
'-o' in 'm4'.
'escape'
'-b' in 'ls'.
'exclude-from'
'-X' in 'tar'.
'exec'
Used in GDB.
'exit'
'-x' in 'xargs'.
'exit-0'
'-e' in 'unshar'.
'expand-tabs'
'-t' in 'diff'.
'expression'
'-e' in 'sed'.
'extern-only'
'-g' in 'nm'.
'extract'
'-i' in 'cpio'; '-x' in 'tar'.
'faces'
'-f' in 'finger'.
'fast'
'-f' in 'su'.
'fatal-warnings'
'-E' in 'm4'.
'file'
'-f' in 'gawk', 'info', 'make', 'mt', 'sed', and 'tar'.
'field-separator'
'-F' in 'gawk'.
'file-prefix'
'-b' in Bison.
'file-type'
'-F' in 'ls'.
'files-from'
'-T' in 'tar'.
'fill-column'
Used in 'makeinfo'.
'flag-truncation'
'-F' in 'ptx'.
'fixed-output-files'
'-y' in Bison.
'follow'
'-f' in 'tail'.
'footnote-style'
Used in 'makeinfo'.
'force'
'-f' in 'cp', 'ln', 'mv', and 'rm'.
'force-prefix'
'-F' in 'shar'.
'foreground'
For server programs, run in the foreground; in other words, don't
do anything special to run the server in the background.
'format'
Used in 'ls', 'time', and 'ptx'.
'freeze-state'
'-F' in 'm4'.
'fullname'
Used in GDB.
'gap-size'
'-g' in 'ptx'.
'get'
'-x' in 'tar'.
'graphic'
'-i' in 'ul'.
'graphics'
'-g' in 'recode'.
'group'
'-g' in 'install'.
'gzip'
'-z' in 'tar' and 'shar'.
'hashsize'
'-H' in 'm4'.
'header'
'-h' in 'objdump' and 'recode'
'heading'
'-H' in 'who'.
'help'
Used to ask for brief usage information.
'here-delimiter'
'-d' in 'shar'.
'hide-control-chars'
'-q' in 'ls'.
'html'
In 'makeinfo', output HTML.
'idle'
'-u' in 'who'.
'ifdef'
'-D' in 'diff'.
'ignore'
'-I' in 'ls'; '-x' in 'recode'.
'ignore-all-space'
'-w' in 'diff'.
'ignore-backups'
'-B' in 'ls'.
'ignore-blank-lines'
'-B' in 'diff'.
'ignore-case'
'-f' in 'look' and 'ptx'; '-i' in 'diff' and 'wdiff'.
'ignore-errors'
'-i' in 'make'.
'ignore-file'
'-i' in 'ptx'.
'ignore-indentation'
'-I' in 'etags'.
'ignore-init-file'
'-f' in Oleo.
'ignore-interrupts'
'-i' in 'tee'.
'ignore-matching-lines'
'-I' in 'diff'.
'ignore-space-change'
'-b' in 'diff'.
'ignore-zeros'
'-i' in 'tar'.
'include'
'-i' in 'etags'; '-I' in 'm4'.
'include-dir'
'-I' in 'make'.
'incremental'
'-G' in 'tar'.
'info'
'-i', '-l', and '-m' in Finger.
'init-file'
In some programs, specify the name of the file to read as the
user's init file.
'initial'
'-i' in 'expand'.
'initial-tab'
'-T' in 'diff'.
'inode'
'-i' in 'ls'.
'interactive'
'-i' in 'cp', 'ln', 'mv', 'rm'; '-e' in 'm4'; '-p' in 'xargs'; '-w'
in 'tar'.
'intermix-type'
'-p' in 'shar'.
'iso-8601'
Used in 'date'
'jobs'
'-j' in 'make'.
'just-print'
'-n' in 'make'.
'keep-going'
'-k' in 'make'.
'keep-files'
'-k' in 'csplit'.
'kilobytes'
'-k' in 'du' and 'ls'.
'language'
'-l' in 'etags'.
'less-mode'
'-l' in 'wdiff'.
'level-for-gzip'
'-g' in 'shar'.
'line-bytes'
'-C' in 'split'.
'lines'
Used in 'split', 'head', and 'tail'.
'link'
'-l' in 'cpio'.
'lint'
'lint-old'
Used in 'gawk'.
'list'
'-t' in 'cpio'; '-l' in 'recode'.
'list'
'-t' in 'tar'.
'literal'
'-N' in 'ls'.
'load-average'
'-l' in 'make'.
'login'
Used in 'su'.
'machine'
Used in 'uname'.
'macro-name'
'-M' in 'ptx'.
'mail'
'-m' in 'hello' and 'uname'.
'make-directories'
'-d' in 'cpio'.
'makefile'
'-f' in 'make'.
'mapped'
Used in GDB.
'max-args'
'-n' in 'xargs'.
'max-chars'
'-n' in 'xargs'.
'max-lines'
'-l' in 'xargs'.
'max-load'
'-l' in 'make'.
'max-procs'
'-P' in 'xargs'.
'mesg'
'-T' in 'who'.
'message'
'-T' in 'who'.
'minimal'
'-d' in 'diff'.
'mixed-uuencode'
'-M' in 'shar'.
'mode'
'-m' in 'install', 'mkdir', and 'mkfifo'.
'modification-time'
'-m' in 'tar'.
'multi-volume'
'-M' in 'tar'.
'name-prefix'
'-a' in Bison.
'nesting-limit'
'-L' in 'm4'.
'net-headers'
'-a' in 'shar'.
'new-file'
'-W' in 'make'.
'no-builtin-rules'
'-r' in 'make'.
'no-character-count'
'-w' in 'shar'.
'no-check-existing'
'-x' in 'shar'.
'no-common'
'-3' in 'wdiff'.
'no-create'
'-c' in 'touch'.
'no-defines'
'-D' in 'etags'.
'no-deleted'
'-1' in 'wdiff'.
'no-dereference'
'-d' in 'cp'.
'no-inserted'
'-2' in 'wdiff'.
'no-keep-going'
'-S' in 'make'.
'no-lines'
'-l' in Bison.
'no-piping'
'-P' in 'shar'.
'no-prof'
'-e' in 'gprof'.
'no-regex'
'-R' in 'etags'.
'no-sort'
'-p' in 'nm'.
'no-splash'
Don't print a startup splash screen.
'no-split'
Used in 'makeinfo'.
'no-static'
'-a' in 'gprof'.
'no-time'
'-E' in 'gprof'.
'no-timestamp'
'-m' in 'shar'.
'no-validate'
Used in 'makeinfo'.
'no-wait'
Used in 'emacsclient'.
'no-warn'
Used in various programs to inhibit warnings.
'node'
'-n' in 'info'.
'nodename'
'-n' in 'uname'.
'nonmatching'
'-f' in 'cpio'.
'nstuff'
'-n' in 'objdump'.
'null'
'-0' in 'xargs'.
'number'
'-n' in 'cat'.
'number-nonblank'
'-b' in 'cat'.
'numeric-sort'
'-n' in 'nm'.
'numeric-uid-gid'
'-n' in 'cpio' and 'ls'.
'nx'
Used in GDB.
'old-archive'
'-o' in 'tar'.
'old-file'
'-o' in 'make'.
'one-file-system'
'-l' in 'tar', 'cp', and 'du'.
'only-file'
'-o' in 'ptx'.
'only-prof'
'-f' in 'gprof'.
'only-time'
'-F' in 'gprof'.
'options'
'-o' in 'getopt', 'fdlist', 'fdmount', 'fdmountd', and 'fdumount'.
'output'
In various programs, specify the output file name.
'output-prefix'
'-o' in 'shar'.
'override'
'-o' in 'rm'.
'overwrite'
'-c' in 'unshar'.
'owner'
'-o' in 'install'.
'paginate'
'-l' in 'diff'.
'paragraph-indent'
Used in 'makeinfo'.
'parents'
'-p' in 'mkdir' and 'rmdir'.
'pass-all'
'-p' in 'ul'.
'pass-through'
'-p' in 'cpio'.
'port'
'-P' in 'finger'.
'portability'
'-c' in 'cpio' and 'tar'.
'posix'
Used in 'gawk'.
'prefix-builtins'
'-P' in 'm4'.
'prefix'
'-f' in 'csplit'.
'preserve'
Used in 'tar' and 'cp'.
'preserve-environment'
'-p' in 'su'.
'preserve-modification-time'
'-m' in 'cpio'.
'preserve-order'
'-s' in 'tar'.
'preserve-permissions'
'-p' in 'tar'.
'print'
'-l' in 'diff'.
'print-chars'
'-L' in 'cmp'.
'print-data-base'
'-p' in 'make'.
'print-directory'
'-w' in 'make'.
'print-file-name'
'-o' in 'nm'.
'print-symdefs'
'-s' in 'nm'.
'printer'
'-p' in 'wdiff'.
'prompt'
'-p' in 'ed'.
'proxy'
Specify an HTTP proxy.
'query-user'
'-X' in 'shar'.
'question'
'-q' in 'make'.
'quiet'
Used in many programs to inhibit the usual output. Every program
accepting '--quiet' should accept '--silent' as a synonym.
'quiet-unshar'
'-Q' in 'shar'
'quote-name'
'-Q' in 'ls'.
'rcs'
'-n' in 'diff'.
're-interval'
Used in 'gawk'.
'read-full-blocks'
'-B' in 'tar'.
'readnow'
Used in GDB.
'recon'
'-n' in 'make'.
'record-number'
'-R' in 'tar'.
'recursive'
Used in 'chgrp', 'chown', 'cp', 'ls', 'diff', and 'rm'.
'reference'
'-r' in 'touch'.
'references'
'-r' in 'ptx'.
'regex'
'-r' in 'tac' and 'etags'.
'release'
'-r' in 'uname'.
'reload-state'
'-R' in 'm4'.
'relocation'
'-r' in 'objdump'.
'rename'
'-r' in 'cpio'.
'replace'
'-i' in 'xargs'.
'report-identical-files'
'-s' in 'diff'.
'reset-access-time'
'-a' in 'cpio'.
'reverse'
'-r' in 'ls' and 'nm'.
'reversed-ed'
'-f' in 'diff'.
'right-side-defs'
'-R' in 'ptx'.
'same-order'
'-s' in 'tar'.
'same-permissions'
'-p' in 'tar'.
'save'
'-g' in 'stty'.
'se'
Used in GDB.
'sentence-regexp'
'-S' in 'ptx'.
'separate-dirs'
'-S' in 'du'.
'separator'
'-s' in 'tac'.
'sequence'
Used by 'recode' to chose files or pipes for sequencing passes.
'shell'
'-s' in 'su'.
'show-all'
'-A' in 'cat'.
'show-c-function'
'-p' in 'diff'.
'show-ends'
'-E' in 'cat'.
'show-function-line'
'-F' in 'diff'.
'show-tabs'
'-T' in 'cat'.
'silent'
Used in many programs to inhibit the usual output. Every program
accepting '--silent' should accept '--quiet' as a synonym.
'size'
'-s' in 'ls'.
'socket'
Specify a file descriptor for a network server to use for its
socket, instead of opening and binding a new socket. This provides
a way to run, in a non-privileged process, a server that normally
needs a reserved port number.
'sort'
Used in 'ls'.
'source'
'-W source' in 'gawk'.
'sparse'
'-S' in 'tar'.
'speed-large-files'
'-H' in 'diff'.
'split-at'
'-E' in 'unshar'.
'split-size-limit'
'-L' in 'shar'.
'squeeze-blank'
'-s' in 'cat'.
'start-delete'
'-w' in 'wdiff'.
'start-insert'
'-y' in 'wdiff'.
'starting-file'
Used in 'tar' and 'diff' to specify which file within a directory
to start processing with.
'statistics'
'-s' in 'wdiff'.
'stdin-file-list'
'-S' in 'shar'.
'stop'
'-S' in 'make'.
'strict'
'-s' in 'recode'.
'strip'
'-s' in 'install'.
'strip-all'
'-s' in 'strip'.
'strip-debug'
'-S' in 'strip'.
'submitter'
'-s' in 'shar'.
'suffix'
'-S' in 'cp', 'ln', 'mv'.
'suffix-format'
'-b' in 'csplit'.
'sum'
'-s' in 'gprof'.
'summarize'
'-s' in 'du'.
'symbolic'
'-s' in 'ln'.
'symbols'
Used in GDB and 'objdump'.
'synclines'
'-s' in 'm4'.
'sysname'
'-s' in 'uname'.
'tabs'
'-t' in 'expand' and 'unexpand'.
'tabsize'
'-T' in 'ls'.
'terminal'
'-T' in 'tput' and 'ul'. '-t' in 'wdiff'.
'text'
'-a' in 'diff'.
'text-files'
'-T' in 'shar'.
'time'
Used in 'ls' and 'touch'.
'timeout'
Specify how long to wait before giving up on some operation.
'to-stdout'
'-O' in 'tar'.
'total'
'-c' in 'du'.
'touch'
'-t' in 'make', 'ranlib', and 'recode'.
'trace'
'-t' in 'm4'.
'traditional'
'-t' in 'hello'; '-W traditional' in 'gawk'; '-G' in 'ed', 'm4',
and 'ptx'.
'tty'
Used in GDB.
'typedefs'
'-t' in 'ctags'.
'typedefs-and-c++'
'-T' in 'ctags'.
'typeset-mode'
'-t' in 'ptx'.
'uncompress'
'-z' in 'tar'.
'unconditional'
'-u' in 'cpio'.
'undefine'
'-U' in 'm4'.
'undefined-only'
'-u' in 'nm'.
'update'
'-u' in 'cp', 'ctags', 'mv', 'tar'.
'usage'
Used in 'gawk'; same as '--help'.
'uuencode'
'-B' in 'shar'.
'vanilla-operation'
'-V' in 'shar'.
'verbose'
Print more information about progress. Many programs support this.
'verify'
'-W' in 'tar'.
'version'
Print the version number.
'version-control'
'-V' in 'cp', 'ln', 'mv'.
'vgrind'
'-v' in 'ctags'.
'volume'
'-V' in 'tar'.
'what-if'
'-W' in 'make'.
'whole-size-limit'
'-l' in 'shar'.
'width'
'-w' in 'ls' and 'ptx'.
'word-regexp'
'-W' in 'ptx'.
'writable'
'-T' in 'who'.
'zeros'
'-z' in 'gprof'.
在Unix系统中,信号处理是进程间通信的重要方式之一。不同的Unix系统变体提供了不同的信号处理接口。以下是BSD风格的signal
函数、System V(USG)风格的signal
接口,以及POSIX标准的sigaction
函数的区别:
BSD(Berkeley Software Distribution)Unix的signal
函数在设计时考虑了信号的可重入性。在BSD系统中,当一个信号处理器被触发时,系统默认情况下会重置该信号的处理器为默认行为。此外,BSD的signal
函数在处理信号时会阻塞相同类型的信号,避免递归调用(即在信号处理函数执行期间,相同的信号再次发生并调用信号处理函数)。
System V(有时称为USG,Unix System Group)的signal
函数则有所不同。在这种变体中,信号处理程序被触发后,信号的处理方式并不会被重置为默认行为,信号处理函数也不会自动阻塞额外的同类信号。这可能导致信号处理函数在执行期间被同类型的信号中断,从而引起竞态条件。
为了解决这些差异,并提供一个可靠和一致的信号处理机制,POSIX(可移植操作系统接口)标准引入了sigaction
函数。sigaction
提供了更多的控制,允许程序明确指定在信号处理函数执行时是否阻塞其他信号。它还允许指定信号处理完毕后信号的处理方式是否应该被重置。sigaction
是现代Unix系统推荐的信号处理方式。