这是针对英文原版页面的中文翻译。

GCC运行库例外的理由和常见问题解答

引言

2007年6月29日,自由软件基金会发布了GPLv3。它马上被15个GNU项目采纳,在随后的几个月内有更多的项目切换到了该许可证。GCC的大多数代码在4.2.2版本发布时都采用了新的许可证,现在我们正在对此进行收尾。

有些伴随GCC的软件库的许可证还没有变更。这些软件库自动被GCC产生的目标代码使用。因此,如果只简单允许这些库按照GPL发布,那么GCC产生的所有目标代码都将需要按照同样的条款发布。然而,FSF很久以前就决定允许开发者使用GCC的软件库编译任何程序,无论该程序使用何种许可证。开发非自由软件对社会不利,而且我们也没有义务使之更容易。我们允许这样做是因为禁止它看来是适得其反,另外的原因是因为使用了其他小软件库而限制GCC的使用看来是抓了芝麻丢了西瓜。

所以,这些软件库一直是许可证例外,该例外允许人们将使用GCC产生的目标代码用任何许可证发布。我们现在将这些软件库的许可证改到GPLv3,并更新这些例外。我们的基本政策没有变化;新的许可证还是允许按照以前的方式使用GCC。不过,我们决定利用这个机会更新例外达成3个目的:

  • 利用GPLv3的新条款。GPLv3有好几个有利于所有软件的新条款。这其中包括第7节,它构建了一个提供许可证例外的框架。为了使GCC能够最大范围地从GPLv3获益,我们需要使用第7节的语言考虑这些新条款并更新例外。

  • 奠定GCC插件架构的基础。长期以来,GCC的开发者一直在考虑为编译器添加一个插件框架。这会让大家为GCC项目做贡献变得更容易,并且也会加速GCC新编译技术的开发。然而,其中也存在着对不择手段的开发者的担心,他们写的插件可能会调用专有软件改变编译后的代码—这实际上就是给GCC添加了专有的扩展并挫败GPL的目标。更新后的例外会防止这种滥用,让GCC团队能够开始展望插件开发。

  • 促使GCC代码的例外整体上一致。经年累月,随着需要许可证例外的文件添加到GCC之中,我们不断审查和更新我们的用词以澄清这些例外并涵盖新的问题。由此导致GCC中现在有许多不同的例外文字,它们提供的基本许可都是一样的。现在,所有这些文件都可以使用我们拟定好的单一新例外文字,这使代码的法律审核变得更容易。

正如GPLv3,我们草拟此文时努力听取了多方用户的意见,并对这些意见做出了适当的处理。总而言之,我们为此花费了超过一年的时间。自由软件基金会和GCC执行委员会感谢软件自由法律中心的Richard Fontana、Bradley Kuhn和Karen Sandler,感谢他们对此例外所做的所有辛勤努力和协助。这些更新会强化GCC社区,我们期待它为编译器的开发打开新的篇章。

GCC对开发者是如此关键,我们料想他们对此更改会有问题,我们希望这些问题都有应对。下面,我们列举了用户可能会有的担忧。如果你关于此例外的问题没有列出,请随时通过<licensing@fsf.org>联系我们。

例外是怎么回事

你需要的许可—用GCC库把代码转换成按照你的许可证发布的目标代码—主要在第1节中:

你有权传播由独立模块和运行库组合而成的目标代码作品,即使该传播从其他方面来看可能违反了GPLv3的条款,前提是所有的目标代码都是经由合法的编译过程产生的。那么你可以为该组合使用你选择的许可证条款,只要它和独立模块的许可证一致。

本节使用了很多术语,这些术语的特定含义和例外如何操作不可分割。本节详解这些术语和常见场景的关系。

当你编写软件时,软件就包含了一系列源代码文件。如果一个文件不包含GCC库里的源代码,那么这个文件就是一个“独立模块”。

当你编译这些源代码文件时,它们通常会经历一系列步骤:源代码生成、预处理、编译成低级代码、汇编和连接。根据所用的语言和软件编写的方式,有些项目可能没有以上所有的步骤,但是它们总会按照这个顺序执行,使用GCC的人会按照这个步骤从高级语言编译到诸如汇编或Java bytecode1。在这个阶段,GCC把你的代码和GCC库合并或连接起来。我们称之为“编译过程。只要此时的输出不是编译器还要用的过渡代码,也不是编译器要输出的过渡代码,”此时的输出就叫做“目标代码。”

要想利用本许可,产生目标代码的编译过程必须“合法”,就是说其中没有引入和GCC以及GPL不兼容的软件。重要的一点是编译过程从你把任何高级语言代码输入给GCC就开始,一旦输出了目标代码就结束。因此,只要GCC没有输出过渡代码,即使你用其他GPL不兼容的汇编器、连接器或者高级语言产生工具和GCC一起工作,你的编译过程还可以是合法的:这些GPL不兼容工具按照我们的定义不算参与编译过程。只有一个地方你不能使用这些GPL不兼容的软件,这就是当GCC在进行核心编译工作的时候。

