编码风格之(5)GNU软件编码风格(3)

GNU软件编码标准风格(3)

Author:Onceday    Date: 2024年1月21日

漫漫长路,才刚刚开始…

本文主要翻译自《GNU编码标准》(GNU Coding Standards)一文。

参考文档:

  • Linux kernel coding style — The Linux Kernel documentation
  • GNU Coding Standards - GNU Project - Free Software Foundation
7. 整体软件配置框架

发布不仅仅是把源文件打包成一个tar文件,然后放到FTP上。您应该对软件进行设置,以便可以将其配置为在各种系统上运行。您的Makefile应该符合下面描述的GNU标准,您的目录布局也应该符合下面讨论的标准。这样做可以很容易地将您的包包含到所有GNU软件的大框架中。

7.1 配置应该如何工作

每个GNU发行版都应该附带一个名为configure的shell脚本。这个脚本给出了参数,这些参数描述了你想要编译程序的机器和系统的类型。configure脚本必须记录配置选项,以便它们影响编译。

这里的描述是GNU包中配置脚本的接口规范。许多软件包使用GNU Autoconf(参见Autoconf的“介绍”部分)或GNU Automake(参见Automake的“介绍”部分)实现它,但您不必使用这些工具。你可以用任何你喜欢的方式实现它,例如,通过使configure成为一个完全不同的配置系统的包装器。

配置脚本的另一种操作方式是从标准名称(如config.h)链接到所选系统的适当配置文件。如果使用这种技术,发行版不应该包含一个名为config.h的文件。这样人们就无法在没有配置的情况下构建程序。

configure可以做的另一件事是编辑Makefile。如果这样做,发行版不应该包含名为Makefile的文件。相反,它应该包含一个Makefile文件。其中包含用于编辑的输入。同样,这样做是为了让人们在不先配置程序的情况下无法构建程序。

如果configure确实写入Makefile,那么Makefile应该有一个名为Makefile,它导致configure重新运行,设置与上次设置相同的配置。应将configure读取的文件列为依赖项
Makefile。

从configure脚本输出的所有文件都应该在开头有注释,说明它们是使用configure自动生成的。这样用户就不会想要手工编辑它们。

配置脚本应该编写一个名为config的文件。状态,描述上次配置程序时指定了哪些配置选项。该文件应该是一个shell脚本,如果运行,将重新创建相同的配置。

配置脚本应该接受一个形式为--srcdir=dirname的选项来指定查找源文件的目录(如果不是当前目录)。这使得在单独的目录中构建程序成为可能,这样就不会修改实际的源目录。

如果用户没有指定--srcdir,那么configure应该同时检查这两个参数...看看它能不能找到来源。如果它在其中一个地方找到了资源,它应该从那里使用它们。否则,它应该报告它找不到源,并且应该以非零状态退出。

通常,支持--srcdir的简单方法是编辑Makefile中VPATH的定义。有些规则可能需要显式引用指定的源目录。为了实现这一点,configure可以向Makefile添加一个名为srcdir的变量,其值恰好是指定的目录。

此外,configure脚本应该采用与大多数标准目录变量对应的选项,以下是清单:

--prefix --exec-prefix --bindir --sbindir --libexecdir --sysconfdir
--sharedstatedir --localstatedir --runstatedir
--libdir --includedir --oldincludedir
--datarootdir --datadir --infodir --localedir --mandir --docdir
--htmldir --dvidir --pdfdir --psdir

configure脚本还应该接受一个参数,该参数指定要为其构建程序的系统类型。这个参数应该是这样的:

cpu-company-system

例如,基于athlon的GNU/Linux系统可能是i686-pc-linux-gnu

