如果把开源许可证分成两大阵营,一边是「宽松许可证」(Permissive License,代表是 MIT 与 Apache 2.0),另一边就是以 GPL(GNU General Public License)为核心的「著佐权」(Copyleft)阵营。宽松许可证的世界里,大家更关心「我能不能拿走用」;而 Copyleft 的世界里,更关心「我拿走以后,下游的用户还能不能拿回去改」。
GPL 是一套已经跑了近四十年的工程合同。它经历了 v1、v2、v3 三个主要版本,加上 LGPL(Lesser GPL)这一条分支。每一次版本升级都不是简单的措辞修订,而是对一类真实工程事件的回应:AT&T 的 Unix 私有化、Tivo 的硬件签名验证、Microsoft-Novell 的专利交叉许可、DRM(Digital Rights Management,数字版权管理)的泛滥。
然而最有意思的一个工程事实是:作为 Copyleft 世界最重要的「旗舰产品」,Linux 内核至今仍然锁在 GPLv2 上,明确拒绝升级到 GPLv3。这个选择不是惰性,而是一次非常清醒的工程取舍——它直接决定了今天全球几十亿台嵌入式设备、Android 手机、路由器、交换机、车机、智能家电的底层合规边界。
这篇文章会把 GPLv2、GPLv3、LGPL 三份许可证的核心条款放在一起做一次彻底的对照,重点解释 Tivoization(Tivo 化,指通过硬件限制规避 GPL 精神的做法)到底是什么,为什么 Linus Torvalds 公开把它当成内核升级 v3 的主要障碍,以及 LGPL 的「链接例外」在动态链接与静态链接、Java 字节码、Android NDK 这些现代场景下到底怎么落地。最后会用一节专门讨论国内路由器厂商、华为、小米等公司在 GPL 合规上的真实实践。
一、GPL 的哲学起点
1.1 Richard Stallman 与 GNU 宣言
要理解 GPL,必须先理解它背后的人与时代。1983 年,Richard Stallman(RMS,理查德·斯托曼)在 MIT 人工智能实验室发起了 GNU(GNU’s Not Unix,递归缩写)项目,目标是写出一整套与 Unix 兼容、但完全自由的操作系统。1985 年,他发布了《GNU 宣言》(GNU Manifesto),正式把「自由软件」(Free Software)作为一种工程与社会运动提出。
《GNU 宣言》里最核心的一段话,奠定了后续所有 GPL 条款的哲学基础:
“GNU, which stands for Gnu’s Not Unix, is the name for the complete Unix-compatible software system which I am writing so that I can give it away free to everyone who can use it.”
这里的「free」不是价格免费,而是「自由」——后来在 FSF(Free Software Foundation,自由软件基金会)的文档里被明确拆成了「四大自由」(Four Freedoms),并编号为 0 到 3:
- Freedom 0:以任何目的运行该程序的自由(the freedom to run the program as you wish)。
- Freedom 1:研究程序如何工作并修改它以满足自己需要的自由(the freedom to study and modify)。前提是必须能看到源代码。
- Freedom 2:再分发拷贝以帮助他人的自由(the freedom to redistribute copies)。
- Freedom 3:将你修改后的版本分发给他人的自由(the freedom to distribute modified versions)。
这四条自由合在一起的工程含义是:用户不但要能用软件,还要能控制软件。而控制权在工程上等价于源代码获取权 + 修改权 + 再分发权。
1.2 Copyleft(著佐权)的核心思想
Stallman 在推动 GNU 项目时很快遇到一个现实问题:如果他写的工具只是把源代码放出来,任何一家公司都可以拿去改一改,打包成专有产品卖给用户,而用户拿到的版本是没有源代码的。这样「四大自由」在用户端就被剥夺了。
他的回应是一个在法律形式上非常漂亮的反转:既然版权法(Copyright)天然给了作者禁止别人复制修改的权力,那我就用这个权力去强制要求「任何基于我代码的衍生作品,在分发时也必须给予用户同样的自由」。这个思路被称为 Copyleft(著佐权,刻意与 Copyright 对仗),GPL 就是它的法律载体。
从工程角度理解,Copyleft 是一种「传染性约束」:
原始作者 A → GPL → 衍生作者 B → 必须也是 GPL → 衍生作者 C → 必须也是 GPL → ...
任何一个下游节点都无法把许可证改成比 GPL 更严格(比如闭源专有),因为上游作者保留了版权,他以「你要用我代码就必须接受 GPL」作为前提授予你使用权。一旦你违反 GPL(比如不公开修改后的源代码),你对原作者代码的使用权就自动终止,你的产品会立即处于版权侵权状态。
1.3 为什么会有 GPL:打印机驱动与 AT&T Unix 事件
GPL 并不是凭空写出来的。它诞生于两个具体的工程事件:
第一个是「打印机驱动事件」。Stallman 在 MIT 实验室时,实验室收到一台 Xerox 的新打印机,但新机器的驱动源代码不再像老机器那样可以拿到。他希望改一下驱动,让打印机在卡纸时自动给用户发消息——这是一个非常合理的本地修改。但 Xerox 拒绝提供源代码,理由是 NDA(Non-Disclosure Agreement,保密协议)。Stallman 事后在多次演讲中把这个事件描述成他走向自由软件运动的转折点:当软件不再能被用户修改,用户对机器的控制权就被剥夺了。
第二个是 AT&T Unix 的封闭化。Unix 起源于 AT&T 贝尔实验室,早期因为反垄断判决,AT&T 不能把软件作为商品销售,因此 Unix 源代码被以几乎象征性的价格授权给了大学和研究机构。到 1980 年代,AT&T 被拆分后摆脱了反垄断限制,开始把 Unix 商业化,对 BSD(Berkeley Software Distribution,伯克利软件分发版)提起诉讼,源代码许可费暴涨。这直接威胁到了整个 Unix 学术生态。
GNU 项目和 GPL 的答案是:与其寄希望于某家公司愿意开放源代码,不如建立一个法律上自我保护的替代生态——任何一段 GPL 代码,都会以法律形式永远留在公共可控的范围内。
1.4 「病毒式许可证」的事实与神话
商业公司内部,GPL 经常被描述成「病毒式许可证」(viral license)。这个说法有一部分是事实,有一部分是神话。
事实部分:GPL 确实对「衍生作品」(derivative work)具有强制传播性。如果你把 GPL 代码整合到你自己的程序里,形成一个整体,这个整体作为衍生作品在分发时必须也以 GPL 分发。
神话部分:
- GPL 不会仅仅因为你的机器上装了 GPL 软件就「感染」你的所有代码。只运行(run)不是分发(convey/distribute),不触发义务。
- GPL 不会「感染」通过普通的 IPC(Inter-Process Communication,进程间通信)、网络调用、管道通信的独立程序。一个闭源程序通过标准接口调用 GPL 进程,并不等于衍生作品。这也是为什么 GNU bash 作为 shell 执行闭源二进制从不构成违规。
- GPL 不禁止收费。Stallman 本人在文档里反复强调「free as in freedom, not as in free beer」,你可以卖 GPL 软件赚钱,只要你继续给买家源代码和再分发权。
- GPL 也不会「感染」通过网络提供服务的场景(除非是 AGPL)——这就是后来 AGPL 要被单独写出来的原因。
理解这些边界非常重要,因为很多公司内部 OSPO(Open Source Program Office,开源项目办公室)的政策其实是过度保守的,把「不允许使用任何 GPL 代码」当成默认规则,错过了很多合规可用的场景。
1.4.1 Free Software 与 Open Source 的术语分歧
这里还需要澄清一组容易混淆的术语:Free Software(自由软件)与 Open Source Software(开源软件)。
1998 年 2 月,Eric Raymond、Bruce Perens 等人在一次会议上决定用 “Open Source” 这个新术语替代 “Free Software”。原因很直接:Free 在英语里歧义太大,“free beer” 的联想让商业世界对这个运动心存戒备。他们希望用一个中性的、工程色彩更强的词重新定位运动。同年 OSI(Open Source Initiative,开源促进会)成立,制定了 Open Source Definition(OSD),并建立了许可证审核流程。
Stallman 对这个改名强烈反对。他至今坚持用 Free Software 一词,写了专门的文章 “Why Open Source misses the point of Free Software”。他认为 Open Source 把运动从「社会正义运动」降级成了「更好的软件开发方法学」,丢掉了核心的伦理承诺。
工程上两者的外延大致重合:OSI 批准的几乎所有许可证,FSF 也会承认为 Free Software;反之亦然。但在法律文件里两个术语偶尔会精确指向不同。本文大部分地方用「开源」以求通用,讨论 GPL 哲学起源时使用「自由软件」以忠于原文语境。
二、GPLv2(1991)核心条款解读
GPLv2 是 1991 年 6 月发布的,它是 GPL 真正成为工业标准的版本。今天你在绝大多数 Linux 发行版、U-Boot、BusyBox、QEMU 的源代码头部,还能看到它的身影。我们逐节来看它的关键条款。
2.1 Section 1 与 Section 2:分发义务
Section 1 处理的是「逐字复制」(verbatim copies):
You may copy and distribute verbatim copies of the Program’s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
翻译成工程语言:如果你只是原样转发 GPL
代码,你必须保留所有原有的版权声明、许可声明、免责声明,并且把
GPL
许可证本身的副本一并交给下游。这一条看起来很简单,但它解释了为什么每一个
Linux 发行版的安装介质里都必须带一份
/usr/share/common-licenses/GPL-2。
Section 2 处理修改后的版本,这才是 Copyleft 的核心:
You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions…
它列出了三个附加条件:
- 你必须在修改过的文件里显著标注你修改了它以及修改日期。
- 你必须把任何「你分发或发布的、整体上或部分地包含程序的、或由程序衍生的作品」整体作为 GPL v2 授权给第三方,且不收取任何许可费。
- 如果修改后的程序在运行时以交互方式读取命令,它必须在启动时打印或显示版权与免责声明,并且告知用户可以重新分发程序、如何查看许可证。
其中 (b) 是整个 Copyleft 的「神之一手」。它使用了一个措辞非常宽泛的短语:「work based on the Program」(基于程序的作品)。GPLv2 对这个概念的定义是:
“The ‘Program’, below, refers to any such program or work, and a ‘work based on the Program’ means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language.”
这里最重要的一点是:GPLv2 把「衍生作品」的判断完全委托给了版权法。这在工程上带来了一个长期的模糊区:静态链接、动态链接、dlopen、RPC、IPC,哪些构成衍生作品?FSF 的立场是「静态链接和动态链接都是衍生作品」,但这个立场并没有经过主流法院的裁决检验。后面的 LGPL 正是在这个模糊区里画了一条更清晰的线。
2.2 Source Code 义务的三种形式
GPLv2 Section 3 规定了当你分发的是可执行二进制时,如何履行源代码义务。它给出了三种可选方式:
Option A:随二进制一起,附带完整机器可读源代码。分发介质必须是
通常用于软件交换的介质(磁盘、光盘、现在是 U 盘或网盘)。
Option B:随二进制附带一份「书面要约」(written offer),有效期
至少 3 年,允许任何第三方按不超过实际介质成本的费用索
取完整的机器可读源代码。
Option C:将你从上游收到的书面要约原样转交给下游。仅允许非商业
分发者使用此选项。
对嵌入式设备厂商来说,Option B 是实际的主流做法:路由器、机顶盒、监控摄像头的固件里不可能塞进几百兆的源代码,所以厂商会在说明书或官网上提供一个 GPL 源代码下载入口,并承诺 3 年内按成本价邮寄光盘。这也是为什么你在一些老路由器的说明书附页里会看到 “GPL Source Code Offer” 的英文段落。
但这里有两个容易踩坑的点:
- 「complete and corresponding source code」的完整性。GPLv2 写得非常清楚:完整源代码必须包括「所有用于控制编译和安装可执行文件的脚本」(all the scripts used to control compilation and installation of the executable)。换句话说,只给出 C 源文件是不够的,你还必须给出 Makefile、配置脚本、交叉编译工具链的调用脚本、烧录脚本。历史上 SFC(Software Freedom Conservancy,软件自由保护协会)起诉某些厂商时,焦点就是「给了 .c 文件但没给 .config 和 build 脚本」。
- 「对应性」(corresponding)。你必须给出的是你这次发布的这个二进制对应的源代码,不能给一个「差不多」的版本。如果你内部做了 50 个 patch,就要交出包含这 50 个 patch 的树。
2.3 Section 7:Liberty or Death 条款
Section 7 是 GPLv2 里最戏剧性的条款之一,社区常称之为 “Liberty or Death”(不自由毋宁死)条款:
If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all.
翻译过来是:如果有任何外部约束(法院判决、专利授权协议、第三方合同)使你无法同时履行 GPL 和那个外部约束,那么结论是——你就不能分发这个程序。GPL 不会自动给你让路。
这个条款是专门为了应对「专利敲诈」和「选择性授权」设计的。举例:某公司 A 在产品里用了 GPLv2 的 foo 库,然后被公司 B 起诉侵犯了某个专利。B 愿意给 A 一份专利许可,但这份许可只覆盖 A 自己使用,不包括 A 的下游用户。此时 A 如果继续分发 foo,就是「从下游用户那里剥夺了他们自由修改和再分发的专利权」,违反了 GPL。Section 7 告诉 A:对不起,你要么把专利问题解决到可以扩展给所有下游用户,要么就停止分发。
Section 7 是一个典型的「硬规则」(hard rule):它宁可让 GPL 代码被下架,也不允许部分用户享受比其他人更少的自由。
2.3.1 免责声明与责任限制(Sections 11-12)
Section 11 和 12 是 GPLv2 里不太被讨论、但法律上极关键的两段。它们以全大写的方式写着:
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
...THE PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND...
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY
MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE
LIABLE TO YOU FOR DAMAGES...
工程含义:GPL 软件以「AS IS」(按现状)方式提供,作者和再分发者对任何损失都不承担责任,除非当地法律强制规定另有要求或双方另有书面协议。这条是所有开源许可证的标配,也是为什么你不能以「上游 bug 导致我们生产事故」为由直接起诉内核开发者。
但这条在某些大陆法系管辖区(包括中国、德国的消费者保护法)的执行力并不是 100%。德国法院历史上在消费者场景下要求即使是免费软件也有最低限度的瑕疵担保。这也是为什么许多商业 Linux 发行版(Red Hat、SUSE、OpenAnolis 商业版)会在 GPL 之上再叠加一份商业服务合同——GPL 拿走责任,商业合同再把责任部分拿回来以换取订阅费。
2.4 「or later」版本条款的工程含义
GPLv2 里还有一个看起来像脚注、其实影响极深远的条款。FSF 建议所有使用 GPL 的项目在版权声明里加上这样一句话:
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
注意最后那句 “or (at your option) any later version”。它给了最终用户一个选择权:你可以按 GPLv2 使用,也可以按 GPLv3、v4、v5…… 的任何一个未来版本使用。这个措辞在后来被称为「or later clause」或 “GPL-2.0-or-later”。
Linux
内核在这里做了一个非常重要、但很多人没有注意到的选择。你去看内核仓库根目录的
COPYING 文件,Linus 在头部明确写了一段话:
Also note that the only valid version of the GPL as far as the kernel
is concerned is _this_ particular version of the license (ie v2, not
v2.2 or v3.x or whatever), unless explicitly otherwise stated.
这段话用非常口语化的英语做了一件极严肃的事:把内核代码锁死在 GPL v2,而不是 v2 or later。用 SPDX(Software Package Data Exchange)的标准化许可证标识符表达,就是:
GPL-2.0-only:只能按 GPLv2,不能升级。GPL-2.0-or-later:可以按 GPLv2,也可以按未来任何版本。
Linux 内核是
GPL-2.0-only。这个决定意味着:将来哪怕 FSF
发布了
GPLv4、GPLv5,内核也不会自动升级过去;想要升级必须得到内核历史上所有版权持有人(至少是现存代码的绝大多数版权持有人)的同意,这在工程上几乎是不可能完成的任务。
这一节是整篇文章后面所有讨论的起点。记住它:Linux 内核 = GPL-2.0-only,没有 or later。
2.5 GPLv2 中的「distribute」「copy」「modify」三动词
GPLv2 的文本里反复出现三个动词:copy(复制)、distribute(分发)、modify(修改)。工程师读条文时应该把这三个动词当成状态机的三种转换动作:
持有 持有(修改过)
+----------+ modify +----------------+
| original | ─────────> | modified copy |
+----------+ +----------------+
│ │
│ copy & distribute │ copy & distribute
▼ ▼
+-----------+ +-----------------+
| 下游用户 A | | 下游用户 B |
+-----------+ +-----------------+
- copy:本地操作,只是复制一份。不触发任何
GPL 义务,你在自己机器上
cp一百份都没关系。 - modify:修改代码,在你本地产生一个衍生作品。仍然不触发义务——你可以在自己机器上修改到天荒地老。
- distribute:对外分发,把副本交到第三方手里。这才是触发义务的动作。
GPLv3 把 distribute 改成了 convey,并在定义中明确「propagation that enables other parties to make or receive copies」才是 convey。内部备份、版本控制、运行程序本身都不是 convey。这个清晰化是 GPLv3 对 GPLv2 的一大语言改进——后者的 distribute 在欧洲某些语言里曾引发过翻译歧义。
记住这个三动词模型,后面所有「我这样做会不会触发 GPL 传染」的问题都能先问一句:「我是否对第三方做了 convey?」如果答案是否,多半没事。
2.6 GPLv2 与商业软件的历史共存
一个常被忽视的事实是:GPLv2 时代的 Linux 商业生态运转得相当成功。Red Hat 1999 年上市,成为第一家上市的开源公司;SUSE、Mandriva、TurboLinux 等发行版在 2000 年代初构成了完整的商业生态;IBM 在 2000 年宣布投入 10 亿美元到 Linux,大量内部工具以 GPLv2 发布。
这些商业成功证明 GPLv2 与商业使用不但不冲突,反而是开源商业化的主力许可证。商业价值从哪里来?
- 一是服务、培训、认证:Red Hat 的主要收入是订阅服务,而非卖代码;
- 二是硬件 + 软件打包:IBM、HP、Dell 卖服务器时带 Linux,用户为整体解决方案付费;
- 三是定制开发:客户愿意付费让 Red Hat、SUSE 针对自己的业务做内核补丁、驱动、调优;
- 四是下游产品差异化:厂商在 GPL 内核之上做闭源应用层(如 NetApp、Juniper 的网络设备),这部分是厂商的竞争壁垒。
这套经济模型也是 Linus 反对 GPLv3 的一个隐含背景:GPLv2 时代的商业生态已经证明了 Copyleft 与商业化可以共存,他不希望 GPLv3 的更严格条款打破已经运转良好的生态。「If it ain’t broke, don’t fix it」——这是非常工程师的判断方式。
三、GPLv2 到 GPLv3(2007)的变化
GPLv3 是 2007 年 6 月 29 日发布的。从 1991 到 2007,整整 16 年。FSF 为什么等了这么久才升级?因为这 16 年里软件行业发生了太多 GPLv2 当年没有预见的事:TiVo 的硬件签名、Microsoft 的专利收费、DRM 在消费电子里的普及、互联网服务取代盒装软件的商业模式转变。GPLv3 就是对这些新现实的集中回应。
3.1 为什么要写 GPLv3
FSF 与律师 Eben Moglen 在 GPLv3 的公开草案流程中列出了四个主要动机:
- Tivoization:TiVo 公司使用 GPLv2 的 Linux 内核构建 DVR(Digital Video Recorder,数字视频录像机),并按 GPLv2 要求公开了源代码,但设备的引导加载器(bootloader)会验证内核签名,如果你用修改后的内核重新编译,哪怕源代码和官方完全一样,只要签名不匹配,设备就拒绝启动。结果是「用户有源代码,但没有修改后运行的自由」。FSF 认为这违反了 Freedom 1 的精神。
- 专利问题:2006 年 11 月,Microsoft 与 Novell 签订了一份专利互保协议,大意是 Microsoft 承诺不起诉 Novell 的 SUSE Linux 客户专利侵权。这被社区视为对 GPL 精神的釜底抽薪:Microsoft 实际上是在用「保护部分用户」的方式制造法律歧视。
- DRM 与 TPM(Trusted Platform Module,可信平台模块):HDCP、CSS、AACS 这类数字版权管理技术越来越普遍,而 DMCA(Digital Millennium Copyright Act,数字千年版权法)的第 1201 条把「规避 DRM」入罪。FSF 担心 GPL 软件被绑进 DRM 链条后,用户的「修改权」会被一纸刑法冻结。
- 国际化:GPLv2 的措辞以美国版权法为默认语境,在欧洲大陆法系国家执行时经常撞到术语差异。GPLv3 显著清理了这类问题。
3.1.1 一次 GPLv3 草案流程的观察
GPLv3 的起草过程本身也值得一提——它是开源许可证历史上第一次大规模的「公开立法」。FSF 和律师 Eben Moglen 从 2006 年 1 月到 2007 年 6 月,发布了四份草案(Discussion Draft 1 到 4),每份草案都配有逐条公开评论界面(gplv3.fsf.org 当时的评注工具)。社区成员可以选中某段文字并发表意见,FSF 收到意见后在下一份草案回应。
这次流程的产物不仅是 GPLv3,还包括 AGPLv3、LGPLv3。它在工程上验证了一件事:法律文本可以像代码一样经历版本控制和 code review。今天 Apache 基金会、CNCF、Linux Foundation 的许多政策文档(包括 DCO、CLA 模板)都借鉴了这种流程。
3.2 Section 6:反 Tivoization 的 Installation Information
GPLv3 最具争议的改动在 Section 6,它引入了「安装信息」(Installation Information)这个新概念:
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
核心要求:如果你分发的是「用户产品」(User Product,粗略地说就是消费者购买的个人设备),你不仅要给出对应的源代码,还必须给出足以让用户「安装并运行修改后版本」的所有信息——包括签名密钥、解锁方式、烧录流程。
举个例子,假设一家厂商 X 做了一个基于 GPLv3 软件的智能音箱,固件由 bootloader 验证 RSA 签名。X 要合规,就必须:
- 公开源代码(这是 GPLv2 就有的义务);
- 再额外提供:RSA 私钥(或一种绕过签名验证的方法)、刷机工具、烧录分区说明,让用户真的能把自己编译的固件装进去跑起来。
这个要求在消费电子厂商眼里几乎不可接受:它意味着你不能再用硬件信任链来锁死设备。反过来 FSF 认为:如果你做的是「用户产品」,用户就应该真正拥有它,而不是「拥有一个你赐予的功能集」。
实际案例走查——假设你要做一款 GPLv3 合规的智能灯泡:
硬件:ESP32-S3 + Wi-Fi 模组
软件:
- GPLv3 MQTT 客户端库
- 专有语音识别模块(你自己写的)
- bootloader:基于 U-Boot(GPLv2,不是 v3)
合规动作:
1. 公开 MQTT 库的源代码(含你的 patch) ← 基本 GPL 义务
2. 提供 Installation Information:
a. OTA 签名公钥/私钥对?或者把签名禁用?
b. 刷机工具、串口协议、分区表文档
c. 如何把你自己编译的固件烧进设备并启动
3. 保留书面要约 3 年
4. 注意:U-Boot 是 GPLv2,Section 6 不适用;
但 MQTT 库是 GPLv3,其「User Product」级别的要求
仍然作用于整机(因为组合作品要同时满足所有组件
许可证的要求)。
这套合规动作做下来,等于你必须把设备彻底「开放」给用户自行刷写。对消费级厂商,这往往是一个难以接受的产品决策,因此大部分商业厂商的做法是——彻底避开 GPLv3 组件,选用 Apache 2.0 或 MIT 的等价库。Mosquitto(MQTT broker)有 EPL 1.0 或 EDL 1.0 双许可就是这种市场需求驱动的产物。
Section 6 对「用户产品」的定义非常谨慎,它只覆盖:
- 消费者商品(consumer product),用于个人、家庭或家居用途;
- 设计为或出售给消费者的任何东西。
这意味着企业级服务器、路由核心设备、医疗专用设备等不一定落入这个条款。但对智能电视、手机、家用路由器、车机来说,Section 6 是一个硬门槛。
3.3 Section 3:DRM 条款
GPLv3 Section 3 处理 DRM 问题:
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
这条在法律技巧上非常聪明。它的意思不是「GPL 禁止 DRM」——许可证本身无法禁止技术手段,而是:GPL 软件一旦被纳入 DRM 系统,作者事先声明这段代码不视为 WIPO 版权公约第 11 条(以及 DMCA 第 1201 条)意义上的「有效技术保护措施」。结果是:任何绕过它的人不构成「规避 DRM」,刑事和民事责任被事先排除。
“When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License…”
通俗说:你分发 GPLv3 代码的时候,就同时放弃了用 DMCA 去追究逆向工程者的权利。
3.4 Section 11:专利授权与报复
GPLv3 Section 11 是对 GPLv2 Section 7 的升级。GPLv2 只规定「如果专利阻止你履行 GPL,你就不许分发」,但它没有正面给出专利许可。GPLv3 填上了这一块。
主要内容可以拆成三部分:
- 明示专利授权(express patent grant)。每一个贡献者在贡献代码时,自动向所有下游用户授予一份「必要专利」(essential patent claims)的非独占、全球、免版税许可,覆盖该贡献代码及其衍生作品的使用、修改、分发。这与 Apache 2.0 的 Section 3 非常相似。
- 专利报复(patent retaliation)。如果你对 GPLv3 软件提起专利诉讼(声称该软件侵犯了你的某项专利),你自己对这份软件的许可自动终止。
- Microsoft-Novell 漏洞关闭。Section 11 专门加了一段,说如果你与第三方签订了「歧视性」(discriminatory)专利协议——即协议只保护部分用户而不是全体用户——你就不得分发该程序。这一段在社区里被戏称为 “Novell clause”,因为它直接把 2006 年那笔交易的套路堵死了。
Section 8 和 Section 11 还共同规定了「终止恢复」(termination cure)机制:违反 GPLv3 的人,如果在 30 天内纠正行为并通知版权持有人,原始许可可以被恢复。这是 GPLv2 没有的——GPLv2 里一旦终止就是永久终止,除非版权持有人主动原谅。这个改动被 SFC 多次引用,因为它让「合规事后补救」在 v3 项目里有了法律依据。
3.4.1 专利条款在现实中的触发场景
Section 11 的三部分条款在现实里是怎么被触发的?给几个典型模式:
模式一:贡献者隐藏专利。A 公司把一段代码贡献到某 GPLv3 项目,但 A 公司同时持有一项覆盖这段代码算法的专利。用户 B 按 GPLv3 合法使用该项目,A 公司起诉 B 侵犯专利。后果:
- 按 Section 11 第一段,A 公司贡献代码时已自动授予所有下游用户使用该专利的免费许可,它的起诉在法律上不应成立;
- 按 Section 11 第二段,即使 A 没有「贡献」,只要它以其他方式分发了 GPLv3 代码(例如作为经销商),它对该代码相关专利的主张也会被条款约束;
- 按 Section 10 第三段(专利报复),A 公司对下游用户提起的专利诉讼会让它自己失去 GPLv3 许可,形成反向惩罚。
模式二:收购后的专利翻盘。公司 C 收购了开源贡献者 D。D 的专利组合移交给 C,C 想对 D 的历史贡献主张专利。Section 11 的文字把授权绑定在「conveyor」身上,D 贡献代码时作为 conveyor,许可已发出,C 作为受让人受该许可约束。这一条在工程上非常重要,它防止了「收购式专利围猎」。
模式三:标准必要专利(SEP)。某视频编解码算法被 MPEG-LA 列为 SEP,同时某 GPLv3 项目实现了该算法。实现方如果自己持有相关专利,授权发出没问题;但项目里可能间接使用到其他第三方的 SEP,这部分 Section 11 覆盖不到。这是 FFmpeg 等项目长期采用 LGPL 而非 GPL 的原因之一:LGPL 的宽松链接允许下游按需自行选择编解码组件和专利策略。
3.5 Section 7:附加权限与许可证兼容性
GPLv3 Section 7 引入了「附加权限」(Additional Permissions)机制:
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions.
它允许项目作者在不修改 GPL 正文的前提下,给下游再附加一些例外。最典型的例子是 GCC 的 Runtime Library Exception:GCC 运行时库(libgcc、libstdc++)本体是 GPLv3,但带一个附加例外,允许你用 GCC 编译出的程序以任意许可证发布,而不需要连带把 libgcc 一并 GPL。这是让 GCC 能作为通用工具链的关键设计。
Section 7 对 Apache 2.0 兼容性的贡献也很大。Apache 2.0 里有专利终止条款和专利授权条款,这些条款与 GPLv2 不兼容(GPLv2 不允许额外施加不在 GPL 里的条件)。但 GPLv3 Section 7 专门把「专利报复」「免责声明」这些额外条款列为允许的附加条件。结果是:GPLv3 + Apache 2.0 可以单向兼容(Apache 代码可以整合进 GPLv3 项目),而 GPLv2 + Apache 2.0 则不行。
3.6 其他变化
除了上述几个重磅条款,GPLv3 还做了一系列工程上有意义的调整:
- 国际化。“distribute” 被替换为 “convey”,因为 “distribute” 在欧洲某些语言里有特定法律含义。“propagate” 专门定义为「做任何会在版权法下产生责任的事」,把「运行」与「传播」明确区分开。
- 通过代理选择未来版本(Proxy)。作者可以在声明里授权某个代理(比如 FSF)为他们决定未来版本的采纳。这给长期项目一个轻量的治理机制。
- 源代码义务的强化。GPLv3 明确加入了「对应源代码」(Corresponding Source)的长定义,包括所有用于构建、安装、运行修改后版本所必需的脚本、接口定义、共享库、系统库接口——把「我给了 .c 文件就算合规」的模糊区彻底堵死。
- 基于网络的分发。GPLv3 允许你通过「同等访问方式」在网络上提供源代码,满足 Section 6 的 “corresponding source” 义务,而不再强制邮寄介质。
这些变化加在一起,使 GPLv3 从一份朴素的 Copyleft 契约变成了一份覆盖硬件、专利、DRM、国际法的综合性工程合同。问题是:这份合同要求的东西,对某一类重要使用者来说太多了。那个使用者就是——Linux 内核。
四、Linus 拒绝升级到 v3 的原因
Linus Torvalds 对 GPLv3 的态度在 2006 年草案发布后迅速明朗,而且从未软化。他在多次 LKML(Linux Kernel Mailing List)邮件、公开演讲和媒体访谈里反复说过同一件事:Linux 内核将永远留在 GPLv2,理由不是 v3 写得不好,而是 v3 不适合内核想做的事。
4.1 Linus 的公开立场
Linus 在 2007 年接受访谈时有一段被反复引用的话:
“I think version 3 is a fine license for the FSF’s goals. But it’s not the license I want for my kernel.”
“for my kernel” 四个字是关键。Linus 从不反对 FSF 的哲学本身,他承认 GPLv3 对消费者自由的保护很完备;但他认为内核的定位不是「消费者自由的载体」,而是「任何人——包括希望锁住硬件的公司——都可以放心使用的基础设施」。
在另一封更长的邮件里,Linus 把反 Tivoization 称为他的「主要反对点」(main objection):
“I think it is insane to require people to make their private signing keys available, for example. I wouldn’t do it. So I don’t think the GPLv3 is as good a license as v2.”
他认为:硬件制造商在自己卖的硬件上用签名防止用户刷机,这是硬件制造商的正当商业决定;用软件许可证去强制他们放弃这项技术手段,是把软件自由的边界推到了硬件之上,超出了许可证该干的事。
Linus 还提过一个非常工程师气质的论点:GPLv2 的「tit for tat」(投桃报李)规则已经足够好——你用我的代码,你就分享你的修改,至于你拿修改后的代码做什么硬件限制,那是硬件和用户之间的事,与代码许可无关。
4.1.1 Tivo 的签名机制技术细节
为了理解 Linus 的反对意见,需要先看看 TiVo 当年具体在技术上做了什么。TiVo 的 DVR 设备(以 TiVo Series 2 为代表)使用一块基于 PowerPC 的 SoC,内部是一颗定制的 Broadcom 芯片。启动流程大致是:
Power on
↓
Boot ROM(芯片内掩膜,不可修改)
↓
读取闪存里的 stage-1 bootloader,校验签名
↓
stage-1 加载 kernel + initrd,再次校验签名
↓
kernel 启动,自检自身签名(双保险)
↓
如果任何一步签名失败 → 硬件进入安全模式,拒绝启动
TiVo 用的内核就是 GPLv2 的 Linux。TiVo
按规矩公开了完整源代码——包括所有
patch、.config、构建脚本。从 GPLv2
字面义务看,TiVo 完全合规。
但 FSF 的观点是:TiVo 做了一件「符合文字、违反精神」的事。你可以拿到源代码,也可以修改编译,但你把编译结果烧进 TiVo 设备 → 启动失败,因为签名不是 TiVo 的。Freedom 1(修改权)在代码层面存在,在设备层面消失。
Linus 的反驳:设备是 TiVo 的硬件,TiVo 有权决定它运行什么。GPL 的目标是保护代码不被圈地,不是保护「硬件所有权」这件事。如果你不满意 TiVo 设备的限制,别买。他反对把软件许可的权限扩张到硬件供应链上。
这场争论没有对错,它是两种不同的「软件自由边界」哲学。GPLv3 站在 FSF 一侧,Linux 内核站在 Linus 一侧。
4.2 嵌入式生态的工程影响
Linus 的立场背后有巨大的现实动力:嵌入式领域。把 GPLv3 套到嵌入式生态上,会发生什么?
看一下全球路由器市场的主流厂商:TP-Link、Netgear、ASUS、D-Link、华为、小米、Ubiquiti。他们几乎全部基于 Linux 内核 + BusyBox + 各家自定义用户态组件。他们的固件链条大致是这样:
[SoC 厂商 BSP(Board Support Package)]
↓
[Linux 内核 + 板级驱动 patch]
↓
[路由器厂商用户态(配置工具、Web UI、OTA 升级代理)]
↓
[签名与分区布局]
↓
[设备 bootloader 验证 → 启动]
在 GPLv2 下,这个链条是合规的:厂商只需要公开 Linux 内核(含 patch)、BusyBox、其他 GPL 组件的源代码;签名密钥、Web UI 这些专有组件可以不开放。产品照常出货。
如果切换到 GPLv3,Section 6 的 Installation Information 要求会直接摧毁签名机制:厂商必须交出能让用户刷入任意修改固件的所有信息,包括私钥或等价的解锁方法。这意味着:
- 运营商定制固件无法锁定版本;
- 安全启动链(Secure Boot)失效;
- FCC(美国联邦通信委员会)在 2016 年之后对无线设备射频合规的硬件签名要求会与 GPL 合规直接冲突——FCC 要求厂商确保用户不能修改射频参数超出授权范围,GPLv3 却要求厂商让用户能修改整个软件栈。
这种冲突不是理论推演。CISCO、TP-Link、Ubiquiti 这些公司的某些产品线,在 2016 年后确实在 OpenWrt 等第三方固件的支持上变得更保守,原因之一就是 FCC 规则的紧缩——而这整张网,如果 Linux 切到 v3,会彻底断裂。
Linus 在某封邮件里用了一个更直白的表达:
“I don’t think anybody has the right to tell me that I can’t prevent people from using my code in a cell phone that is locked down.”
翻译:我不觉得有谁有权告诉我,我不能阻止别人在锁死的手机里用我的代码。这句话的精神内核是:他把内核当成「工具」,工具不应对使用方式做道德裁决。
4.3 GPL-2.0-only 的法律含义
如前所述,内核根目录的 COPYING 明确写着 v2
only。让我们看一下它的工程含义。
首先,内核是一个巨大的版权聚合体。linux/CREDITS、MAINTAINERS、scripts/get_maintainer.pl
可以帮助追踪哪些文件由谁维护,但「维护者」不等于「版权持有人」。内核每个文件的版权归属非常分散——既有个人开发者,也有
IBM、Intel、Red Hat、Google、Huawei、Samsung
等几百家公司。自 2005 年起,内核大规模使用
Signed-off-by 约定(Developer Certificate of
Origin,DCO),要求每个提交者声明自己有权以内核当前许可证贡献,但这份声明针对的就是
GPL-2.0,不是 v2 or later。
其次,根据 FSF 自己的说法,GPL 项目升级到新版本有两条路:
- 项目一开始就写了
"v2 or any later version"。这种项目任何单个用户都可以选择以 v3 使用,项目维护者无需额外做什么。 - 项目写的是「仅 v2」或没有 or later。此时要升级到 v3,必须得到所有现存代码版权持有人的同意,或者把不同意的人的代码全部移除重写。
Linux 内核是第二种。它的版权持有人数以千计(很多已经过世或失联),代码量数千万行。让所有人同意升级到 v3,在工程上等同于重写一次内核。Linus 在公开发言里多次表示他不会发起这件事。
可以把这个状态写成一个推论:
(COPYING 写 v2 only)
∧
(版权持有人分散,无法统一同意)
⇒
(Linux 内核事实上永远停在 GPLv2)
这不是一个「还没升级」的问题,而是一个结构性稳态。任何时候讨论「Linux 能不能改成 v3」,都应该先把这个推论说清楚。
SPDX 上的内核许可清理工作(由 Thomas Gleixner 等人在
2017–2018 年推动)最终结果是:内核绝大部分文件头被标注为
// SPDX-License-Identifier: GPL-2.0 或
GPL-2.0 WITH Linux-syscall-note。注意这里的
GPL-2.0 在 SPDX 2.0 之前是 “GPL-2.0-only”
的别名。大约 98% 以上的文件是 v2 only。
4.4 内核模块与「污染」旗标
内核 GPL 的边界上还有一个工程师每天都会碰到的话题:内核模块的许可证。内核里有一套宏:
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
MODULE_LICENSE("GPL and additional rights");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_LICENSE("Dual MIT/GPL");
MODULE_LICENSE("Dual MPL/GPL");
MODULE_LICENSE("Proprietary");当一个模块用 "Proprietary"
加载时,内核会设置 TAINT_PROPRIETARY_MODULE
标志位,并在 dmesg 里打印:
foo: loading out-of-tree module taints kernel.
foo: module license 'Proprietary' taints kernel.
Disabling lock debugging due to kernel taint
这就是「污染旗标」(taint
flag)。它不是阻止你加载专有模块,而是告诉任何 bug
报告的接收者:这个内核状态包含了非 GPL
模块,社区不承诺为此提供支持。/proc/sys/kernel/tainted
按位记录污染来源,每一位都有语义(P=proprietary、F=forced、C=staging crap…)。
历史上最典型的例子是 NVIDIA 的
nvidia.ko,它是专有模块,长期设置 Proprietary
旗标。AMD 的 amdgpu 最终走了反方向,主线化并以
GPL/MIT 双许可发布,避免了污染。而 NVIDIA 直到 2022
年才发布了 open-gpu-kernel-modules(GPLv2/MIT
双许可),但仅覆盖 Turing 及更新架构,且大量固件仍为闭源
blob。
这里衍生出一个长期争议:专有内核模块是否构成内核的衍生作品?FSF 的官方立场一贯是「是」——任何链接到内核的模块,哪怕是运行时动态加载,都属于衍生作品,必须是 GPL。但 Linus 和很多内核开发者的立场更温和:只要模块是一个可以在其他系统上同样工作的、使用内核稳定接口的「独立作品」,它就不一定构成衍生作品。这个立场的体现是内核里存在两套符号导出:
EXPORT_SYMBOL(foo); /* 所有模块可用 */
EXPORT_SYMBOL_GPL(bar); /* 只有 MODULE_LICENSE 为 GPL 兼容时可用 */当一个 Proprietary 模块尝试解析
EXPORT_SYMBOL_GPL
的符号时,模块加载器会拒绝:
foo: Unknown symbol bar (err -22)
foo: disagrees about version of symbol bar
这个机制是 Linus 给出的一种工程妥协:内核接受专有模块存在的事实,但把「内部、GPL 哲学敏感的接口」单独圈出来禁止专有模块使用。哪些接口用哪个宏,不是统一标准,而是维护者的判断。
对企业工程师来说,实操上的关键点是:
- 如果你的内核模块是专有的,尽量只依赖
EXPORT_SYMBOL符号; - 任何 dmesg 里出现
taints kernel都会在生产环境 bug 分析中被视为「非主线状态」; - 双许可(Dual BSD/GPL)是让模块既能进入主线、又能被 BSD 生态复用的常见做法,FreeBSD 的 ZFS、某些驱动都是走这条路。
4.4.1 发行版中的 GPL-only 模块冲突:ZFS on Linux
一个至今未解的著名案例是 ZFS。ZFS 原本是 Sun 为 Solaris 开发的文件系统,2005 年随 OpenSolaris 以 CDDL(Common Development and Distribution License,MPL 衍生的一种弱 Copyleft)授权开源。OpenZFS 项目后来把它移植到 Linux 作为内核模块。
矛盾来了:CDDL 与 GPLv2 被广泛认为不兼容。不是因为 CDDL 的 Copyleft 比 GPL 弱(弱是不冲突的),而是因为 CDDL 和 GPL 都对「修改后必须用自己那套许可证」有要求。两套不重叠的要求合在一起就会自相矛盾——你不能同时满足 CDDL 要求「文件级 Copyleft」和 GPL 要求「整体 Copyleft」。
后果:
- 你不能把 ZFS 代码直接合并进内核主线(主线只接受 GPL 兼容代码);
- 你也不能把 ZFS 代码作为二进制发行版的一部分与内核一起分发(形成衍生作品触发双方许可冲突);
- 但你可以把 ZFS 源代码单独分发,让用户自行编译为内核模块加载——这被认为是「用户自行组合」,不构成分发者的衍生作品。
Ubuntu 在 2016 年做了一个更大胆的选择:把
zfs.ko 作为二进制模块包放进官方仓库。Canonical
的法律分析认为这不违反 GPL,因为内核与 ZFS
分别作为独立软件分发,只在运行时加载——这个立场被 SFC
公开批评,但至今没有诉讼。
这个悬而未决的状态很好地说明:GPL 的传染边界不是一个黑白答案,而是一个「法律分析 + 风险承受度」的工程决策。
4.4.2 内核的 symbol namespace 与 CONFIG_MODULE_SIG
近年内核引入了另两套机制间接强化许可证控制:
- Symbol namespaces(5.4 引入):允许模块显式「import」某个命名空间的符号,做更细粒度的接口分层。虽然不是许可证机制,但常与 GPL-only 限制配合使用。
- 模块签名(
CONFIG_MODULE_SIG):允许发行版要求加载的模块必须由指定密钥签名。这是一种安全机制,但副作用是让企业发行版能进一步控制「谁的模块能加载到他们的内核里」。
这些机制的综合效果是:Linux 内核在坚守 GPLv2 only 的同时,还通过技术手段把 GPL 的边界守得更紧。这与 Linus 的立场并不矛盾——他反对的是「软件许可强加于硬件」,不反对「软件许可在软件内部被严格执行」。
五、LGPL:宽松版 GPL
GPL 本身不区分「程序」和「库」:只要是 GPL 代码,被链接进来的程序就整体被视为衍生作品。这对系统工具、应用程序来说问题不大,但对底层库(C 运行时、数学库、编解码库、GUI 工具包)来说是灾难性的——它意味着任何使用这个库的专有软件都无法存在。1990 年代初,GNU 项目在写 glibc、libstdc++ 时马上撞上了这堵墙。
LGPL(Lesser GPL)的使命就是在 GPL 和 BSD 之间开出一条中间道路。
5.1 LGPL v2.1:从 Library GPL 到 Lesser GPL
LGPL 最早叫 “Library General Public License”(LGPL 2.0,1991)。1999 年 Stallman 写了一篇长文章,把它改名为 “Lesser General Public License”(LGPL 2.1),并解释了改名的原因:他希望开发者默认不要用 LGPL,而是把 GPL 作为首选,LGPL 只在「战略上必要」时才使用——也就是当你写的库和某个专有库有直接竞争,不允许专有程序链接意味着你的库根本没有用户。glibc 和 libstdc++ 就是典型例子:如果它们不允许专有程序链接,Linux 就不会有商业应用,Linux 生态就起不来。
改名 “Lesser” 是故意的贬义措辞:FSF 希望告诉开发者「这是一个较弱的 Copyleft,用它意味着你放弃了一部分自由保护」。
5.2 链接例外的工程含义
LGPL v2.1 的核心是 Section 5 和 Section 6。它区分两种使用模式:
- 「基于 Library 的作品」(work based on the Library):这是修改了库本身的源代码或者直接把库静态塞进去且不给出替换手段的情况。此时整个作品按 LGPL(实际上等价于 GPL)处理。
- 「使用 Library 的作品」(work that uses the Library):这是在你的程序里调用库 API 的情况。此时你的程序可以不用 LGPL,可以是任何许可证(包括闭源专有),但必须满足一些条件。
Section 6 给出了「使用」模式下的条件清单(择要翻译):
- 在每份你分发的作品里,显著声明你使用了该库,并告诉用户库本身按 LGPL 授权。
- 随分发提供一份 LGPL 的副本。
- 如果你的作品在运行时显示版权声明,必须包括库的版权声明和指向 LGPL 的指针。
- 并且,必须满足下面四种之一:
- (d1) 随作品提供完整的、机器可读的库源代码(含你对库做的修改,如果有的话),外加能把作品与库重新链接生成新可执行文件的「对象代码与/或源代码」。换句话说:用户必须能用新版本的库重新链接你的程序。
- (d2) 使用合适的共享库机制进行链接。共享库必须已经存在于用户系统(或由你提供),且在用户系统更换库版本后能正常工作。
- (d3) 随作品附带一份「至少 3 年」的书面要约,承诺按成本提供 (d1) 所要求的材料。
- (d4) 如果你是通过从他人处得到的副本转分发,可以把他人的要约原样转交。
读完这些条件,可以得到 LGPL 链接例外的工程精髓:你可以静态链接 LGPL 库到闭源程序里,但必须给下游用户「替换这个库」的能力。
在动态链接场景下这很自然:你程序里调用 glibc,glibc 是共享库,用户换一个版本的 glibc 你的程序自动用新的。这时 (d2) 天然满足。
在静态链接场景下麻烦得多:静态链接把库代码编进了你的二进制,用户怎么「替换」?LGPL
的答案是——你必须提供你程序的「可重链接对象文件」(relocatable
object
files),让用户可以把新版本的库链接回去。具体做法是提供
.o 文件或 .a 文件(不含 LGPL
库代码的你自己的部分),加上
Makefile/脚本,让用户在本地完成一次链接操作。
这个要求对 Android NDK 里的 LGPL
库使用就是一个真实的坑:如果你在 apk 里静态链接了一个 LGPL
库,你理论上必须在合规材料中附带你 native 组件的
.o 文件和链接脚本,以便用户自己换库。绝大多数
Android 应用根本做不到这一点。这是为什么 Android 社区里对
LGPL 库采取非常审慎的态度,常见建议是:
- 如果可以动态链接(
.so+dlopen或 NDK 动态链接),优先动态链接; - 如果必须静态链接,优先选择 MIT/Apache 2.0 的等价库;
- 如果一定要用 LGPL 且静态链接,准备好发布链接用的对象文件并在应用隐私页/版权页明确说明。
5.2.1 LGPL 链接边界的一个具体推演
假设你做一款闭源 PDF 阅读器,想用 Poppler(LGPL v2.1+)作为 PDF 渲染内核。按 LGPL v2.1 Section 6 的要求,工程动作可以有几种合规路径:
路径 A:动态链接(推荐)
你的 app 二进制 ← dlopen → libpoppler.so
↑
用户可自由替换该 .so
合规清单:
- 在「关于」页列出 Poppler 名称、版本、LGPL 链接
- 官网提供 Poppler 源代码下载(可直接链上游)
- 保证 .so 与 app 在独立文件(不要把 .so 合并进 app 可执行)
- 无须公开 app 的任何代码
路径 B:静态链接 + 可重链接对象
你的 app 二进制 = app.o + libpoppler.a 静态合并
合规清单(比 A 多出来的部分):
- 发布 app.o(你的可重链接对象文件)+ 链接脚本
用户取得新版本 libpoppler.a 后,能自行
执行:ld app.o libpoppler_new.a -o app_new
- 或者,直接公开 app 源代码
路径 C:违规做法(错误示范)
把 libpoppler 源代码拷一份到自己仓库,改成内部
类名,直接静态编译进 app.exe,不公开任何东西。
这在 LGPL 下是清楚的违规:修改库本身的代码必须以
LGPL 发布;静态链接没提供可重链接路径。
路径 A 对现代桌面、服务器都容易满足。问题出在 iOS、Web
Assembly、某些单文件分发场景:iOS
禁止动态加载第三方代码(App Store 规则),WASM
把所有依赖打进一个 .wasm
文件,这两种场景天然只能走静态链接,LGPL 的路径 B
在实操上非常笨重。因此 iOS App 社区对 LGPL
库的接受度很低——在 CocoaPods
上你会看到许多库的作者主动提供「商业许可证选项」来绕过这个问题。
5.3 LGPL v3:继承 GPLv3 所有新条款
LGPL v3(2007)的结构设计非常简洁——它不再是一份独立的完整许可证,而是写成「GPLv3 + 一组附加权限」。因此:
- LGPLv3 继承了 GPLv3 的反 Tivoization、DRM、专利、Apache 兼容等所有新条款;
- 并在此基础上给出了库使用的例外。
LGPLv3 引入了一个新概念:「对应应用代码」(Corresponding Application Code):
“The Corresponding Application Code for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work.”
简单说:如果你把 LGPLv3 库组合进一个「结合作品」(Combined Work),你必须把你应用部分的「对象代码或源代码」作为合规材料的一部分——让用户能把它和新版本的库组合回去。这与 LGPL v2.1 Section 6 (d1) 的要求类似,但在 v3 里被用更工整的术语描述了。
5.4 LGPL 在 Java、Android 上的特殊问题
LGPL 最早是为 C/C++ 生态设计的,链接模型是链接器把对象文件合并进二进制。在 Java、Kotlin、Swift、Go 这些后出现的语言里,「链接」的含义完全不同,LGPL 的条文变得模糊甚至不可执行。
Java 的情况:Java 程序通过
.class / .jar 分发,运行时由 JVM
加载并 JIT
编译。一个程序是否「链接」了一个库?在字节码层面它只是在
import 时引用类名,在运行时由 classloader 动态解析。FSF
对此写了一份专门的 FAQ「LGPL and Java」,立场是:Java
的类链接被视为 LGPL 意义上的动态链接,因此静态 include
的问题不存在,只要你满足「让用户能替换库」的条件就行。但这份
FAQ 没有法律效力,只是 FSF 的解读。
Android 的情况:Android 平台自己几乎不用 LGPL 代码。Google 的核心策略是用 Apache 2.0 重写基础库(Android Framework、Bionic C 库、Skia),唯一的 GPL 组件是 Linux 内核,唯一的 LGPL 组件集中在少数本地库(早期 FFmpeg、某些编解码)。Android 明确避开了 GNU libc(glibc)而选择 Bionic,避开 GNU GCC 的 libstdc++ 而选择 libc++(LLVM),避开 GNU Classpath 而选择 Apache Harmony(早期)和后来基于 OpenJDK 重写。这条路线的代价是大量工程重复劳动,但回报是 Android 的用户空间(不含内核)可以以 Apache 2.0 作为默认授权进入到几乎所有 OEM 厂商的专有定制里。
GNU Classpath 与 Android OpenJDK 之间还有一个半公开的故事。2010 年 Oracle 起诉 Google,指控 Android 的 Java 实现侵犯 Oracle 的专利和 Java API 版权。官司打了将近十年,最终 2021 年美国最高法院判决 Google 使用 Java API 构成合理使用(fair use)。这期间 Android 从 Apache Harmony 迁到了 OpenJDK 基础。OpenJDK 的许可证是 GPLv2 with Classpath Exception——这里的 Classpath Exception 就是一种「类似 LGPL 链接例外」的附加权限,允许任意许可证的程序链接 OpenJDK 的类库。这让 Android 在法律上能直接使用 OpenJDK 实现而不污染 app 的许可证。
5.5 LGPL 在嵌入式系统里的两难
LGPL 在桌面/服务器环境里几乎是完美设计:动态链接天然满足 Section 6 (d2)。但在嵌入式与移动设备里,LGPL 的「你必须能替换库」要求与「设备的完整性、安全启动、FCC 合规」之间的冲突比 GPLv3 更早出现。
以一款智能门锁为例:
- 固件签名:防止被篡改后破解开锁;
- 使用的编解码库是 LGPL(假设某个音频提示库);
- 用户按 LGPL (d1) 要求提供可重链接对象 → 用户理论上能替换编解码库 → 用户也能借此路径植入任意代码 → 门锁安全性崩溃。
厂商的普遍应对:
- 方案 A:换成 BSD/MIT 等价库(首选)。FFmpeg 有 LGPL 核心 + 可选 GPL 组件,但很多场景可直接换为 MIT 的 minimp3 / dr_libs。
- 方案 B:把 LGPL 库彻底动态化,放在一个独立分区(通过签名保证,但用户替换后设备进入「调试模式」降级运行)。
- 方案 C:就地说明 LGPL 的 (d) 条件我们选择 (d1) 路径,但设备运行签名固件时不保证功能完整——这是一种有风险的尝试,法律上未被充分检验。
这一节对比 GPLv3 的反 Tivoization 条款,可以看出:FSF 在 LGPL v2.1 时代其实已经预见到了硬件锁定问题,但当时的措辞是温和的(「让用户能重新链接」),没有上升到「必须给签名密钥」的程度。GPLv3 的反 Tivoization 本质上是把 LGPL v2.1 里那个「能替换库」的精神从库层面推广到了整个程序层面——也正是这一步让 Linus 觉得走过头了。
六、GPL 兼容性矩阵
讨论许可证兼容性时,最容易混乱的是「A + B 能不能合并成一个作品」。下面按常见情况整理一张表。这里「合并」的含义是做成一个单一作品或紧耦合的衍生作品;纯粹的聚合(同一光盘里两个独立程序)不受这张表约束。
| A B | Public Domain | MIT/BSD-2 | BSD-3 | Apache 2.0 | LGPL v2.1 | LGPL v3 | GPL v2 only | GPL v2 or later | GPL v3 |
|---|---|---|---|---|---|---|---|---|---|
| Public Domain | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| MIT / BSD-2 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| BSD-3 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Apache 2.0 | ✓ | ✓ | ✓ | ✓ | ✗ | ✓ | ✗ | ✓* | ✓ |
| LGPL v2.1 | ✓ | ✓ | ✓ | ✗ | ✓ | ✓* | ✓ | ✓ | ✓* |
| LGPL v3 | ✓ | ✓ | ✓ | ✓ | ✓* | ✓ | ✗ | ✓ | ✓ |
| GPL v2 only | ✓ | ✓ | ✓ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ |
| GPL v2 or later | ✓ | ✓ | ✓ | ✓* | ✓ | ✓ | ✓ | ✓ | ✓ |
| GPL v3 | ✓ | ✓ | ✓ | ✓ | ✓* | ✓ | ✗ | ✓ | ✓ |
注释:
- ✓ 表示代码可合并。合并后整体作品通常要按「较强」的那一侧许可证分发(Copyleft 一侧)。
- ✗ 表示条款冲突,不能合并。
- ✓* 表示单向或需借助「or later」与附加权限通道:例如 Apache 2.0 与 GPL v2 不兼容,但 Apache 2.0 与 GPL v3 兼容;GPL v2-or-later 的项目可以选择升级到 v3 来获得 Apache 兼容性。
- LGPL v2.1 和 LGPL v3 的互通依赖 LGPL v2.1 的「or later」条款和 LGPL v3 的附加权限结构。
表里最反直觉的两个单元格是:
- Apache 2.0 ✗ GPL v2 only:Apache 2.0 的专利报复条款被 FSF 认定为「给 GPL 加了额外条件」,而 GPL v2 禁止施加额外条件(Section 6)。这是真实存在、被 FSF 与 Apache 基金会双方公开确认的不兼容。
- GPL v2 only ✗ GPL v3:同一个家族的两个版本互不兼容。原因是 v3 加了一些 v2 没有要求的额外义务(如 Installation Information),而「only」意味着项目不接受这些额外义务。
这张表直接解释了为什么 Linux 内核没法直接吸收某些 Apache 2.0 的代码:如果某个子系统想从 Apache 项目引入实现,要么上游的作者愿意以 MIT/BSD 重新授权给内核,要么干脆重写。
6.1 许可证合并后的「优势者原则」
在上面的矩阵里,合并后需要按较严格一侧的许可证分发。这个规则常被称为「优势者原则」或「最强 Copyleft 决定整体许可」:
MIT ⊕ MIT = MIT
MIT ⊕ BSD-3 = BSD-3(或 MIT,取决于哪边有更多条件)
MIT ⊕ GPLv2 = GPLv2(GPL 胜出)
Apache 2.0 ⊕ GPLv3 = GPLv3
LGPLv3 ⊕ GPLv3 = GPLv3(LGPL 在组合作品里退化为 GPL)
理解这条原则的一个关键是:Copyleft 许可证是「入口许可」而不是「出口许可」。GPL 并不是说「我所有代码一定要出到 GPL」,而是说「任何基于我代码的衍生作品,在下游分发时必须至少给予用户 GPL 等价的自由」。结果是下游作品的许可证必须兼容 GPL,最简单的做法就是整体用 GPL。
6.2 SPDX License Expression
现代工程里许可证的精确表达已经标准化为 SPDX Expression 语法:
简单: MIT
合取(全部): GPL-2.0-only AND MIT
析取(选其一):GPL-2.0-or-later OR MIT
附加例外: GPL-2.0-only WITH Linux-syscall-note
GPL-3.0-or-later WITH Classpath-exception-2.0
Linux 内核顶部的 SPDX 行非常典型:
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-noteLinux-syscall-note
是内核的一个附加例外,它说:通过系统调用从用户态程序「使用」内核,不视为衍生作品。这解决了一个古老的困惑——每一个
Linux 上跑的程序都在调
syscall,难道都是内核的衍生作品?显然不是,这个 note
把它写死。
SPDX 还允许自定义例外,GCC Runtime Library Exception、Autoconf 例外、Bison 例外都有对应的标准 SPDX 表达。企业内部做 SBOM 时应当一律使用 SPDX 表达式,避免自创文字描述。
七、工程坑点
7.1 内核模块的 GPL 符号导出
上面第四节已经介绍了 EXPORT_SYMBOL 和
EXPORT_SYMBOL_GPL
的区别。这里补充一些工程实践细节。
内核里有多少 GPL-only 符号?截至近几年的 Linux
主线,EXPORT_SYMBOL_GPL 的数量已经接近甚至超过
EXPORT_SYMBOL。一个粗略的估算:
# 在内核源代码树执行
grep -r "EXPORT_SYMBOL(" --include='*.c' | wc -l
grep -r "EXPORT_SYMBOL_GPL(" --include='*.c' | wc -l结果会显示两者都是数万级的量。哪些符号是 GPL-only?有一些通用模式:
- 调度器相关(
sched_setscheduler_nocheck等):GPL-only,因为调度行为深度侵入内核核心。 - KVM 虚拟化接口(
kvm_*):GPL-only。 - 块设备层(
blk_mq_*):大量 GPL-only。 - 追踪基础设施(
__tracepoint_*、tracepoint_*):GPL-only。 - 内存管理核心(
mem_cgroup_*、部分kmalloc_*):GPL-only。
一个真实的工程陷阱:某些闭源厂商会通过「shim
模块」绕过符号限制。Shim 的做法是写一个 GPL
的「桥接模块」,把 GPL-only 符号中转成普通
EXPORT_SYMBOL
给自己的闭源模块用。这种做法在社区被严厉批评——它在法律上形成了一个明显的「用
GPL 许可证作伪装」的结构,FSF 和 SFC
都将其视为违规。然而它在技术上是能工作的,内核并没有机制阻止。工程师应当警惕任何代码审查中出现的
shim 模块模式。
7.2 动态链接 vs 静态链接下的 LGPL 实践
实务上企业工程师最常问的问题之一是:「我动态链接 LGPL 库,需要做什么?」
最小合规清单(以 LGPL v2.1 为例):
1. 在产品文档 / 「关于」页面列出使用的 LGPL 库名称、版本、
许可证链接。
2. 在发行介质或官网提供完整的库源代码(可以转发上游 tarball)。
如果打了本地 patch,patch 也要给出。
3. 如果产品做过自动更新,确保更新后替换库的能力仍然存在
(不要把动态链接偷偷改成静态)。
4. 保留书面要约 3 年(对实体产品尤其重要)。
静态链接的增量义务:
5. 提供让用户能把新版本库重新链接回你的程序的材料。两种常见
做法:
(a) 发布你程序的可重链接对象文件(.o / .a),加上 Makefile
和链接脚本;
(b) 发布你程序的完整源代码(很多厂商嫌麻烦,干脆把程序改成
开源)。
6. 在隐私页/版权页显著标注:「本产品包含 XX LGPL 库的静态链
接版本,如需替换库请访问 …」。
另一个被忽视的坑:LGPL 对库的修改。如果你对 LGPL 库本身打了 patch,该 patch 必须以 LGPL 发布。这一点对使用定制版 FFmpeg、定制版 OpenSSL(OpenSSL 不是 LGPL,但逻辑相同)的团队是常见合规问题。实操建议是把 patch 放在一个独立的、公开的 git 仓库里,每次发布版本时打 tag,URL 放进产品合规页。
7.3 GPL 传染的「组合作品」判断
GPLv2 Section 2 最后一段有一个常被引用的措辞:
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
「单纯聚合」(mere aggregation)不触发传染。一张光盘里放了一个 GPL 程序和一个闭源程序,两者互不依赖,光盘本身不因此全部 GPL。
问题在于:什么算「单纯聚合」,什么算「组合成一个作品」?边界从来没有被法院清晰划定。历史上有几个著名的论战:
- systemd 之争:Lennart Poettering 设计的 systemd 由多个二进制组成(systemd-pid1、journald、logind 等),它们通过 D-Bus 与其它进程通信。是一个还是多个作品?多数观点认为是多个,因为进程之间用标准 IPC,没有编译期耦合。
- Linux + 专有固件
blob:很多设备驱动会在运行时加载一个厂商提供的二进制固件(通过
request_firmware())。这个固件是否是内核的衍生作品?社区的广泛接受是「不是」——固件运行在独立硬件上,不共享内核地址空间,只通过 DMA/MMIO 接口通信。内核会把这些固件放在linux-firmware仓库,明确标注专有许可。 - 容器镜像:一个 Docker 镜像的基础层是 GPL(比如 Debian 的 glibc、coreutils),上面应用层是闭源专有程序。这是聚合还是组合?社区共识是聚合——容器里每个进程独立、通过标准接口交互,没有编译期链接。这也是 Docker Hub 上能同时存在大量闭源商业应用与 GPL 发行版基础层的法律基础。
FSF 自己的 FAQ 给出的近似判据是:「如果两个程序在同一地址空间通过函数调用交互,或者共享数据结构,它们更可能是一个作品;如果通过管道、socket、D-Bus、文件、网络调用交互,它们更可能是独立作品。」这个判据在工程上是合理的,但没有司法判决背书。
7.3.1 一个真实的组合边界争议:glibc 链接问题
glibc 是 LGPL(v2.1+)。你写的专有程序 foo 通过动态链接
glibc,这显然合规。但有一个细节:glibc
头文件(<stdio.h>、<stdlib.h>)里包含大量宏、inline
函数、静态 inline 定义。当你
#include <stdio.h> 并编译时,这些宏和
inline 会被直接内联到你的 .o
里,成为你二进制的一部分。
FSF 对此的立场写在 “LGPL-and-Java” FAQ 与 glibc
自己的授权说明里:glibc 头文件中的 inline
内容被明确视为「接口定义」而非「库内容」,通过它们引入的代码不触发
LGPL 的 Copyleft。否则任何 Linux 应用都会因为
printf 的 inline 定义而被
LGPL「感染」,这显然不是设计意图。
这个例子说明:Copyleft 的边界在现实里不是纯粹的法律问题,而是法律 + 工程惯例 + 上游作者意图 + 社区共识 的综合产物。阅读许可证文本只是入门,理解项目的实际合规惯例同样重要。
7.4 源代码发布义务的时间节点
GPL 一个常被误解的维度是「什么时候必须提供源代码」。答案是:在你分发可执行文件的那一刻,源代码义务就已经开始。
具体形态:
- 网络下载:如果你在官网提供二进制下载,你必须在同一个地方(或以「至少同等访问性」的方式)提供源代码。不能说「你先买一台设备,收到设备后我再给你源代码」——这违反同等访问要求。
- 实体介质:嵌入式设备只能走 Option B(3 年书面要约)。你必须在用户随产品收到的文档里(或产品包装上)印上要约文字,明确告知获取源代码的联系方式与期限。
- 企业内部分发:如果你在公司内部给员工分发 GPL 软件,这不构成「convey」(对外分发),不需要公开源代码,但必须保留员工查阅源代码的权利(通常通过内部镜像)。
历史上 SFC 打过的几桩有名的合规官司(在此不展开具体文号,只说公开事实):
- SFC 等组织与若干家庭无线路由器/网络存储设备厂商就 BusyBox 合规达成和解,厂商同意公开完整源代码、建立长期合规通道。
- BusyBox 是 SFC 早期 GPL 执法的标志性项目,相关合规程序形成了业内「书面要约 + 在线仓库 + 包含构建脚本」的事实标准。
- 2021 年,SFC 代表 Christoph Hellwig 起诉 Vizio 智能电视未完整履行 GPL 源代码义务,这是罕见的以「GPL 下游用户(第三方受益人)」身份提起的合同诉讼——它的价值在于理论上确立了用户自己可以起诉,而不只依赖版权持有人。
工程上的合规提醒:
- 发布流程里必须固化一个「release bundle」的环节,把二进制、源代码 tarball、构建脚本、使用的上游版本 commit hash 一起归档。
- 源代码镜像地址必须长期可用。CDN 过期、域名换人、公司重组都是常见失效原因。
- 上游更新时,你打的 patch 必须跟版本一起推进。不能发布 6.1 内核的二进制但源代码还挂着 5.10 的 tarball。
7.5 一次真实合规排查的工程日志(虚构但典型)
把本节的各种原则串起来,看一个现场化的场景。你是某物联网初创的技术负责人,产品即将出海欧盟。法务发来一封邮件:「我们要过 CE 认证,合规部门要求出示所有开源许可证的合规证据。你有一周时间。」
Day 1:盘点依赖。你让团队跑一遍 SBOM 生成:
# Yocto 项目可直接生成 SPDX
bitbake -c create_spdx <image>
# 对手写固件
pip install cyclonedx-bom
cyclonedx-py -o sbom.json产出一份 JSON,里面 387 个组件,按许可证分布:
MIT : 142
Apache-2.0 : 88
BSD-3-Clause : 41
GPL-2.0-only : 56 ← 主要是 Linux 内核 + BusyBox + dropbear
LGPL-2.1-or-later : 18
GPL-3.0-or-later : 12 ← 这是危险信号
MPL-2.0 : 9
CDDL-1.0 : 1 ← 不兼容警报
Proprietary : 20
Day 2:消除危险组件。
- GPL-3.0 的 12 个组件逐一审查。发现其中 8 个是 GNU coreutils、tar、gzip——替换成 BusyBox 内置版本或 Toybox(BSD-0)。剩下 4 个是 GNU libmicrohttpd、gnutls 等,替换为 civetweb(MIT)、mbedTLS(Apache 2.0)。
- CDDL-1.0 那一个是 OpenZFS——产品不需要,直接移除。
Day 3:准备 GPL 源代码包。
# 收集所有 GPL/LGPL 组件的源代码 tarball + patch
mkdir -p gpl_release/kernel gpl_release/busybox ...
cp $YOCTO_DL/linux-5.15.123.tar.xz gpl_release/kernel/
cp $BUILD/tmp/work/.../linux-5.15.123/.config gpl_release/kernel/
cp -r $BUILD/tmp/work/.../linux-5.15.123/*.patch gpl_release/kernel/打一个总的
gpl_source_v1.0.0.tar.xz,放到合规站点。
Day 4:文档化。写一份
THIRD_PARTY_LICENSES.md:
# Third-Party Licenses
This product includes software from the following open-source projects.
## GPL v2 Components
- Linux Kernel 5.15.123 (GPL-2.0-only)
Source: https://compliance.example.com/fw-1.0.0/kernel.tar.xz
- BusyBox 1.36.1 (GPL-2.0-only)
...
## LGPL v2.1 Components
- zlib ... # 实际是 zlib license,校对!
- glibc ...
## Written Offer
For a period of 3 years from product shipment, you may request
complete corresponding source code by emailing compliance@example.com.Day 5:固件印刻。把
THIRD_PARTY_LICENSES.md 做成产品「关于 →
开源声明」菜单中的静态页,OTA 更新同步更新。产品说明书附加
“Written Offer” 段落。
Day 6:法务复核。列几个检查项:
- 每个 GPL 二进制都对应着公开可下载的源代码?
- 源代码包含构建所需的
.config、toolchain 版本声明、patch 序列? - 合规页面 URL 长期稳定(不依赖临时 CDN)?
- Written Offer 覆盖产品生命周期至少 3 年?
- 专有模块不链接
EXPORT_SYMBOL_GPL?
Day 7:提交认证。
这个流程走下来,如果之前没做工作,通常要 1–2 个月;一旦建立了自动化 SBOM + 合规发布管道,每次版本发布的增量工作只有几十分钟。
八、中国案例:路由器厂商与 Android 厂商的 GPL 合规
下面这节基于公开可查的事实(厂商的公开源代码门户、SFC 的公开披露、媒体报道)。不涉及任何未公开的内部文件或未经证实的诉讼号。
8.1 TP-Link 的源代码发布实践
TP-Link(普联技术)维护了一个公开的 GPL
源代码门户,历史域名是
www.tp-link.com/en/support/gpl-code/
以及专门的代码仓库
gpl.tp-link.com(站点可用性随时间变化,近年部分页面整合进全球支持中心)。用户可以按产品型号和固件版本号下载对应的源代码压缩包。
TP-Link 的典型合规材料包含:
- 定制版 Linux 内核源代码(基于 SoC 厂商 BSP,通常是 Qualcomm Atheros 或 Realtek 的版本);
- BusyBox 源代码(往往是上游 tarball + 少量厂商 patch);
- 其他 GPL 用户态工具(iptables、dropbear ssh 服务器等);
- 编译所需的 Makefile 与配置。
历史上 TP-Link 与 OpenWrt 社区、GPL
执法者之间经历过一段摩擦:早期某些型号的合规压缩包不包含完整的交叉编译脚本和
kernel
config,社区需要逆向工程来补齐构建能力。随着社区的持续压力以及
OpenWrt 社区与部分型号的深度合作,TP-Link
的合规质量在近年有明显提升。国内研究者做过的一类典型验证动作是:下载合规包、抽取内核
.config、与官方固件解包后的
/proc/config.gz(如果开启)对比,检查两者是否一致。
8.2 华为与 openEuler / HarmonyOS 的合规链条
华为作为硬件厂商的 GPL
合规同样成熟。它公开的开源门户之一是
consumer.huawei.com/en/opensource/(消费者终端产品的
GPL 源代码下载)以及
openEuler、openHarmony
两个社区。
- openEuler(
openeuler.org)是华为牵头、后捐赠给开放原子基金会的服务器 Linux 发行版,整体以社区治理模式运作,内核基于 Linux 长期支持版本。其合规材料直接通过 Gitee 上的仓库公开发布。 - openHarmony(
openharmony.cn)采用 Apache 2.0 为主、Linux 内核仍然是 GPL 的双层结构。HarmonyOS 的商用版本在内核层仍然使用 Linux(某些设备切换为自研 LiteOS),其 GPL 部分按标准流程公开。 - HiSilicon 芯片的 Linux 驱动:历史上华为海思芯片的 Linux 驱动按 GPL 发布在消费者开源门户里,对应每款设备的内核版本与配置。
HarmonyOS / openHarmony 的一个长期讨论点是:如果一款终端设备的底层是 Linux 内核(GPL),上层是 OpenHarmony 框架(Apache 2.0),那么整机的合规材料应该覆盖哪些部分?答案是分层处理——GPL 部分按 GPL 发布源代码,Apache 部分按 Apache 的 NOTICE 要求发布。两者共存不冲突,正是 GPL 兼容性矩阵里「Apache ✓ GPL v2(通过独立程序边界)」的实际体现。
8.3 小米的 Android 内核合规
小米有一个公开的 GitHub 组织
MiCode,其中包含了大量机型的内核源代码仓库,例如
MiCode/Xiaomi_Kernel_OpenSource
以及按机型命名的分支(如 mayfly-q-oss
代表某代小米 12 的 Q 版本内核)。每次 MIUI 或 HyperOS
主要版本发布后,相应机型的内核源代码会在一段时间窗口内推送到
GitHub。
小米的合规质量随机型不同存在差异:
- 旗舰机型(小米数字系列、MIX、Ultra 系列)合规及时,内核源代码通常在公开发售后几周到几个月内发布;
- 红米部分入门机型(特别是仅在海外销售的机型)合规速度较慢,历史上曾有过多代 MIUI 版本发布后才补齐的情况。
LineageOS、PixelExperience 等第三方 ROM 社区的生态,直接依赖这类合规源代码——没有内核源代码就无法为新机型做二次开发。社区与厂商之间形成了一种松散但稳定的关系:社区通过公开压力推动合规,厂商通过合规换取对第三方开发者生态的部分支持(解锁 bootloader 的官方流程就是这种关系的技术体现)。
值得强调的是:GPL 义务的触发点是「分发」,不是「上市销售」。所以理论上只要机器开卖,同时就需要合规材料到位。国内部分中低端机型长期处于延迟合规状态,这在 GPL 合规社区眼里是一个真实但较少被追责的灰色地带——既没有版权持有人主动起诉,也没有监管机关介入,于是维持了事实上的弹性。
8.4 国内 Android 刷机生态与 AOSP / 内核边界
Android 的特殊分层对 GPL 合规影响深远:
[应用层 / Apache 2.0]
↓
[Android Framework / Apache 2.0]
↓ (JNI)
[Native libs / Apache 2.0 + 少量 BSD / 少量 LGPL]
↓
[Linux kernel / GPL-2.0-only]
这套分层设计的意图之一是:让 OEM 厂商对上层 Android 做任何闭源修改都不会触发 GPL 传染。厂商的所有 UI 定制、AI 模型、人脸解锁、支付沙箱都可以是专有二进制,不需要公开源代码。只有内核及其补丁必须公开。
这也是为什么对国内 Android 厂商的 GPL
合规监督几乎完全聚焦在内核部分:社区不会问你 MIUI
桌面的代码,但会反复要你 kernel_*.tar.gz。
刷机生态的工程细节上还有一个隐蔽的合规问题:Device
Tree Overlay(DTBO)与 vendor 分区。现代 Android
设备通常把内核与硬件描述分开:内核主体在
boot.img,硬件特定的 dtb/dtbo 在
vendor_boot。GPL
要求的「完整对应源代码」应该包括用于生成 dtbo
的设备树源文件(.dts、.dtsi)。一些厂商只发布
boot.img 对应的内核树,但遗漏 vendor
的设备树——这是常见合规缺陷。
8.5 国内合规成熟度对比:从「被动回应」到「主动发布」
把几家国内主要硬件厂商放在同一坐标系下比较,可以看到明显的阶段性分化:
阶段 1:被动回应(2010 年前)
公司压根没有 GPL 合规意识,社区投诉后才手工打包一份源代码
发给投诉者,不公开。
阶段 2:门户化(2010–2015)
建立对外 GPL 代码门户,按机型发布源代码压缩包。但质量参差:
缺 .config、缺编译脚本、patch 与实际固件不对应。
阶段 3:工程化(2015–2020)
合规纳入发布流程。CI 在固件构建时自动打出「GPL bundle」,
含内核源、.config、工具链版本说明、patch 序列。
代表:华为 consumer 门户、小米 MiCode 后期仓库。
阶段 4:社区化(2020 之后)
部分厂商把 GPL 代码直接以 Git 仓库形式在 GitHub / Gitee
上维护,允许社区以 issue 形式反馈问题。
代表:openEuler、openHarmony、小米部分旗舰机型。
从阶段 2 跳到阶段 3 是国内厂商过去十年最大的合规进步。驱动力不是监管压力(国内监管对 GPL 合规几乎没有直接执法路径),而是两股力量:一是出海产品被 SFC、FSFE(Free Software Foundation Europe)这类欧美组织盯上,触发跨境法律风险;二是第三方开发者社区(OpenWrt、LineageOS)对合规材料的工程质量直接构成产品口碑压力。
这也给一个对国内所有做出海硬件产品的公司的实用提醒:GPL 合规是产品出海的基础门槛,不是法务的加分项。SFC 一类组织每年会对主要市场上的消费电子做合规审计,未合规产品被发出「cease and desist」后续由代理销售渠道自动下架,影响比预期严重。
九、选型建议
把前面所有讨论收敛到一个工程决策框架,给出实际选型建议。
场景 A:你写的是一个通用库,希望被最大范围采用,包括商业闭源场景。
选择:MIT 或 Apache 2.0。不要选 GPL、LGPL。原因:GPL 会把大量潜在用户挡在门外;LGPL 虽然允许专有软件链接,但它对「静态链接」的义务在移动端和容器化时代越来越难履行,用户会倾向于找替代品。Apache 2.0 的额外好处是提供专利授权与专利报复,对企业法务更友好。
场景 B:你写的是一个底层基础库,在某个领域存在专有竞争对手,你希望用 Copyleft 强迫专有产品也贡献回来,但不希望断绝商业合作。
选择:LGPL v2.1。glibc、FFmpeg(LGPL 核心 + 可选 GPL 组件)、早期 Qt 都是这个选择。它保留了「修改库本身必须开源」的硬约束,同时允许专有程序通过动态链接合法使用。
场景 C:你写的是一个应用程序、开发工具、命令行工具、系统服务,你希望它永远留在开源世界。
选择:GPL v2 或 GPL v3。具体选哪个,看你是否关心 Tivoization、专利、DRM:
- 如果你不希望你的代码被用在锁死的消费硬件里 → GPL v3;
- 如果你希望最大化兼容性,尤其是希望代码能被 Linux 内核生态复用 → GPL v2 only 或 GPL v2 or later。
场景 D:你做嵌入式固件,希望深度集成 Linux 内核并发布商业产品。
选择:内核必然是 GPL-2.0-only(你无法改)。你自己的驱动、用户态组件可以在兼容性允许的范围内自选: - 板级配置、非关键用户态:MIT/Apache 都可以; - 内核模块:推荐 GPL v2(避免 Proprietary taint,允许使用 GPL-only 符号); - 如果你写了想单独卖的工具,走专有许可;GPL 边界清晰即可。
场景 E:你的库/框架主要服务于云端 SaaS 场景,担心云厂商白嫖。
选择:考虑 AGPL v3。它把 GPL 的 convey 定义扩展到了「通过网络对外提供服务」。相关讨论将在本系列下一篇展开——这里仅作提示。
场景 F:你在做一个工具链或运行时(编译器、解释器、标准库实现)。
选择:看看 GCC 的做法。GCC 本身是 GPLv3,但运行时库(libgcc、libstdc++)带 GCC Runtime Library Exception,允许用 GCC 编译出的目标程序按任意许可证发布。这种「Core Copyleft + Runtime Exception」的组合是经过长期实战检验的模板。
一条反复被验证的经验法则:选许可证永远应该围绕「我希望谁能使用我的代码 / 在什么条件下使用」这个问题,不要围绕「我觉得哪个许可证的哲学最对」。GPL 本身不是错误,但放错位置就是错误。
9.1 企业内部的 GPL 合规流程建议
把选型落到工程组织里,需要一套轻量但执行到位的流程。参考形态:
[新依赖引入] ——审批——> [OSPO / 法务检查许可证]
│
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
[宽松许可证] [LGPL] [GPL/AGPL]
直接放行 评估静态/动态链接 高度关注
是否能满足替换要求 默认禁止进入
闭源产品线;
独立 GPL 产品
线单独审批
落地到工具链:
- SBOM(Software Bill of Materials,软件物料清单):每次构建生成 CycloneDX 或 SPDX 格式的 SBOM,包含所有依赖及其许可证。CI 里接一个 license-checker 阶段,发现 GPL/AGPL 直接阻断。
- License 扫描工具:FOSSology、ScanCode Toolkit、LicenseFinder 这一类开源工具,可以识别源代码里各种许可证声明格式,配合 SPDX 标识符做自动化。
- 合规发布通道:专门建立一个
compliance.example.com或在公司官网固定 URL 放产品的 GPL 源代码包,附带版本号与对应固件版本的映射表。
9.2 许可证选择的决策清单(Checklist)
给一个便于背的清单,在团队内部讨论许可证选型时可以按序过:
1. 这个项目的目标用户是谁?(个人开发者 / 企业 / 商业产品 /
消费硬件)
2. 你希望收到的最大贡献者规模是?(几十 / 几千 / 几万)
许可证越严格,贡献者心理门槛越高。
3. 你是否在意专利?(是 → Apache 2.0 / GPLv3 / AGPLv3)
4. 你是否在意「云厂商拿去做闭源 SaaS」?(是 → AGPLv3 / SSPL / BSL)
5. 你是否在意「嵌入设备里被签名锁死」?(是 → GPLv3;
否 → GPLv2 or later;不关心 → MIT/Apache 2.0)
6. 你写的是库还是应用?库优先考虑 LGPL 或 Apache;
应用可以 GPL。
7. 这个项目将来可能合并进哪些上游?如果你希望能被
Linux 内核吸纳 → GPL-2.0 only(与内核一致)。
8. 你团队的法务/商务对 GPL 的态度?如果极度敏感,
选 Apache 2.0 能省掉大量沟通成本。
这张清单跑一遍,许可证选型基本不会错。
9.3 企业里最常见的三个错误
实战中看到的错误模式高度集中,列一下帮助读者自检:
- 错误一:认为「只要我只用不改就不触发 GPL」。错。GPL 的触发点是分发,不是修改。你只要分发了包含 GPL 代码的产品,义务就来了,不管你改没改。
- 错误二:认为「内部使用不触发 GPL」。这在大多数情况正确(公司内网服务、研发工具),但对嵌入式固件、SDK、给客户的二进制交付物都不成立。一旦物理分发或远程更新到不同法人实体,就是 convey。
- 错误三:认为「加一个进程边界就安全」。进程边界确实有助于切断衍生作品判断,但不是万能。
fork + exec一个 GPL 程序,从它读取结果,通常被认为是独立作品;但如果你的主程序只有在调用 GPL 程序时才能完成功能,并且两者紧密耦合,FSF 会主张它仍然是一个衍生作品。判断要看具体架构。
9.4 常见 FAQ
把客户、同事、法务反复问过的问题集中回答一次:
Q1:我们只在服务器内部用 GPL 软件,需要公开源代码吗?
不需要——GPL 义务只在「convey」时触发,纯内部使用不触发。但需要注意「内部」的边界:如果你把软件部署到客户侧服务器,或者打包进交付物,就是 convey。云服务场景下,服务自己运行 GPL 程序而不分发二进制给最终用户,GPL 不触发(AGPL 才触发,下一篇讨论)。
Q2:我能不能买一份 GPL 代码的「商业许可」绕过公开源代码?
如果代码的所有版权持有人都愿意给你出「商业许可」,可以。这叫双许可(dual licensing)。但 Linux 内核由数千位贡献者组成,要获得全部版权许可是不可能的。典型的成功双许可项目:MySQL(Oracle 单一版权人,可以发商业许可)、Qt(Qt Company 持有大部分版权,早期提供商业许可)。
Q3:我改了 Linux 内核做了一个驱动,我发布的产品必须公开这个驱动吗?
是。内核驱动通常被视为内核的衍生作品,必须 GPL
v2。一个特例是:如果你使用严格稳定的内核接口、驱动独立编译、不依赖
GPL-only
符号,你可以在法律灰色地带发布闭源模块,但风险自担,也会产生
TAINT_PROPRIETARY_MODULE。主流实践建议永远
GPL。
Q4:我只是链接 glibc 做系统调用,我的专有程序算 LGPL 吗?
不算。glibc 是 LGPL,但系统调用层面和 glibc 头文件的 inline 定义都不触发传染(按 glibc 本身的 COPYING 与 FSF FAQ)。你的专有程序可以自由授权。
Q5:GPL 软件的 bug 导致我们生产事故,能向上游追责吗?
不能。GPLv2/v3 都有明确的「AS IS」免责声明和责任限制条款。除非上游作者出具了独立的书面承诺或商业合同,否则开源上游不承担任何责任。这就是为什么企业付费购买 Red Hat、SUSE 支持——不是为了代码,是为了责任承担方。
Q6:我写的开源库被一家公司违反 GPL 拿去做专有产品,我能怎么办?
步骤:
- 收集证据——被违反产品的二进制、证据表明其中包含你的代码(反编译、字符串匹配、内核模块符号等);
- 向对方发送合规通知(非起诉函),要求其在合理期限内履行义务;
- 联系 SFC 或当地类似组织寻求代理执法;
- 如对方持续不配合,以版权侵权提起诉讼。
GPLv3 有 30 天「cure period」给被违反方一个纠正窗口;GPLv2 没有,原则上一旦违反许可立即终止,但实务中法院通常接受善意补救。
Q7:MIT 代码合并进 GPL 项目以后还能拿出来单独用吗?
MIT 原始代码在它的原始仓库里仍然是 MIT,随时可以拿出来单独使用。你从 GPL 项目里取出的那份「被合并、被修改」的代码是 GPL 的,不能当成 MIT 用。这是「入口许可」原则的又一体现。
Q8:AGPL 适合我的项目吗?
如果你的项目主要是被部署为网络服务,并且你担心云厂商拿去改闭源运营,AGPL 值得考虑。但要知道:AGPL 会让 80% 的商业用户直接放弃你——很多公司的 OSPO 把 AGPL 与 SSPL 列入黑名单。具体权衡本系列下一篇详细讨论。
本文为工程参考,不构成法律意见。涉及具体法律风险请咨询专业法律顾问。
十、参考资料
以下为本文涉及的主要公开材料索引。所有链接为撰写时可访问的公开页面,具体内容以官方最新版本为准。
- GNU General Public License, version 2, June 1991. https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- GNU General Public License, version 3, 29 June 2007. https://www.gnu.org/licenses/gpl-3.0.html
- GNU Lesser General Public License, version 2.1, February 1999. https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
- GNU Lesser General Public License, version 3, 29 June 2007. https://www.gnu.org/licenses/lgpl-3.0.html
- Richard Stallman, “The GNU Manifesto” (1985). https://www.gnu.org/gnu/manifesto.html
- Richard Stallman, “Why you shouldn’t use the Lesser GPL for your next library” (1999). https://www.gnu.org/licenses/why-not-lgpl.html
- Free Software Foundation, “Frequently Asked Questions about the GNU Licenses”. https://www.gnu.org/licenses/gpl-faq.html
- Linus Torvalds, kernel source tree,
COPYING文件顶部关于 v2 only 的说明。 - Linus Torvalds, LKML 与公开演讲中关于 GPLv3
的多次发言(LKML 归档检索关键字:
GPLv3,DRM,Tivoization)。 - Software Freedom Conservancy, “A Practical Guide to GPL Compliance”. https://sfconservancy.org/docs/
- SPDX License List. https://spdx.org/licenses/
- Linux kernel SPDX license clean-up 提案与合并记录(Thomas Gleixner 等,2017-2018)。
- TP-Link GPL Code Center. https://www.tp-link.com/en/support/gpl-code/
- Huawei Consumer Open Source Release Center. https://consumer.huawei.com/en/opensource/
- openEuler 官方站点. https://www.openeuler.org/
- OpenHarmony 官方站点. https://www.openharmony.cn/
- Xiaomi MiCode on GitHub. https://github.com/MiCode
- Eric S. Raymond, “The Cathedral and the Bazaar” (1999). 对开源运动早期历史的经典描述。
- Bruce Perens, “The Open Source Definition”(OSI 采用)。https://opensource.org/osd
- Lawrence Rosen, “Open Source Licensing: Software Freedom and Intellectual Property Law” (2004). 许可证工程的基础法学文献之一。
- Heather Meeker, “Open Source for Business” (2020). 企业视角的合规与选型实务手册。
- Linus Torvalds, 2006–2008 年 LKML 上就 GPLv3
问题的若干公开邮件,可通过
lore.kernel.org搜索关键字GPLv3检索。 - Yocto Project Compliance Documentation. https://docs.yoctoproject.org/dev-manual/licenses.html
- Linux Foundation OpenChain Project. https://www.openchainproject.org/ 面向供应链的开源合规标准。
- ISO/IEC 5230:2020 (OpenChain Specification). 首个面向开源许可证合规的国际标准。
- FSFE(Free Software Foundation Europe), “REUSE Specification”. https://reuse.software/ 推动源代码头部 SPDX 标识的最佳实践。
- Richard Fontana 等人维护的 “Copyleft and the GNU General Public License: A Comprehensive Tutorial and Guide”(Copyleft Guide). https://copyleft.org/guide/
上一篇:MIT、BSD、Apache 2.0:宽松许可证的真实区别
下一篇:AGPL、SSPL、BSL:云厂商时代的”反云”许可证
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【开源许可与版权工程】闭源项目如何选择开源依赖:公司内部合规实操
面向做闭源/商业产品的团队:逐一拆解 MIT、LGPL、GPL、AGPL、SSPL、BSL 在 SaaS、私有化部署、移动 App、嵌入式固件等形态下的许可边界,给出三级名单模板、CI 扫描配置、SBOM 存证方案与出海补充要求。
开源许可与版权工程
面向中国工程团队的开源许可、版权与合规系列。从 GPL、AGPL、Apache、木兰协议到中国真实案例、SCA/SBOM 工具链与出海合规,讲清楚开源在工程落地中的坑与方法。
【开源许可与版权工程】开源许可证全景:宽松、弱 Copyleft、强 Copyleft、网络 Copyleft
从 MIT 到 AGPL,从 SPDX 标识符到 OSI 认证:一篇讲清楚四类开源许可证的边界、兼容性矩阵、SSPL/BSL 的争议、Commons Clause 事件,以及工程里最常见的踩坑场景和选型建议。
【开源许可与版权工程】开源许可证实操手册:从选型到发布
面向工程团队的开源许可证完整操作手册:许可证选型决策树、LICENSE/NOTICE/SPDX 文件写法、第三方依赖声明、CI 自动化检查、发布物合规标注,以及六套真实可复制的项目结构模板。