所以,如果你用了GCC,不管有没有GPL不兼容的软件,编译过程都可以是合法的。如果你只用了GPL兼容的编译工具,编译过程也是合法的。(即使使用不同的编译器,人们也常常会为GNU/Linux软件连接GCC库。)不过,如果你在把高级语言代码转换成低级语言代码的过程中用了GCC加上GPL不兼容的工具,那么这就不是一个合法的编译过程。比如,你使用GCC加上一个专有的插件就是这么一个非法编译过程。

只要编译过程是合法的,那么你有权为GCC产生的目标代码的发布“选择你的条款。”

如果你在编译过程中使用了GPL不兼容的工具,那么你不能使用这项权利。由于GCC产生的目标代码都来自GPL软件库,所以如果要发布这些目标代码就要遵循GPL的条款。你不能使用GCC开发你自己的GPL不兼容软件。

常见问题解答

我使用的是GCC的标准发布版(比如由FSF提供的,或者是操作系统自带的),我用它编译GPL不兼容软件。例外的更改对我有什么影响?

此次更改不会影响你。除非你把GCC配置成输出过渡代码—这种情况很少见—新的例外是要确保你这样做时没有违反许可证,正如老的例外一样。

这个变更会影响哪些人?

目前使用GCC的人应该不会受到影响。其中唯一的政策性修改是为了防止开发者在将来对GCC的功能做出某些修改。FSF一直和GCC开发者紧密合作来了解人们目前使用GCC的方式,以确保他们在新的例外条款下仍然能够继续按照已有的方式使用GCC。

我使用GCC加上专有的预处理工具/源代码生成工具来做编译。我可以利用这个例外吗?

是的。编译过程开始于任何“完全由高级语言表达的代码,而不是过渡代码语言。”这包括由预处理工具或其他专有软件生成的代码。这样,编译过程不包含任何专有软件;它是合法的,例外对这样的程序适用。

我使用GCC加上专有的汇编器/连接器做编译。我还可以利用这个例外吗?

是的。编译过程当编译器产生目标代码时结束,这个包括输出“适用于汇编器、载入器、连接器/运行程序的输入文件。”换句话说,在这种情况下编译过程在GCC输出汇编代码或未连接的目标文件时已经结束,所以其中不包含任何专有软件的参与。它是合法的,例外对这样的程序适用。

我使用GCC编译程序的一部分,使用专有软件编译程序的其余部分。然后这些部分在汇编或连接阶段合在一起。我还能利用这个例外吗?

是的。在这种情况下,每个独立模块都是按照合法的编译过程变成目标代码的。尽管不同模块经历了不同的过程,该例外还是适用于这个程序的。

我使用不包含任何GCC成分的专有编译器编译我的程序,然后将它和libstdc++连接起来。我的程序本身不包含任何像用GCC编译的程序那样的运行库(libgcc)。我还能利用这个例外吗?

是的。虽然该例外最常见的场景可能是用于把libgcc和GCC编译的目标代码合在一起,但是GPL和GCC运行库例外都不区分静态连接、动态连接以及其他合成方式。该例外许可你可以用,同样的条款,无论你采用了哪一个合成方式。

请注意,如果你要发布的是独立的libstdc++库,那么你需要按照GPL的条款来发布。比如,如果你的库是按照目标代码的形式发布的,那么你需要使用由GPLv3第6节里规定的方法之一来提供源代码。但是只要你的程序适用GCC运行库例外,GPL条款就不会扩展到你的程序。

为什么编译器过渡代码不在“目标代码”的定义之内?

当我们第一次考虑给GCC添加插件架构时,我们非常担心有人会写一个插件来简单把GCC的过渡代码、底层编译数据格式保存到磁盘。这样的话,其他软件就可以不经GCC而优化或改进这些代码。我们可能很难争辩说这些程序应该遵循GPL的copyleft条款,所以我们想要阻止这种活动。

我们的做法是把这些输出排除在目标代码之外。正因为如此,即使有人写了保存中间信息的插件,任何在GCC输出目标代码之前修改这些信息的程序也都参与到了编译过程之中。如果该程序是专有软件,那么例外就不适用于它编译的软件;GCC最后输出的目标代码就必须按照GPL的条款来发布。

如果我写了一些汇编语言的代码,我是否还可以把它和其他正常编译的目标代码合在一起,并利用该例外?

是的,只要这些目标代码是经由合法编译过程产生的。在汇编器里跑手写的汇编代码就是一个编译过程,因为它把让人编写代码的[a]非过渡性语言[]的代码转换成...目标代码。”

GCC运行库例外包含哪些库?

GCC运行库例外涵盖了所有的许可证说明里陈述了例外适用的文件。这包括libgcc、libstdc++、libfortran、libgomp、libdecnumber、libgcov以及其他和GCC一起发布的库。

Classpath会使用该例外吗?

尽管Classpath当前的例外起着相似的作用,我们这次也还没有更新它。因为自由软件Java社区的最新发展,Classpath许可证政策的优先级和其他GCC库有所不同,我们会单独评估。

译注

  1. Java bytecode:这是Java语言编译后的中间语言,就像汇编是C/C++编译后的中间语言一样。