configure脚本需要能够解码如何描述机器的所有可能的替代方案。因此,athlon-pc-gnu/linux将是一个有效的别名。有一个名为[config.sub](https://git.savannah.gnu.org/cgit/config.git/plain/ config.sub),您可以将其用作验证系统类型和规范化别名的子例程。

配置脚本还应该采用选项--build=buildtype,这应该等同于一个普通的buildtype参数。例如,

configure --build=i686-pc-linux-gnu <==>configure i686-pc-linux-gnu

当没有通过选项或参数指定构建类型时,配置脚本通常应该使用shell脚本配置[config.guess](https://git.savannah.gnu.org/ cgit/config.git/plain/config.guess)来猜测它。

其他选项允许更详细地指定机器上存在的软件或硬件,包括或排除包的可选部分,或调整某些工具或参数的名称:

  • --enable-feature[=parameter],配置包以构建和安装一个名为feature的可选用户级工具。这允许用户选择要包含哪些可选特性。如果它是默认构建的,那么给出一个可选参数’ no '应该会忽略功能。
    --enable选项不应该导致一个功能取代另一个功能。

    ——enable选项不应该用一个有用的行为替换另一个有用的行为。

    --enable的唯一正确用法是用于是否构建程序的一部分或排除它。

  • --with-package,这个包将被安装,所以将这个包配置为与package一起工作。package的可能值包括gnu-as(或gas),gnu-ldgnu-libcgdbxx-toolkit。不要使用--with选项来指定文件名,以便查找某些文件。这超出了--with选项的范围。

  • variable=value,将变量variable的值设置为value。这用于覆盖构建过程中命令或参数的默认值。

    例如,用户可以发出configure CFLAGS=-g CXXFLAGS=-g来使用调试信息而不使用默认优化进行构建。

    指定变量作为配置参数,如下所示:

    ./configure CC=gcc
    

    比在环境变量中设置它们更可取:

    CC=gcc ./configure
    

    因为它有助于稍后使用config.status重新创建相同的配置。但是,这两种方法都应该得到支持。

所有配置脚本都应该接受所有的“细节”选项和变量设置,无论它们是否对手头的特定包产生任何影响。特别是,它们应该接受以--with---enable-开头的任何选项。这样,用户就可以用一组选项一次性配置整个GNU源代码树。

您将注意到--with---enable-这两个类别很窄:它们没有为您可能想到的任何选项提供位置。这是故意的。我们希望限制GNU软件中可能的配置选项。我们不希望GNU程序有特殊的配置选项。

执行部分编译过程的包可能支持交叉编译。在这种情况下,程序的主机和目标机器可能不同。

configure脚本通常应该将指定类型的系统同时视为主机和目标,从而生成一个适用于它所运行的同一类型机器的程序。

要编译一个程序,使其在不同于构建类型的主机类型上运行,请使用配置选项--host=hosttype,其中hosttype使用与buildtype相同的语法。主机类型通常默认为构建类型。

要配置一个交叉编译器、交叉汇编器,或者其他什么,你应该指定一个不同于主机的目标,使用配置选项--target=targettypetargettype的语法与主机类型相同。所以命令看起来像这样:

./configure --host=hosttype --target=targettype

目标器类型通常默认为主机类型。交叉操作没有意义的程序不需要接受--target选项,因为为交叉操作配置整个操作系统并不是一个有意义的操作。

有些程序有自动配置自己的方法。如果您的程序被设置为这样做,那么您的configure脚本可以简单地忽略它的大部分参数。

7.2 makefile的通用约定

本节描述为GNU程序编写makefile的约定。使用Automake将帮助您编写遵循这些约定的Makefile。有关可移植makefile的更多信息,请参阅Autoconf中的posix和“portable Make”部分。

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

SHELL = /bin/sh

以避免在SHELL变量可能从环境中继承的系统上出现问题。(这从来都不是GNU make的问题)。

不同的make程序有不兼容的后缀列表和隐式规则,这有时会造成混淆或错误行为。因此,只使用特定Makefile中需要的后缀显式设置后缀列表是个好主意,如下所示:

.SUFFIXES:
.SUFFIXES: .c .o

第一行清除了后缀列表,第二行引入了可能受此Makefile中隐式规则约束的所有后缀。

不要这么认为.目录在命令执行的路径中。当您需要在make过程中运行包中的一部分程序时,如果程序是作为make的一部分构建的,请确保它使用./,如果文件是源代码的不变部分,请确保它使用$(srcdir)/。如果没有这些前缀之一,则使用当前搜索路径。

./(构建目录)和$(srcdir)/(源目录)之间的区别很重要,因为用户可以使用--srcdir选项在单独的目录中构建。一种形式的规则如下:

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 $@

以允许VPATH正确工作。当目标有多个依赖项时,使用显式的$(srcdir)是使规则正常工作的最简单方法。例如,上面的目标为foo.1最好写成:

foo.1 : foo.man sedscript
	sed -f $(srcdir)/sedscript $(srcdir)/foo.man > $@

GNU发行版通常包含一些不是源文件的文件,例如Info文件,以及来自AutoconfAutomakeBisonFlex的输出。由于这些文件通常出现在源目录中,因此它们应该始终出现在源目录中,而不是在构建目录中。因此,更新它们的Makefile规则应该将更新后的文件放在源目录中。

但是,如果一个文件没有出现在发行版中,那么Makefile不应该把它放在源目录中,因为在一般情况下构建程序不应该以任何方式修改源目录。

尝试使构建和安装目标,至少(以及它们的所有子目标)在并行make中正确工作。

7.3 Makefiles中的实用程序

编写Makefile命令(以及任何shell脚本,如configure)以在sh下运行(包括传统的Bourne shell和posix shell),而不是csh。不要使用ksh或bash的任何特殊特性,或者传统Bourne sh中不广泛支持的posix特性。

用于构建和安装的configure脚本和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”部分。

避免在makefiles中创建符号链接是一个好主意,因为一些文件系统不支持符号链接。

用于构建和安装的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)

当您使用ranlibldconfig时,您应该确保如果系统中没有相关的程序,也不会发生什么不好的事情。需要忽略来自该命令的错误,并在该命令之前打印一条消息,告诉用户该命令失败并不意味着有问题(Autoconf AC_PROG_RANLIB宏可以解决这个问题)。

如果使用符号链接,则应该为没有符号链接的系统实现回退。可以通过Make变量使用的其他实用程序有:

chgrp chmod chown mknod

在Makefile部分(或脚本)中使用其他实用程序是可以的,这些实用程序仅适用于您知道存在这些实用程序的特定系统。

7.4 用于指定命令的变量

makefile应该为覆盖某些命令、选项等提供变量。特别是,您应该通过变量运行大多数实用程序。因此,如果你使用Bison,有一个名为Bison的变量,其默认值设置为Bison = Bison,并在需要使用Bison时使用$(Bison)来引用它。

文件管理实用程序(如ln、rm、mv等)不需要以这种方式通过变量引用,因为用户不需要用其他程序替换它们。

每个程序名称变量都应该带有一个选项变量,用于向程序提供选项。在program-name变量名后面附加FLAGS以获得选项变量名,例如BISONFLAGS。(C编译器的名称CFLAGS, yacc的名称YFLAGS, lex的名称LFLAGS都是此规则的例外,但我们保留它们,因为它们是标准的)。

在任何运行预处理器的编译命令中使用CPPFLAGS,在任何进行链接的编译命令中使用LDFLAGS,以及在任何直接使用ld的编译命令中使用LDFLAGS

如果必须使用C编译器选项来正确编译某些文件,请不要将它们包含在CFLAGS中。用户希望能够自己自由地指定CFLAGS

相反,安排将必要的选项传递给独立于CFLAGS的C编译器,通过在编译命令中显式地编写它们或通过定义隐式规则,像这样:

CFLAGS = -g
ALL_CFLAGS = -I. $(CFLAGS)
.c.o:
	$(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<

一定要在CFLAGS中包含-g选项,因为这不是正确编译所必需的。您可以将其视为仅推荐的默认值。如果将包设置为默认使用GCC编译,那么您也可以在CFLAGS的默认值中包含-O

CFLAGS放在编译命令的最后,在包含编译器选项的其他变量之后,这样用户就可以使用CFLAGS来覆盖其他变量。CFLAGS应该在C编译器的每次调用中使用,无论是编译还是链接。每个Makefile都应该定义变量INSTALL,这是将文件安装到系统中的基本命令。

每个Makefile还应该定义变量INSTALL_PROGRAMINSTALL_DATA

INSTALL_PROGRAM的默认值应该是$(INSTALL)INSTALL_DATA的默认值应该是${INSTALL} -m 644

然后,它应该使用这些变量作为实际安装的命令,分别用于可执行文件和不可执行文件。这些变量的最小使用如下:

$(INSTALL_PROGRAM) foo $(bindir)/foo
$(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a

不过,最好在目标文件上支持DESTDIR前缀,下一节将对此进行说明。在一个命令中安装多个文件是可以接受的,但不是必需的,最后一个参数是目录,如下所示:

$(INSTALL_PROGRAM) foo bar baz $(bindr)
7.5 支持分阶段安装

DESTDIR是一个附加在每个已安装目标文件前的变量,如下所示:

$(INSTALL_PROGRAM) foo $(DESTDIR)$(bindir)/foo
$(INSTALL_DATA) libfoo.a $(DESTDIR)$(libdir)/libfoo.a

DESTDIR变量由用户在make命令行中指定为绝对文件名。例如:

make DESTDIR=/tmp/stage install

应该只在安装install*和卸载uninstall*目标中支持DESTDIR,因为只有在这些目标中DESTDIR才有用。

如果你的安装步骤正常安装/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的值,然后在默认情况下将这些文件安装到预期的位置。此外,指定DESTDIR不应该以任何方式改变软件的操作,因此它的值不应该包含在任何文件内容中。

DESTDIR支持通常用于包创建。对于想要了解给定包将安装在何处的用户,以及允许通常没有权限安装到受保护区域的用户在获得这些权限之前进行构建和安装,这也很有帮助。最后,它还可以用于诸如stow之类的工具,在这些工具中,代码安装在一个地方,但使用符号链接或特殊挂载操作使其看起来像是安装在其他地方。因此,我们强烈建议GNU软件包支持DESTDIR,尽管它不是绝对要求。

7.6 安装目录变量

安装目录应该始终由变量命名,因此很容易在非标准位置安装。下面描述了这些变量的标准名称以及它们在GNU包中应该具有的值。它们基于标准的文件系统布局,它的变体在GNU/Linux和其他现代操作系统中使用。

安装程序在调用make(例如,make prefix=/usr install)或configure(例如,configure ——prefix=/usr)时会覆盖这些值。GNU包不应该试图猜测在它们被安装到的系统上哪个值适合这些变量:直接使用这里指定的默认设置,以便所有的GNU包的行为相同,允许安装程序实现任何所需的布局。

所有的安装目录及其父目录都应该在安装之前创建(如果需要的话)。

前两个变量设置了安装的根目录。所有其他安装目录都应该是这两个目录之一的子目录,并且不应该直接安装到这两个目录中。

  • prefix,用于构造下面列出的变量的默认值的前缀。prefix的默认值为/usr/local。当构建完整的GNU系统时,前缀将为空,/usr将是到/的符号链接。(如果您使用Autoconf,请将其写为@prefix@)。

    使用不同的prefix值运行“make install”不会重新编译该程序。

  • exec_prefix,在构造下面列出的一些变量的默认值时使用的前缀。exec_prefix的默认值应该是$(prefix),(如果你使用Autoconf,把它写成@exec_prefix@)。

    通常,$(exec_prefix)用于包含特定于机器的文件(例如可执行文件和子例程库)的目录,而$(prefix)直接用于其他目录。
    使用不同的exec_prefix值运行make install不会重新编译程序。

可执行程序安装在以下目录之一:

  • bindir,用户可以运行的可执行程序的安装目录。这通常应该是/usr/local/bin,但是写成$(exec_prefix)/bin。(如果你使用的是Autoconf,把它写成@bindir@)。
  • sbindir,用于安装可从shell运行的可执行程序的目录,但通常只对系统管理员有用。这通常应该是/usr/local/sbin,但是写成$(exec_prefix)/sbin。(如果你正在使用自动配置,写为@sbindir@)。
  • libexecdir,用于安装由其他程序而非用户运行的可执行程序的目录。这个目录通常应该是/usr/local/libexec,但是可以写成$(exec_prefix)/libexec。如果你使用Autoconf,把它写成@libexecdir@ libexecdir的定义对所有包都是一样的,所以您应该将数据安装在它的子目录中。大多数包将它们的数据安装在$(libexecdir)/package-name/下,也可能在它的其他子目录中,比如$(libexecdir)/package-name/machine/version

程序在执行过程中使用的数据文件分为两类:

  • 有些文件通常由程序修改,其他的则通常不会被修改(尽管用户可以编辑其中的一些)。
  • 有些文件是独立于体系结构的,可以由站点上的所有机器共享,有些是依赖于体系结构的,只能由相同类型和操作系统的机器共享,其他可能永远不会在两台机器之间共享。

这就产生了六种不同的可能性。然而,除了目标文件和库之外,我们不鼓励使用与体系结构相关的文件。使其他数据文件与体系结构无关要简单得多,而且通常并不难。

下面是Makefiles应该用来指定存放这些不同类型文件的目录的变量:

(1)datarootdir,用于与体系结构无关的只读数据文件的目录树的根目录。这通常应该是/usr/local/share,但是要写成$(prefix)/share。如果你使用Autoconf,把它写为@datarootdir@datadir的默认值是基于这个变量。如infodirmandir等也是如此。

(2)datadir,用于安装此程序的特殊只读、独立于体系结构的数据文件的目录。这通常是与datarootdir相同的位置,但我们使用两个单独的变量,以便您可以移动这些特定于程序的文件,而无需更改Info文件,手册页等的位置。

这通常应该是/usr/local/share,但是将它写成$(datarootdir)。(如果您使用Autoconf,请将其写入@datadir@)datadir的定义对所有包都是一样的,所以你应该把你的数据安装在它的子目录下。大多数包将它们的数据安装在$(datadir)/package-name/下。

(3)sysconfdir,用于安装属于单个机器的只读数据文件的目录,也就是说,用于配置主机的文件。

邮件和网络配置文件、/etc/passwd等等都属于这里。该目录下的所有文件都应该是普通的ASCII文本文件。这个目录通常应该是/usr/local/etc,但是把它写成$(prefix)/etc。(如果您使用的是自动配置,请将其写入@sysconfdir@)。

不要在此目录下安装可执行文件(它们可能属于$(libexecdir)$(sbindir))。另外,不要安装在正常使用过程中被修改过的文件(目的是改变系统配置的程序除外)。这些可能属于$(localstatedir)

(4)sharedstatedir,用于安装与体系结构无关的数据文件的目录,程序在运行时可以修改这些文件。

这通常应是/usr/local/com,但是写成$(prefix)/com。(如果您使用的是Autoconf,请将其写为@sharedstatedir@)。

(5)localstatedir,用于安装数据文件的目录,这些文件在程序运行时被修改,并且属于一台特定的机器。用户不需要修改此目录下的文件来配置包的操作,将这些配置信息放在$(datadir)$(sysconfdir)$(localstatedir)通常应该是/usr/local/var,但是写成$(prefix)/var。(如果您使用的是Autoconf,请将其写为@localstatedir@)。

(6)runstatedir,用于安装程序在运行时修改的数据文件的目录,它属于一台特定的机器,并且不需要保存比程序执行时间更长的时间,通常是长寿命的,例如,直到下一次重启。用于系统守护进程的PID文件是一个典型的用途。

此外,除非在重新启动时,否则不应该清理这个目录,而一般的/tmp(TMPDIR)可能会被任意清理。这通常应该是/var/run,但是把它写成$(localstatedir)/run。例如,如果需要的话,可以将它作为一个单独的变量使用/run。(如果您使用的是Autoconf 2.70或更高版本,请将其写入@runstatedir@)。

如果您的程序有特定类型的文件,这些变量指定用于安装这些文件的目录。每个GNU包都应该有Info文件,因此每个程序都需要
infodir,但不是所有都需要libdirlispdir

(1)includedir,用于安装头文件的目录,用户程序将使用c # include预处理器指令包含头文件。通常应该是/usr/local/include,但是写成$(prefix)/include。(如果你使用Autoconf,把它写为@includedir@)。除了GCC之外,大多数编译器不会在目录/usr/local/include中查找头文件。

因此,以这种方式安装头文件只对GCC有用。有时这不是问题,因为有些库实际上只打算与GCC一起工作。但有些库旨在与其他编译器一起工作。它们应该在两个地方安装头文件,一个由includedir指定,另一个由oldincludedir指定。

(2)oldincludedir,用于安装#include头文件的目录,用于GCC以外的编译器。通常应该是/usr/include。(如果你使用的是Autoconf,你可以把它写成@oldincludedir@)。

Makefile命令应该检查oldincludedir的值是否为空。如果是,他们不应该尝试使用它,他们应该取消头文件的第二次安装。包不应该替换此目录中现有的头文件,除非该头文件来自同一包。

因此,如果您的Foo包提供了一个头文件Foo .h,那么如果(1)那里没有Foo .h,或者(2)存在的Foo .h来自Foo包,那么它应该将头文件安装在oldincludedir目录中。要判断Foo .h是否来自Foo包,请在文件(注释的一部分)中放入一个魔法字符串,然后为该字符串执行grep

(3)docdir,该软件包的文档文件(除“信息”外)的安装目录。默认情况下,它应该是/usr/local/share/doc/yourpkg,但它应该写成$(datarootdir)/doc/yourpkg。(如果你使用Autoconf,把它写成@docdir@),yourpkg子目录可能包含一个版本号,它可以防止文件名相同的文件之间的冲突,比如README。

(4)infodir,此软件包的Info文件的安装目录。默认情况下,它应该是/usr/local/share/info,但是应该写为$(datarootdir)/info。(如果您使用Autoconf,请将其写为@infodir@),infodirdocdir分开是为了与现有实践兼容。

(5)htmldir/dvidir/pdfdir/psdir,用于安装特定格式文档文件的目录。它们都应该默认设置为$(docdir)。(如果你使用Autoconf,将它们写成@htmldir@@dvidir@等),提供多个文档翻译的包应该将它们安装在$(htmldir)/ll $(pdfdir)/ll等中,其中lllocale缩写,如enpt_BR

(5)libdir,存放目标文件和目标代码库的目录。不要在这里安装可执行文件,它们可能应该放在$(libexecdir)中。libdir的值通常应该是/usr/local/lib,但是要写成$(exec_ prefix)/lib。(如果您使用Autoconf,请将其写入@libdir@)。

(6)lispdir,用于安装此包中的任何Emacs Lisp文件的目录。默认情况下,它应该是/usr/local/share/emacs/site-lisp,但应该写成$(datarootdir)/emacs/site-lisp。如果您使用的是Autoconf,则将默认值写入@lispdir@。为了使@lispdir@工作,您需要在configure.ac文件中配置以下几行,

lispdir=’${datarootdir}/emacs/site-lisp’
AC_SUBST(lispdir)

(7)localedir,用于安装此包的特定于语言环境的消息编目的目录。默认情况下,它应该是/usr/local/share/locale,但它应该写成$(datarootdir)/locale。(如果您使用的是Autoconf,请将其写为@localedir@)。这个目录通常每个地区都有一个子目录。

unix风格的手册页是安装在以下其中一个:

(1)mandir,用于安装此包的手册页(如果有的话)的顶级目录。它通常是/usr/local/share/man,但您应该将其写为
$(datarootdir)/man。(如果您使用的是Autoconf,请将其写入@mandir@)。

(2)man1dir,第1节手册页的安装目录。写入$(mandir)/man1

(3)man2dir,用于安装第2节手册页的目录。写入$(mandir)/man2

不要让任何GNU软件的主要文档成为手册页。用Texinfo写一个手册。手册页只是为在Unix上运行GNU软件的人准备的,它只是一个次要的应用程序

(1)manext,已安装的手册页的文件扩展名。这应该包含一个句号后跟适当的数字;它通常应该是“.1”。

(2)man1ext,安装的第1节手册页的文件扩展名。

(3)man2ext,安装的第2节手册页的文件扩展名。

如果包需要在手册的多个部分中安装手册页,请使用这些名称而不是manext

最后,你应该设置以下变量:

(1)srcdir,正在编译的源代码的目录。该变量的值通常由configure shell脚本插入。(如果使用Autoconf,请使用srcdir = @srcdir@)。

例如下面实例:

# Common prefix for installation directories.
# NOTE: This directory must exist when you start the install.
prefix = /usr/local
datarootdir = $(prefix)/share
datadir = $(datarootdir)
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.
libexecdir = $(exec_prefix)/libexec
# Where to put the Info files.
infodir = $(datarootdir)/info

如果您的程序将大量文件安装到一个标准用户指定的目录中,那么将它们分组到该程序特定的子目录中可能会很有用。
如果您这样做,您应该编写安装规则来创建这些子目录。

不要期望用户在上面列出的任何变量的值中包含子目录名。为安装目录设置一组统一的变量名是为了使用户能够为几个不同的GNU包指定完全相同的值。为了使这一点有用,必须设计所有的包,以便在用户这样做时能够合理地工作。

有时,并非所有这些变量都可以在当前版本的Autoconf/Automake中实现,但在Autoconf 2.60中,我们相信它们都是。如果没有,这里的描述将作为Autoconf将实现的规范。作为一名程序员,您可以使用开发版本的Autoconf,也可以在支持这些变量的稳定版本发布之前避免使用这些变量。

7.7 用户标准目标

所有GNU程序都应该在它们的makefile文件中有以下目标:

(1)all,编译整个程序。这应该是默认目标。此目标不需要重新构建任何文档文件;信息文件通常应该包含在发行版中,只有在明确要求时才应该制作DVI(和其他文档格式)文件。

默认情况下,Make规则应该与-g进行编译和链接,以便可执行程序具有调试符号。否则,你在面对崩溃时基本上是无助的,而且用一个新的构建来复制它通常是很不容易的。

(2)install,编译程序并将可执行文件、库等复制到文件名中,以供实际使用。如果有一个简单的测试来验证程序是否正确安装,则此目标应该运行该测试。

安装可执行文件时不要剥离它们。这有助于以后可能需要的最终调试,现在磁盘空间很便宜,动态加载器通常确保在正常执行期间不加载调试部分。需要剥离二进制文件的用户可以调用install-strip目标来实现。

如果可能的话,编写安装目标规则,以便它不会修改构建程序的目录中的任何内容,前提是刚刚完成了make all。这对于在一个用户名下构建程序并在另一个用户名下安装程序非常方便。

如果要安装的文件还不存在,那么这些命令应该创建这些文件所在的所有目录。这包括作为变量prefixexec_prefix的值指定的目录,以及所需的所有子目录。一种方法是使用如下所述的installdirs目标。

在安装手册页的任何命令之前使用-,这样make将忽略任何错误。这是为了防止有些系统没有安装Unix手册页文档系统。

安装Info文件的方法是使用$(INSTALL_DATA)将它们拷贝到$(infodir)中,然后运行install-info程序,如果它存在的话。install-info是一个编辑Info dir文件以添加或更新给定Info文件的菜单项的程序,它是Texinfo包的一部分。

下面是一个安装Info文件的示例规则,它还尝试处理一些其他情况,例如install- Info不存在。

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

在编写安装目标时,必须将所有命令分为三类:普通命令(normal)、安装前命令(pre-installation)和安装后命令(post-installation)。

(3) install-html/install-dvi/install-pdf/install-ps,这些目标以Info以外的格式安装文档;如果需要这种格式,它们将由安装包的人显式调用。GNU更喜欢Info文件,所以这些文件必须由安装(install)目标安装。

当您有许多文档文件要安装时,我们建议您通过安排这些目标安装在适当的安装目录(如htmldir)的子目录中来避免冲突和混乱。例如,如果您的包有多个手册,并且您希望安装带有许多文件的HTML文档(例如makeinfo --HTMLsplit模式输出),那么您肯定希望使用子目录,否则不同手册中具有相同名称的两个节点将相互覆盖。

请使这些安装格式化(install-format)目标调用格式化目标的命令,例如,通过使format成为依赖项。

(4) uninstall,删除所有已安装的文件,如installinstall-*目标创建的副本。此规则不应修改执行编译的目录,而只应修改安装文件的目录。与安装命令一样,卸载命令分为三类。

(5)install-strip,类似于安装,但在安装时剥离可执行文件。在简单的情况下,这个目标可以以一种简单的方式使用安装目标:

install-strip:
	$(MAKE) INSTALL_PROGRAM=’$(INSTALL_PROGRAM) -s’ 
		install

但是,如果包安装脚本以及真正的可执行文件,安装条带目标不能仅仅引用安装目标;它必须剥离可执行文件,但不剥离脚本。

Install-strip不应该删除为安装而复制的构建目录中的可执行文件。它应该只剥离已安装的副本。

通常我们不建议剥离可执行程序,除非您确定程序没有错误。然而,安装一个剥离的可执行文件以供实际执行,同时将未剥离的可执行文件保存在其他地方,以防出现错误,这是合理的。

(6)clean,删除当前目录中通常通过构建程序创建的所有文件。也删除其他目录中的文件,如果它们是由这个makefile创建的。但是,请不要删除记录配置的文件。还要保留那些可以通过构建生成的文件,但通常不会这样做,因为它们是发行版附带的。

没有必要删除用mkdir -p创建的父目录,因为它们本来就可能存在。如果.dvi文件不是发行版的一部分,请删除它们。

(7) distclean,删除当前目录(或由该makefile创建)中通过配置或构建程序创建的所有文件。如果您解压缩了源代码并构建了程序,而没有创建任何其他文件,那么make distclean应该只留下发行版中的文件。但是,不需要删除用mkdir -p创建的父目录,因为它们可能已经存在了。

(8)mostlyclean,像clean一样,但可能会避免删除一些人们通常不想重新编译的文件。例如,GCC的mostlyclean目标不会删除libgcc.a。因为很少需要重新编译它,并且需要花费很多时间。

(9)maintainer-clean,删除几乎所有可以用这个Makefile重建的东西。这通常包括由distclean删除的所有内容,以及更多如Bison生成的C源文件、标记表、Info文件等等。

我们说“几乎所有”的原因是,运行命令make maintainer-clean不应该删除configure,即使configure可以使用Makefile中的规则进行重制。更一般地说,make maintainer-clean不应该删除为了运行configure并开始构建程序而需要存在的任何东西。另外,也不需要删除用mkdir -p创建的父目录,因为它们本来就可能存在。这些是唯一的例外,Maintainer-clean应该删除所有其他可以重建的东西。

maintainer-clean目标旨在供包的维护者使用,而不是普通用户使用。您可能需要特殊的工具来重建一些make maintainer-clean删除的文件。由于这些文件通常包含在发行版中,我们没有注意使它们易于重构。如果您发现您需要再次打开整个发行版,请不要责怪我们。

为了帮助用户了解这一点,用于特殊的维护人员清理目标的命令应该以以下两个命令开头:

@echo ’This command is intended for maintainers to use; it’
@echo ’deletes files that may need special tools to rebuild.’

(10)TAGS,更新这个程序的标签表。

(11)info,生成所需的任何Info文件。编写规则的最佳方法如下:

info: foo.info
foo.info: foo.texi chap1.texi chap2.texi
	$(MAKEINFO) $(srcdir)/foo.texi

您必须在Makefile中定义变量MAKEINFO。它应该运行makeinfo程序,它是Texinfo发行版的一部分。

通常,GNU发行版附带Info文件,这意味着Info文件存在于源目录中。因此,info文件的Make规则应该在源目录中更新它。当用户构建包时,Make通常不会更新Info文件,因为它们已经是最新的了。

(12)dvi/html/pdf/ps,生成给定格式的文档文件。这些目标应该始终存在,但是如果不能生成给定的输出格式,则任何目标或所有目标都可以是no-op。这些目标不应该是所有目标的依赖项;用户必须手动调用它们。

下面是一个从Texinfo生成DVI文件的示例规则:

dvi: foo.dvi

foo.dvi: foo.texi chap1.texi chap2.texi
	$(TEXI2DVI) $(srcdir)/foo.texi

您必须在Makefile中定义变量TEXI2DVI。它应该运行texi2dvi程序,它是Texinfo发行版的一部分。(texi2dvi使用来完成真正的格式化工作。TEX不是随Texinfo一起分发的)。或者,只编写依赖项,并允许GNU make提供命令。

下面是另一个例子,这是从Texinfo生成HTML:

html: foo.html
foo.html: foo.texi chap1.texi chap2.texi
	$(TEXI2HTML) $(srcdir)/foo.texi

同样,您将在Makefile中定义变量TEXI2HTML,例如,它可以运行makeinfo ——no-split ——html(makeinfo是Texinfo发行版的一部分)。

(13)dist,为这个程序创建一个发行版tar文件。应该设置tar文件,以便tar文件中的文件名以子目录名开头,该子目录名是它作为发行版的包的名称。该名称可以包含版本号。

例如,GCC版本1.40的发行tar文件解压缩到名为GCC-1.40的子目录中。

最简单的方法是创建一个适当命名的子目录,使用ln或cp在其中安装适当的文件,然后对该子目录进行tar。使用gzip压缩tar文件。实际发布文件的1.40版本GCC命名为GCC -1.40.tar.gz。支持其他自由压缩格式也是可以的。

dist目标应该显式依赖于发行版中的所有非源文件,以确保它们在发行版中是最新的。

(14)check,进行自检(如果有的话)。用户必须在运行测试之前构建程序,但不需要安装程序;您应该编写自测试,以便它们在构建但未安装程序时工作。

以下目标建议作为常规名称,用于它们有用的程序:

(1)installcheck,执行安装测试(如果有的话)。用户必须在运行测试之前构建并安装程序。您不应该假设$(bindr)在搜索路径中。

(2)installdirs,添加一个名为installdirs的目标来创建安装文件的目录及其父目录是很有用的。有一个名为mkinstalldirs的脚本可以方便地完成这个任务,您可以在Gnulib包中找到它。你可以使用这样的规则:

# Make sure all installation directories (e.g. $(bindir))
# actually exist by making them if necessary.
installdirs: mkinstalldirs
    $(srcdir)/mkinstalldirs $(bindir) $(datadir) 
        $(libdir) $(infodir) 
        $(mandir)	

或者,如果您希望支持DESTDIR(强烈建议):

# Make sure all installation directories (e.g. $(bindir))
# actually exist by making them if necessary.
installdirs: mkinstalldirs
    $(srcdir)/mkinstalldirs 
        $(DESTDIR)$(bindir) $(DESTDIR)$(datadir) 
        $(DESTDIR)$(libdir) $(DESTDIR)$(infodir) 
        $(DESTDIR)$(mandir)

此规则不应修改执行编译的目录。它应该只创建安装目录。

7.8 安装命令类别

在编写安装目标时,必须将所有命令分为三类:普通命令、安装前命令和安装后命令。

  • 普通命令将文件移动到适当的位置,并设置其模式。它们不能修改任何文件,除了那些完全来自它们所属的包的文件。

  • 安装前和安装后的命令可能会修改其他文件;特别是,它们可以编辑全局配置文件或数据库。

  • 安装前命令通常在正常命令之前执行,安装后命令通常在正常命令之后执行。

安装后命令最常见的用法是运行install-info。这不能用普通命令完成,因为它改变的文件(Info目录)并不完全和完全来自正在安装的包。这是一个安装后命令,因为它需要在安装包的普通命令之后执行信息文件。

大多数程序不需要任何预安装命令,但我们有这个功能,以防万一需要它。

要将安装规则中的命令划分为这三个类别,请在其中插入类别行。类别行指定后面命令的类别。

类别行由制表符和对特殊Make变量的引用以及末尾的可选注释组成。你可以使用三个变量,每个类别一个,变量名指定类别。在普通执行中,类别行是无操作的,因为这三个Make变量通常是未定义的(您不应该在makefile中定义它们)。

下面是三个可能的分类行,每个都有一个解释其含义的注释:

$(PRE_INSTALL) # Pre-install commands follow.
$(POST_INSTALL) # Post-install commands follow.
$(NORMAL_INSTALL) # Normal commands follow.

如果在安装规则的开头不使用类别行,那么在第一个类别行出现之前,所有命令都被分类为正常。如果不使用任何类别行,则所有命令都被分类为正常。以下是要卸载的类别行:

$(PRE_UNINSTALL) # Pre-uninstall commands follow.
$(POST_UNINSTALL) # Post-uninstall commands follow.
$(NORMAL_UNINSTALL) # Normal commands follow.

通常,将使用预卸载命令从Info目录中删除条目。如果安装或卸载目标有任何作为安装子例程的依赖项,那么您应该用一个类别行启动每个依赖项的命令,并且也用一个类别行启动主目标的命令。这样,无论实际运行的是哪个依赖项,您都可以确保每个命令都被放置在正确的类别中。

安装前和安装后的命令不应该运行任何程序,除了这些:

[ basename bash cat chgrp chmod chown cmp cp dd diff echo
egrep expand expr false fgrep find getopt grep gunzip gzip
hostname install install-info kill ldconfig ln ls md5sum
mkdir mkfifo mknod mv printenv pwd rm rmdir sed sort tee
test touch true uname xargs yes

以这种方式区分命令的原因是为了制作二进制包。通常,二进制包包含所有需要安装的可执行文件和其他文件,并且有自己的安装方法,因此不需要运行正常的安装命令。但是安装二进制包确实需要执行安装前和安装后命令。

构建二进制包的程序通过提取安装前和安装后命令来工作。下面是提取预安装命令的一种方法(需要-s选项来静默关于进入子目录的消息):

make -s -n install -o all 
    PRE_INSTALL=pre-install 
    POST_INSTALL=post-install 
    NORMAL_INSTALL=normal-install 
| gawk -f pre-install.awk

其中文件预安装。Awk可以包含以下内容:

$0 ~ /^(normal-install|post-install)[ 	]*$/ {on = 0}
on {print $0}
$0 ~ /^pre-install[ 	]*$/ {on = 1}
7.9 制作发布

您应该用一对版本号来标识每个版本,一个主要版本和一个次要版本。我们不反对使用两个以上的数字,但你不太可能真的需要它们。将Foo version 69.96打包到一个名为Foo-69.96.tar.gz的压缩tar文件中。它应该解压缩到一个名为foo-69.96的子目录中。

构建和安装程序不应该修改发行版中包含的任何文件。这意味着以任何方式构成程序一部分的所有文件必须分为源文件和非源文件。源文件是由人类编写的,永远不会自动更改;非源文件是由Makefile控制下的程序从源文件生成的。

发行版应该包含一个名为README的文件,其中包含软件包的总体概述:

  • 包的名称。
  • 包的版本号,或指在包中可以找到版本的位置。
  • 对包装功能的一般描述。
  • 对文件INSTALL的引用,其中应该包含对安装过程的解释。
  • 任何不寻常的顶级目录或文件的简要解释,或其他提示读者找到他们的方式在源代码。
  • 对包含复制条件的文件的引用。如果使用了GNU GPL,应该在一个名为“COPYING”的文件中。如果使用GNU LGPL,它应该在一个名为copy.lesser的文件中。

当然,所有的源文件都必须在发行版中。在发行版中包含非源文件以及生成它们的源文件是可以的,只要它们与生成它们的源文件是最新的,并且与机器无关,这样发行版的正常构建就永远不会修改它们。我们通常包含Autoconf、Automake、Bison、flex、TEX和makeinfo生成的非源文件;这有助于避免发行版之间不必要的依赖,这样用户就可以安装他们喜欢的任何版本的软件包。不要轻易地诱导对其他软件的新依赖。

可能在构建和安装程序时被实际修改的非源文件不应该包含在发行版中。因此,如果要发布非源文件,在发布新版本时一定要确保它们是最新的。

确保发行版中的所有文件都是全球可读的,并且目录是全局可读(world-readable)和全局可搜索(world-searchable)(八进制模式755)。我们过去常常建议发行版中的所有目录都是全局可写的(八进制模式777),因为旧版本的tar在以非特权用户提取存档时将无法处理。但是,在创建存档时,这很容易导致安全问题,所以现在我们建议不要这样做

不要在发行版中包含任何符号链接。如果tar文件包含符号链接,那么人们甚至无法在不支持符号链接的系统上解压缩它。另外,不要为不同目录中的一个文件使用多个名称,因为某些文件系统无法处理这种情况,这会阻止解压缩发行版。

尽量确保所有的文件名在MS-DOS上是唯一的。一个名字MS-DOS由最多8个字符组成,可选后跟一个句点和最多3个字符。MS-DOS将截断句号前后的额外字符。因此,foobarhacker.cfoobarhacker.o不模棱两可,它们被截断为foobarha.cfoobarha.o,它们是不同的。

在您的发行版中包含texinfo.tex的副本,其用于测试打印任何*.texinfo*.texi文件。同样,如果您的程序使用小型GNU软件包,如regexgetoptobstacktermcap,请将它们包含在发行文件中。将它们排除在外会使发行文件更小,但代价是可能给不知道要获取哪些其他文件的用户带来不便。

8. 引用非自由软件和文档
8.1 自由软件的道德思想

GNU程序不应该推荐、促进或授予使用任何非自由程序的合法性。专有软件是一个社会和道德问题,我们的目标是结束这个问题。我们不能阻止一些人编写专有程序,或者阻止其他人使用它们,但是我们可以而且应该拒绝向新的潜在客户宣传它们,或者拒绝给公众留下它们存在是合法的印象。

自由软件的GNU定义可以在GNU网站上找到,自由文档的定义可以在https://www.gnu.org/philosophy/free-doc.html找到。本文档中使用的术语“free”和“non-free”是指那些定义。

重要许可证的列表以及它们是否符合免费的条件见https://www.gnu.org/licenses/license-list.html。如果不清楚一个许可证是否符合自由的条件,请写信给[email protected]询问GNU工程。我们会回答,如果许可证是重要的,我们会将其添加到列表中。

当一个非自由的程序或系统是众所周知的,您可以顺便提到它,这是无害的,因为可能想要使用它的用户可能已经知道它了。例如,解释如何在一些广泛使用的非自由操作系统上构建您的包,或者如何与一些广泛使用的非自由程序一起使用它,在首先解释如何在GNU系统上使用它之后,这是很好的。

但是,您应该只提供必要的信息,以帮助那些已经使用非自由软件的人与它一起使用您的程序,不要提供或引用任何关于专有程序的进一步信息,也不要暗示专有程序增强了您的程序,或者它的存在在任何方面都是一件好事。目标应该是已经在使用专有程序的人将得到他们需要的关于如何与它一起使用您的自由程序的建议,而那些还没有使用专有程序的人将看不到任何可能导致他们对它感兴趣的东西。

你不应该为非自由程序推荐任何非自由的附加组件,但是可以提到帮助它与你的程序一起工作的免费附加组件,以及如何安装免费附加组件,即使这需要运行一些非自由程序。

如果一个非自由程序或系统在您的程序领域中是模糊的,您的程序不应该提及或支持它,因为这样做会倾向于普及非自由程序,而不是普及您的程序。(如果想要使用您的程序的人通常不知道Foobar的存在,那么您就不能指望在Foobar的用户中为您的程序找到许多其他用户)。

有时一个程序本身是自由软件,但它依赖于一个非自由平台来运行。例如,过去很多Java程序依赖于一些非自由的Java库。(见https://www.gnu.org/philosophy/java-trap.html)。推荐或推广这样一个节目就是推广它所需要的其他节目;因此,法官提到前者就好像提到后者一样。出于这个原因,我们小心翼翼地在自由软件目录中列出Java程序:我们希望避免推广非自由的Java库。

Java不再有这个问题,但总的原则将保持不变: 不推荐、推广或合法化依赖于非自由软件运行的程序

一些自由软件强烈鼓励使用非自由软件。一个典型的例子就是mplayer。它本身就是自由软件,自由代码可以处理某些类型的文件。
然而,mplayer建议使用非免费的编解码器来处理其他类型的文件,并且安装mplayer的用户很可能会同时安装这些编解码器。实际上,推荐mplayer是为了促进非自由编解码器的使用。

因此,你不应该推荐那些强烈鼓励使用非自由软件的程序。这就是为什么我们没有在自由软件目录中列出mplayer。

GNU软件包不应该让用户参考任何自由软件的非自由文档。可以包含在自由操作系统中的自由文档对于完成GNU系统或任何自由操作系统是必不可少的,因此鼓励它是优先考虑的; 推荐使用我们不允许包含的文档会破坏社区产生我们可以包含的文档的动力。因此GNU软件包不应该推荐非自由文档。

相比之下,在一个程序的注释中引用期刊文章和教科书来解释它是如何工作的是可以的,即使它们是非自由的。这是因为我们不会在GNU系统中包含这些东西,即使它们是免费的,它们超出了软件发行版需要包含的范围。

引用描述或推荐非自由程序的网站是在推广该程序,因此请不要链接(或提及名称)包含此类材料的网站。这个策略特别适用于GNU软件包的网页。

那么链接链呢?点击几乎任何网站的链接都可能最终导致非自由软件的推广;这是网络固有的特性。我们是这样对待的。

你不应该参考AT&T的网站,如果它推荐AT&T的非自由软件包;你不应该引用链接到AT&T网站的页面p,因为页面p本身就是推荐和合法化非自由程序的部分。

但是,如果p包含指向AT&T网站的链接,用于其他目的(例如长途电话服务),则没有理由不链接到p

如果一个网页需要用户运行该程序才能使用该网页,那么它会以一种隐式但特别强烈的方式推荐该程序。许多页面包含Javascript代码,他们以这种方式推荐。这段Javascript代码可能是自由的,也可能是非自由的,但通常情况下是非自由的。

如果不运行非自由Javascript代码就不能实现引用页面的目的,那么就不应该引用它。因此,如果引用该页面的目的是让人们查看视频或订阅邮件列表,而如果用户的浏览器阻止了非自由Javascript代码,则查看或订阅无法工作,则不要引用该页面。

极端的情况是那些依赖非免费Javascript代码来查看页面内容的网站。任何托管在wix.com上的网站都有这个问题,其他一些网站也是如此。向人们推荐这些页面来阅读它们的内容,实际上是在敦促他们运行那些非自由程序,所以请不要推荐这些页面。(这样的页面也会破坏网络,因此它们应该受到谴责,原因有二)。

相反,请从页面中引用摘录来说明你的观点,或者找另一个地方引用这些信息。

8.2 GNU Free Documentation License

原文请参考standards.pdf (gnu.org)第8章内容。

		Appendix A GNU Free Documentation License
			Version 1.3, 3 November 2008
Copyright c 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
https://fsf.org/

Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

0. 前序(PREAMBLE)

本许可证的目的是使手册、教科书或其他功能和有用的文档在自由的意义上是自由的:确保每个人都有有效的自由来复制和重新发布它,无论是否修改它,无论是商业还是非商业。其次,本许可证为作者和出版者保留了一种获得作品荣誉的方式,同时不被认为对其他人所做的修改负责。

本许可证是一种"copyleft”,这意味着文档的衍生作品本身必须在同样的意义上是自由的。它是对GNU通用公共版的补充许可证,这是一个为自由软件设计的copyleft许可证。

我们设计本许可证是为了将它用于自由软件的手册,因为自由软件需要自由的文档:一个自由的程序应该附带提供与该软件相同的自由的手册。但本许可证并不局限于软件手册;它可以用于任何文本工作,无论主题或是否作为印刷书籍出版。我们主要将此授权推荐给以指导或参考为目的的作品。

1. 效力与定义(APPLICABILITY AND DEFINITIONS)

本许可证适用于任何媒介上的任何手册或其他作品,只要该作品包含版权所有者发布的声明,说明它可以根据本许可证的条款进行分发。这样的通知授予在此所述条件下使用该作品的全球性、免版税、无限期的许可。下文的“文件”是指任何此类手册或作品。任何公众成员都是被许可人,并被称为“您”。如果您以版权法下需要许可的方式复制、修改或分发作品,则表示您接受该许可。

文件的“修改版本”是指包含文件或其部分内容的任何作品,无论是逐字复制,还是经过修改和/或翻译成另一种语言。

“次要部分”是文档的命名附录或前端内容部分,专门处理文档的发布者或作者与文档总体主题(或相关事项)的关系,并且不包含任何可以直接属于该总体主题的内容。(因此,如果文件的一部分是数学教科书,第二部分可能不解释任何数学。)这种关系可以是与主题或相关事项的历史联系,也可以是关于它们的法律、商业、哲学、伦理或政治立场。

“不变章节”是某些次要章节,其标题被指定为在声明文档已经发布的通知中,是那些不变章节在本许可证下。如果一个章节不符合上述二级的定义,那么它就是二级的不允许被指定为不变式。文档可以不包含不变量部分。如果文档没有标识任何不变节,那么就没有。

“封面文本”是列出的某些短段落的文本,作为前封面文本或封底文本,在声明文件根据本许可证发布的通知中。封面文字最多可以有5个单词,封底文字最多可以有25个单词。

文件的“透明”副本是指一种机器可读的副本,以一种公众可获得的格式表示,这种格式适用于使用通用文本编辑器或(对于由像素组成的图像)通用绘画程序或(对于绘图)某些广泛使用的绘图编辑器直接修改文档,并且适用于输入文本格式化器或自动翻译为适合输入文本格式化器的各种格式。以透明文件格式制作的副本,其标记(或没有标记)已被安排以阻止或阻止读者的后续修改,则不是透明的。如果用于大量文本,图像格式就不是透明的。非“透明”的副本称为“不透明”。

透明副本的合适格式示例包括没有标记的纯ASCII、Texinfo输入格式、LaTEX输入格式、使用公开可用DTD的SGML或XML,以及为人为修改而设计的符合标准的简单HTML、PostScript或PDF。透明图像格式的例子包括PNG、XCF和JPG。不透明格式包括只能由专有文字处理器读取和编辑的专有格式、DTD和/或处理工具通常不可用的SGML或XML,以及由某些文字处理器生成的仅用于输出目的的机器生成的HTML、PostScript或PDF。

对于印刷书籍,“扉页”是指扉页本身,以及用于清晰地容纳本许可证要求出现在扉页上的材料的下列页面。对于没有标题页的作品,“标题页”是指在作品标题最显眼的地方,在正文开始之前的文本。

“发布者”系指向公众分发本文件副本的任何个人或实体。

“标题为XYZ”的部分是指文档的命名子单元,其标题精确地为XYZ,或者在将XYZ翻译成另一种语言的文本后面的括号中包含XYZ。(这里XYZ代表下面提到的特定部分名称,例如“致谢”、“奉献”、“背书”或“历史”。)当您修改文档时,“保留这样一个部分的标题”意味着根据这个定义,它仍然是一个“标题为XYZ”的部分。

文件可以在声明本许可证适用于文件的通知旁边包括保证免责声明。这些保证免责声明被视为包含在本许可证中,但仅涉及放弃保证:这些保证免责声明可能具有的任何其他含义都是无效的,并且对本许可证的含义没有影响。

2. 逐字的复制(VERBATIM COPYING)

您可以在任何媒介上复制和分发文档,无论是商业的还是非商业的,前提是本许可证、版权声明以及说明本许可证适用于本文档的许可证通知在所有副本中都被复制,并且您没有在本许可证的那些条件中添加任何其他条件。您不得使用技术手段阻碍或控制您制作或分发的副本的阅读或进一步复制。但是,您可以接受补偿,以换取副本。如果您发布了足够多的副本,您还必须遵守第3节中的条件。

您也可以在上述相同条件下出借副本,并且您可以公开展示副本。

3. 大量地复制(COPYING IN QUANTITY)

如果您发布文档的印刷副本(或通常具有印刷封面的媒体副本),数量超过100个,并且文档的许可声明要求封面文字,则您必须将副本装入封面中,并清晰易读地携带所有这些封面文字:封面上的前封面文字,封底上的后封面文字。这两个封面也必须清楚清楚地表明你是这些副本的出版商。封面必须呈现完整的标题,标题的所有单词同样突出和可见。你可以在封面上添加其他材料。只要保留文件的标题并满足这些条件,仅限于封面的复制就可以被视为在其他方面的逐字复制。

如果任何一个封面所需的文字都太大而无法清晰地容纳,您应该将列出的第一个(尽可能多地适合)放在实际封面上,并将其余的继续放在相邻的页面上。

如果您发布或分发文档的不透明副本的数量超过100个,则您必须在每个不透明副本中包含一份机器可读的透明副本,或者在每个不透明副本中或在每个不透明副本中声明一个计算机网络位置,以便一般使用网络的公众可以使用公共标准网络协议从该位置下载文档的完整透明副本,且不添加任何材料。如果您使用后一种选择,当您开始大量分发不透明副本时,您必须采取合理的谨慎措施,以确保在您最后一次向公众分发该版本的不透明副本(直接或通过您的代理商或零售商)一年后,该透明副本在指定地点仍可获得。

请求,但不是必须,您在重新分发任何大量副本之前与文件的作者联系,让他们有机会为您提供文件的更新版本。

4. 修改(MODIFICATIONS)

您可以在上述第2节和第3节的条件下复制和分发文件的修改版本,前提是您完全按照本许可证发布修改版本,并且修改版本承担文件的角色,从而将修改版本的分发和修改许可给任何拥有其副本的人。此外,您必须在修改版本中做这些事情:

  1. 在扉页(和封面,如果有的话)使用与正文不同的标题文档,并从以前的版本(如果有的话,应该在文档的历史部分列出)。如果该版本的原始出版商给予许可,您可以使用与先前版本相同的标题。
  2. 作为作者,在标题页上列出一个或多个负责修改版本的作者身份的个人或实体,以及至少五位文件的主要作者(如果少于五位,则为所有主要作者),除非他们免除了此要求。
  3. 在标题页写明修改版本的发布者的名称,作为发布者。
  4. 保存文件的所有版权声明。
  5. 在其他版权声明旁边为您的修改添加适当的版权声明。
  6. 在版权声明之后,立即附上一份许可声明,允许公众在本许可的条款下使用修改后的版本,格式如下面的附录所示。
  7. 在该许可通知中保留不变章节的完整列表和所需的封面文档许可声明中给出的文本。
  8. 包括一份未经修改的本许可证副本。
  9. 保留标题为“历史”的部分,保留其标题,并在其中添加一个项目,至少说明标题页上给出的修改版本的标题,年份,新作者和出版商。如果文档中没有标题为“历史”的部分,则创建一个说明文档标题页上给出的标题、年份、作者和出版商的部分,然后添加一个描述前面句子中所述的修改版本的项。
  10. 保留文档中给出的网络位置(如果有的话),以供公众访问文档的透明副本,同样地,保留文档中给出的先前版本所基于的网络位置。这些可以放在“历史”一节。您可以省略在文档本身发布至少四年之前发布的作品的网络位置,或者如果它所引用的版本的原始出版商给予许可。
  11. 对于任何标题为“致谢”或“奉献”的部分,保留该部分的标题,并在该部分中保留每个贡献者致谢和/或奉献的所有内容和语气。
  12. 保留文件中所有不变章节,文本和标题保持不变。章节编号或同等内容不被视为章节标题的一部分。
  13. 删除任何标题为“背书”的部分。该部分不得包括在修改版本中。
  14. 不要将任何现有章节重新命名为“背书”,也不要将标题与任何不变章节冲突。
  15. 保留任何保证免责声明。

如果修改版本包含新的前置性章节或附录,这些章节或附录符合次要章节的资格,并且不包含从文档复制的材料,您可以选择指定这些章节中的一些或全部为不变章节。要做到这一点,将它们的标题添加到修改版本许可声明中的不变章节列表中。这些标题必须区别于任何其他章节标题。

您可以添加一个标题为“认可”的部分,只要它只包含各方对您的修改版本的认可-例如,同行评审的声明或文本已被某个组织批准为标准的权威定义。

您可以在修改版本的封面文本列表的末尾添加一段最多五个单词的前封面文本,以及一段最多25个单词的后封面文本。任何一个实体(或通过其安排)只能增加一段封面文字和一段封底文字。如果文件已包含由你或由你所代表的同一实体所作安排而先前添加的同一封面的封面文字,则你不得再添加另一封面文字;但是,您可以替换旧版本,但必须得到添加旧版本的前一个出版商的明确许可。

文档的作者和发布者不允许使用他们的名字进行宣传,或声称或暗示对任何修改的认可的版本。

5. 组合文件(COMBINING DOCUMENTS)

您可以将本文档与在本许可证下发布的其他文档结合起来,根据上面第4节中为修改版本定义的条款,只要您在组合中包含所有原始文档的所有不变部分,未经修改,并在其许可声明中将它们全部列为组合作品的不变部分,并且您保留所有它们的保证免责声明。

合并后的作品只需要包含本许可证的一个副本,并且多个相同的不变章节可以用一个副本替换。如果有多个具有相同名称但内容不同的不变章节,则通过在其末尾添加括号中已知的该章节的原作者或出版商的名称,或其他唯一数字,使每个此类章节的标题唯一。对合并作品的许可声明中恒常章节列表中的章节标题进行相同的调整。

在合并时,您必须将各种原始文件中标题为“历史”的任何部分合并,形成一个标题为“历史”的部分;同样地,将任何标题为“致谢”的部分和任何标题为“奉献”的部分结合起来。您必须删除所有标题为“背书”的部分。

6. 文件集合(COLLECTIONS OF DOCUMENTS)

您可以将本文件和在本许可证下发布的其他文件组成一个集合,并将本许可证在各种文件中的单个副本替换为包含在集合中的单个副本,前提是您遵循本许可证的规则,在所有其他方面逐字复制每个文件。

您可以从这样的集合中提取单个文档,并在本许可证下单独分发它,只要您在提取的文档中插入本许可证的副本,并在有关该文档的逐字复制的所有其他方面遵循本许可证。

7. 独立作品的聚合(AGGREGATION WITH INDEPENDENT WORKS)

将文件或其衍生文件与其他单独和独立的文件或作品汇编在存储或分发介质的卷中或在卷上,如果汇编产生的版权不用于限制汇编用户的合法权利超出单个作品允许的范围,则称为“集合”。当文档包含在集合中时,本许可不适用于集合中其他本身不是文档派生作品的作品。

如果第3条的封面文字要求适用于这些文件副本,那么如果文件小于整个集合体的一半,则文件的封面文字可以放置在集合体内支撑文件的封面上,或者如果文件是电子形式的,则可以放置在电子等价物的封面上。否则,它们必须出现在支撑整个聚集体的印刷封面上。

8. 翻译(TRANSLATION)

翻译被认为是一种修改,因此您可以根据第4节的条款发布文档的翻译。用翻译替换不变章节需要获得其版权所有者的特别许可,但是除了这些不变章节的原始版本之外,您可以包括部分或所有不变章节的翻译。您可以在文件中包括本许可证、所有许可证声明和任何保证免责声明的翻译,前提是您还包括本许可证的原始英文版本以及这些声明和免责声明的原始版本。如果本许可证的翻译版本与原版本、通知或免责声明有不一致之处,以原版本为准。

如果文件中的某部分标题为“致谢”、“奉献”或“历史”,则要求(第4节)保留其标题(第1节)通常需要更改实际标题。

9. 结尾(TERMINATION)

除非本许可证明确规定,否则您不得复制、修改、再许可或分发本文件。任何以其他方式复制、修改、再许可或分发它的企图都是无效的,并且将自动终止您在本许可下的权利。

但是,如果您停止所有违反本许可的行为,那么您从特定版权所有者处获得的许可将(a)暂时恢复,除非版权所有者明确并最终终止您的许可,以及(b)永久恢复,如果版权所有者未能在终止后60天内以某种合理的方式通知您违规行为。

此外,如果版权所有者以某种合理的方式通知您违反了本许可证,这是您第一次从该版权所有者那里收到违反本许可证的通知(对于任何作品),并且您在收到通知后30天内纠正了违规行为,则您从特定版权所有者处获得的许可将永久恢复。

终止您在本节项下的权利并不会终止从您处获得本许可的副本或权利的各方的许可。如果您的权利已被终止且未永久恢复,则收到部分或全部相同材料的副本并不赋予您使用该材料的任何权利。

10. 本许可证的未来修订版(FUTURE REVISIONS OF THIS LICENSE)

自由软件基金会可以发布GNU自由软件的新修订版本的文件许可。这些新版本将在精神上与当前版本相似,但可能在细节上有所不同,以解决新的问题或关注点。见https://www.gnu.org/licenses/。

许可证的每个版本都有一个不同的版本号。如果文档指定本许可证的特定编号版本“或任何更新版本”适用于它,您可以选择遵循该指定版本或自由软件基金会发布的任何更新版本(不是草案)的条款和条件。如果文档没有指定本许可证的版本号,您可以选择自由软件基金会曾经发布过的任何版本(不是草稿)。如果文件指定代理可以决定本许可证的哪个未来版本可以被使用,那么该代理接受某个版本的公开声明将永久授权您为文件选择该版本。

11. 重新获得许可证( RELICENSING)

“大规模多作者协作站点”(或“MMC站点”)指任何世界性的发布受版权保护的作品并为任何人编辑这些作品提供显著便利的Web服务器。任何人都可以编辑的公共wiki就是这种服务器的一个例子。本网站包含的“大规模多作者合作”(或“MMC”)是指在MMC网站上发布的任何一组具有版权的作品。

“CC-BY-SA”是指由Creative Commons Corporation(一家主要营业地点位于加利福尼亚州旧金山的非营利公司)发布的知识共享署名-相同方式共享3.0许可协议,以及该组织发布的该许可协议的未来copyleft版本。

“合并”系指作为另一文件的一部分,全部或部分地发布或重新发布一份文件。

一个MMC“有资格获得再授权”,如果它是在本许可证下授权的,并且如果所有作品在本许可证下首次在其他地方发布,随后全部或部分并入MMC,(1)没有封面文本或不变章节,并且(2)因此在2008年11月1日之前并入MMC。

MMC网站的运营商可以重新发布包含在以下网站中的MMC,CC-BY-SA在2009年8月1日之前的任何时间在同一地点,只要MMC有资格重新颁发许可证。

8.3 添加许可证

要在您编写的文档中使用本许可证,请在文档中包含一份许可证副本,并在标题页后面放置以下版权和许可证声明:

Copyright (C) year your name.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
Texts. A copy of the license is included in the section entitled ‘‘GNU
Free Documentation License’’.

如果你有固定章节,前封底文字和后封底文字,替换“with…Texts“。一行是这样的:

with the Invariant Sections being list their titles, with
the Front-Cover Texts being list, and with the Back-Cover Texts
being list.

如果你有没有封面文本的不变章节,或者这三者的其他组合,将这两种选择合并以适应情况。如果您的文档包含重要的程序代码示例,我们建议在您选择的自由软件许可证下并行发布这些示例,例如GNU通用公共许可证,允许它们在自由软件中使用。