补丁的工作方式
“补丁(patch)”是描述某个文件两个不同版本之间区别的文件。程序 diff 会逐行比较原始文件与新文件,并以特定格式向标准输出打印这些区别。程序 patch 可以读取 diff 的输出,并将那些改变应用于原始文件的另一个拷贝。(注意,“补丁”一词既涉及 diff 命令的输出,也涉及应用那个补丁的命令。)例如:
$ cat old/file.txt
This
is
a
simple
file.
$ cat new/file.txt
This
is
a
slightly more complex
file.
$ diff -uNr old new
diff -uNr old/file.txt new/file.txt
--- old/file.txt Tue May 28 23:00:21 2002
+++ new/file.txt Tue May 28 23:01:01 2002
@@ -1,5 +1,5 @@
This
is
a
-simple
+slightly more complex
file.
可见,两个文件只有一行的区别。在命令行中列出的来自第一个文件的那一行显示时在最前有一个“-”,接下来是来自第二个文件的那一行,在命令行中显示时最前而有一个“+”。直观上,是从旧文件中“减去(suBTracting)”那一行,并“添加”来自新文件的那一行。记住,旧文件总是先出现,然后是较新的文件。
现在,让我们来应用刚刚创建的补丁。补丁会将较旧版本的文件更新为较新版本的文件,所以我们应该对文件的较旧的版本应用补丁。
$ diff -uNr old new > patchfile
$ cd old
$ patch -p1 < ../patchfile
patching file file.txt
$ cat file.txt
This
is
a
slightly more complex
file.
使用 patch 命令应用了 diff 命令的输出后,“旧”文件现在与“新”文件相同。
应用补丁
接下来我们将学习如何应用补丁。需要应用某个补丁的一个常见的原因是为了获得一个特定的内核版本,它不能从 FTP.kernel.org 作为一个大的 tarball 下载得到 —— 或者是为了获得一个增量的补丁,这样当大部分内核文件仍然相同时就不必去下载整个新内核。
内核补丁的命名和创建标准不是特别简单。假定出于某种原因您需要得到内核 2.6.9-rc4,而当前已经拥有版本 2.6.7 的完整的内核源代码。为了从 2.6.7 升级到 2.6.9-rc4 需要下载下列补丁:
从 2.6.7 到 2.6.8
从 2.6.8 到 2.6.9-rc4
每一个 prepatch(两个主版本之间的补丁,称作 patch-2.6.x-rcN,通常可以在 ftp 站点上名为 testing 的目录中找到)都是针对前一个主版本的变化而创建的。常见的错误是下载了内核版本 2.6.9,然后却尝试应用 2.6.9-rc4 prepatch。如果想要得到内核版本 2.6.9-rc4,应该下载内核 2.6.8,然后应用 2.6.9-rc4 prepatch。这是因为 2.6.9-rc4 是 2.6.9 的前身,不能颠倒。注意:命名的惯例和内核 prepatches 的位置会经常发生变化。可能不得不去阅读 Linux-内核邮件列表来得知最新补丁的保存位置及它们的名称。
官方内核补丁的实现都支持您只需进行如下操作:
cd <your linux source tree>
patch -p1 < ../patchfile
patch 命令的 -p1 选项表示的是“除去直到第一个正斜杠的部分路径名,然后尝试对除去了路径名的文件应用补丁”。
如果所有这些看起来太过复杂和令人厌烦,那么可能应该去尝试使用 Cogito。本部分的最后有对 Cogito 的简短介绍。
创建一个补丁
要记住的第一件事情是,始终要在某个地方保存内核源代码的一个未经改动的、原始的版本。不要在它里面进行编译,不要编辑其中的任何文件,不要对它做任何事情 —— 只是拷贝它,来得到源代码树的工作拷贝。原始内核源代码应该是在一个名为 linux.vanilla 或 linux.orig 的目录中,并且工作目录应该与原始代码位于同一目录之中。例如,如果原始源代码位于 /usr/src/linux.vanilla 目录下,那么工作所用的源代码也应该位于 /usr/src/ 目录中。
在对工作拷贝进行了修改后,将使用 diff 创建一个补丁。假定您的工作源代码树名为 linux.new,那么应该运行这个命令:
$ diff -upNr linux.vanilla linux.new > patchfile
原始内核源代码与新的内核源代码之间的所有区别现在就已经在 patchfile 之中。 注意:不要使用不一致的目录创建补丁,例如(不要 这样做):
$ diff -upNr linux.vanilla working/usb/thing1/linux > patchfile
这将不会创建一个标准格式的补丁,而且没有人会去费力尝试您的补丁,因为它难以应用。
既然已经创建了一个补丁,那么阅读它吧!几乎可以肯定,补丁中包含的有些文件您不希望将它们作为补丁的一部分,比如旧的编辑器备份文件、对象文件,或者在开发过程中创建的随机垃圾文件。要除去这些文件,可以让 diff 忽略特定的文件,可以删除这些文件,或者可以手工编辑 diff。在手工编辑补丁之前一定要理解补丁的格式,否则很可能创建出一个不能应用的补丁。make mrproper 是一个实用的命令,可以用来除去在内核构建期间创建的额外文件。
不过要记住,这会删除 .config 文件并强制您对内核进行完全的编译。
另外,要确保补丁位于正确的目录中。新的行是不是前面有“+”的那些行?并且,要确保那些是您所希望执行的修改。非常容易使用完全错误的源代码树完成 diff。
当认为自己已经获得了补丁的最终版本之后,将它应用到原始的源代码树(不要破坏原始源代码树的惟一拷贝)。如果它不能应用而又没有报错,那么重新去完成那个补丁。
同样,如果这这看起来太过复杂,可能应该去尝试使用 Cogito。
在提交补丁之前需要考虑的事情
创建了一个补丁之后,您会希望与其他人共享它。理想的情形是,您自己测试那个补丁,也让其他人去测试它,并让其他人去阅读那个补丁本身。总之,您会希望自己的补丁没有 bug、合理编写、易于应用。
始终要自己编译和测试自己的补丁。您会看到有人向 linux-内核提交“完全没有测试的(totally untested)”补丁,但不会对其倾心 —— 完成没有经过测试的补丁可能是一个没用的补丁。内核维护人员曾不止一次发布根本不能编译的内核。人无完人 —— 在任何情况下都要测试您的补丁。
确保代码与相关代码相符合,并遵循内核代码风格惯例。虽然查看其他源文件通常是了解当前惯例的最佳途径,不过还应去查看文件 Documentation/CodingStyle 中的规范说明。
如果您的补丁难以应用,那么它几乎肯定不会被认可。除了要使用适当层次的目录创建补丁以外,创建它时所针对的内核需要与其他人将补丁应用到的内核相同(或者几乎相同)。所以,如果想让 XYZ 来应用您的补丁,那么要确定 XYZ 正在使用的内核的版本,然后尝试尽可能使用与之相近的内核。通常是内核维护人员所发布的最新 vanilla 内核。
例如,如果有一个针对 2.6.9-rc2 补丁,而 2.6.9-rc4 是发布的最新版本,那么应该针对 2.6.9-rc4 重新创建补丁。最简单的方法是,将补丁从 2.6.9-rc2 应用到 2.6.9-rc4,并修订两个版本之间的所有变化,然后针对 2.6.9-rc4 重新进行 diff。
将补丁提交给谁
这个问题的答案是“看情况而定”。订阅 Linux 内核邮件列表以及与您的研究领域更相关的列表;您将了解到谁是适合的人选。
尝试确定最明确参与维护您正在修改的那部分内核的人。如果您对 bar 子系统中的 foo 驱动程序进行了修改,而 foo 驱动程序有一个维护人员,那么您可能应该将补丁提交给 foo 的维护人员,只有当 foo 的维护人员不理您时再提交给 bar 子系统的维护人员。
顶层内核源代码目录中的 MAINTAINERS 经常会过期,不过,无论如何,通常还是会有所帮助。不管您将补丁发送给 MAINTAINERS 文件的哪个人,都不会有人责怪您。当无法确定如何做时,这总是可采取的最安全方法。
另外,要将您的补丁发送到 [email protected] 的 Linux 内核邮件列表(除非有理由不这样做)。除了维护人员以外的其他开发者可能需要知道您的修改。他们还可能会提供帮助,给出注解与建议。
发布补丁
大部分补丁都足够小,可以包含在邮件中。虽然有些维护人员拒绝接收附件中的补丁,有些维护人员拒绝接收 MIME-编码 的补丁,但是所有维护人员都会接收包含在纯文本邮件主体中的补丁。确保邮件客户机不会破坏您的补丁 —— 如果不能确定,那么将补丁用邮件发送给自己并应用它,这样来确保其他人也可以应用它。大部分 Linux 邮件列表希望补丁拥有以字符串 [PATCH] 为前缀的有意义的英语主题,便于查找和阅读补丁。
如果您的补丁太大,不能通过电子邮件发送(大约 40 KB 或者更大),那么将它放在其他人可以下载的 Web 页面上或者 ftp 站点上,然后把 URL 放在电子邮件中。
源代码树中的 Documentation/SubmittingPatches 文件中可以找到关于如何提交补丁的更多指南。
策略考虑因素
如果所有事实都表明您的补丁有适当的格式、是正确的而且修订了一个 bug,那么提交它将简单得多。更重要的是,您的补丁需要有吸引力、适时、有趣,而且要考虑维护人员的自尊心。在大部分情况下,简单的 bug 修复会被立即认可。不过,有时您会遇到更大的问题。重要的是要记住不能去从事 Linux 维护人员系统周边的工作;您的工作必须深入其中。
学习关于 linux-内核的一些思路,人们试图以这些思路来说服他人将自己的补丁融入内核。如果您的补丁没有被认可,那么去聆听其他人是如何评价它,并尝试解决它的问题。最常被拒绝的补丁是特性(feature)补丁 —— 添加的新特性被其他维护人员认为没有吸引力。不要浪费时间去尝试让补丁被认可,只需要单独维护它。如果足够多的人发现那个补丁有用,那么在下载并使用您的补丁的人中,您会被认为是一位有帮助的内核修改者而获得名望。
有时,维护人员只是因为他或者她的自尊心而不认可某个补丁。在这种情况下,惟一的选择是维护一个独立于主内核的更好版本代码。通常,在一段时间之后,被证明是更好的外部维护的代码将取代内核内部代码 —— 这是成为维护人员的一个途径。
可取代 diff 和 patch 的另一种选择:Cogito
当前很多内核开发者使用 Cogito 来取代 diff 和 patch。它简化了大量内核开发任务,比如更新到最新的版本、创建补丁和应用补丁。
要添加一个文件,运行:
$ cg-add file
要创建一个补丁,运行:
$ cg-diff > patchfile
要应用一个补丁,运行:
$ cg-patch < patchfile
(出处:http://www.sheup.com)