如何进行Linux内核开发
这是关于这个主题的全面文档。它包含了如何成为Linux内核开发人员以及如何学习与Linux内核开发社区合作的说明。它试图不包含与内核编程技术相关的任何内容,但会帮助指导你朝着正确的方向前进。
如果本文档中的任何内容过时,请向本文件的维护者发送补丁,其联系方式在文档底部列出。
介绍
所以,你想学习如何成为Linux内核开发人员?或者你的经理告诉你,“去为这个设备编写Linux驱动程序。” 本文档的目标是通过描述你需要经历的过程以及如何与社区合作的提示,教会你一切你需要知道的,也会尝试解释社区为什么会以这种方式工作。
内核主要用C语言编写,一些与体系结构相关的部分用汇编语言编写。内核开发需要对C语言有很好的理解。汇编语言(任何体系结构)不是必需的,除非你计划为该体系结构进行底层开发。尽管它们不能替代扎实的C语言教育和/或多年的经验,但以下书籍对于参考是很好的:
- 《C程序设计语言》(Kernighan和Ritchie著,Prentice Hall出版)
- 《实用C编程》(Steve Oualline著,O'Reilly出版)
- 《C语言参考手册》(Harbison和Steele著,Prentice Hall出版)
内核使用GNU C和GNU工具链编写。虽然它遵循ISO C11标准,但使用了一些标准中没有的扩展。内核是一个独立的C环境,不依赖于标准C库,因此不支持C标准的某些部分。不允许任意长的长长除法和浮点数。有时很难理解内核对工具链的假设和它使用的扩展,不幸的是,对它们没有明确的参考。请查看gcc信息页面(info gcc)以获取有关它们的一些信息。
请记住,你正在尝试学习如何与现有的开发社区合作。这是一个多样化的团队,对编码、风格和流程有着很高的标准。这些标准是基于时间的积累,基于他们发现对于这样一个庞大且地理分布广泛的团队来说最有效的工作方式。尽量提前尽可能多地了解这些标准,因为它们有很好的文档记录;不要期望别人适应你或你公司的工作方式。
法律问题
Linux内核源代码是根据GPL发布的。请参阅源代码主目录中的COPYING文件。有关Linux内核许可规则以及如何在源代码中使用SPDX标识符的说明,请参阅Documentation/process/license-rules.rst。如果你对许可有进一步的问题,请咨询律师,不要在Linux内核邮件列表上提问。邮件列表上的人不是律师,你不应该依赖他们在法律问题上的陈述。
有关GPL的常见问题和答案,请参阅:
文档
Linux内核源代码树中有大量的文档,对于学习如何与内核社区互动是非常宝贵的。当内核添加新功能时,建议同时添加解释如何使用该功能的新文档文件。当内核更改导致内核向用户空间公开的接口发生变化时,建议你将信息或补丁发送给手册页的维护者,解释变化的手册页维护者的邮箱是 mtk.manpages@gmail.com,并抄送列表 linux-api@vger.kernel.org。
以下是内核源代码树中的一些必读文件:
- Documentation/admin-guide/README.rst
- 该文件简要介绍了Linux内核的背景,并描述了配置和构建内核所需的内容。对内核新手来说,应该从这里开始。
- Documentation/process/changes.rst
- 该文件列出了构建和成功运行内核所需的各种软件包的最低版本。
- Documentation/process/coding-style.rst
- 这描述了Linux内核的编码风格,以及其中的一些原理。所有新代码都应遵循本文档中的指南。大多数维护者只有在遵循这些规则的情况下才会接受补丁,许多人只会在代码符合适当的风格时审查代码。
- Documentation/process/submitting-patches.rst
- 该文件详细描述了成功创建和发送补丁的方法,包括(但不限于):
- 邮件内容
- 邮件格式
- 发送对象
遵循这些规则并不能保证成功(因为所有补丁都要经过内容和风格的审查),但不遵循这些规则几乎总是会阻碍成功。
- 其他关于如何正确创建补丁的优秀描述包括:
- Documentation/process/stable-api-nonsense.rst
- 该文件描述了内核内部没有稳定API的决定背后的原因,包括:
- 子系统的shim层(用于兼容性?)
- 驱动程序在操作系统之间的可移植性。
- 缓解内核源代码树内的快速变化(或防止快速变化)
该文档对于理解Linux开发哲学至关重要,对于从其他操作系统开发转移到Linux的人来说非常重要。
- 其他文档...
成为内核开发人员
如果你对Linux内核开发一无所知,你应该查看Linux KernelNewbies项目:
它包括一个有帮助的邮件列表,你可以在那里询问几乎任何类型的基本内核开发问题(在提问之前确保先搜索归档,以免问到已经在过去回答过的问题)。它还有一个IRC频道,你可以在那里实时提问,以及许多有用的文档,对于学习Linux内核开发是很有用的。
该网站提供了有关代码组织、子系统和当前项目(内部和外部)的基本信息。它还描述了一些基本的后勤信息,比如如何编译内核和应用补丁。
如果你不知道从哪里开始,但想要寻找一些任务来加入内核开发社区,可以去Linux Kernel Janitor's项目:
这是一个很好的开始。它描述了一系列需要在Linux内核源代码树中清理和修复的相对简单的问题。与负责该项目的开发人员一起工作,你将学习将你的补丁提交到Linux内核树中的基础知识,并可能被指导下一个要做的工作方向,如果你还没有想法的话。
在对Linux内核代码进行任何实际修改之前,了解所涉及代码的工作原理至关重要。为此,最好直接阅读代码(大部分棘手的部分都有良好的注释),甚至可以借助专门的工具。其中一个特别推荐的工具是Linux Cross-Reference项目,它能够以自引用、索引的网页格式呈现源代码。内核代码的一个优秀且最新的存储库可以在以下网址找到:
开发流程
Linux内核开发流程目前由几个不同的主要内核“分支”和许多不同的子系统特定内核分支组成。这些不同的分支包括:
- Linus的主线树
- 具有多个主要版本号的各种稳定树
- 子系统特定树
- linux-next集成测试树
Linux内核维护流程
主线树
主线树由Linus Torvalds维护,可以在https://kernel.org或仓库中找到。其开发流程如下:
- 一旦发布新内核,将开放为期两周的时间窗口,此期间维护者可以向Linus提交大的差异,通常是已经包含在linux-next中数周的补丁。首选提交大的更改的方式是使用git(内核的源代码管理工具,更多信息可以在https://git-scm.com/找到),但纯粹的补丁也可以。
- 两周后发布-rc1内核,重点是尽可能使新内核变得非常稳定。此时的大多数补丁应该修复回归。一直存在的错误不算是回归,因此只有在重要情况下才推送这类修复。请注意,-rc1之后可能会接受全新的驱动程序(或文件系统),因为这种更改不会引起回归,只要更改是自包含的并且不影响被添加的代码之外的区域。在发布-rc1后,可以使用git向Linus发送补丁,但补丁也需要发送到公共邮件列表进行审查。
- 每当Linus认为当前的git树处于合理的状态以供测试时,就会发布一个新的-rc。目标是每周发布一个新的-rc内核。
- 过程持续到内核被认为“就绪”,整个过程应该持续大约6周。
值得一提的是,Andrew Morton在linux-kernel邮件列表上写道:
"没有人知道内核何时会发布,因为它是根据感知的错误状态而不是根据预先设定的时间表发布的。"
各种稳定树与多个主要版本号
具有3部分版本号的内核是稳定内核。它们包含相对较小且关键的修复,用于解决给定主要主线发布中发现的安全问题或重大回归。主要稳定系列中的每个发布都会增加版本号的第三部分,保持前两部分不变。
这是推荐的分支,适用于希望使用最新稳定内核并且不想帮助测试开发/实验版本的用户。
稳定树由“稳定”团队stable@vger.kernel.org维护,并根据需要发布。正常发布周期大约为两周,但如果没有紧迫问题,则可能会更长。与此相反,与安全相关的问题可能会导致几乎立即发布。
内核树中的文件Documentation/process/stable-kernel-rules.rst记录了哪些更改适用于稳定树,以及发布过程的工作方式。
子系统特定树
各种内核子系统的维护者以及许多内核子系统开发者在源代码库中公开了他们的当前开发状态。这样,其他人可以看到内核不同领域的发展情况。在开发迅速的领域,可能会要求开发者将其提交基于这样的子系统内核树,以避免提交与其他已经进行的工作发生冲突。
这些存储库大多是git树,但也有其他SCMs在使用,或者发布为quilt系列的补丁队列。这些子系统存储库的地址在MAINTAINERS文件中列出。其中许多可以在https://git.kernel.org/上浏览。
在提交到这样的子系统树之前,建议对提议的补丁进行审查,主要是在邮件列表上进行(请参阅下面的相应部分)。对于几个内核子系统,此审查过程使用工具patchwork进行跟踪。Patchwork提供一个Web界面,显示补丁发布、对补丁的任何评论或对其进行的修订,维护者可以将补丁标记为审查中、已接受或已拒绝。其中大多数patchwork站点在https://patchwork.kernel.org/上列出。
linux-next集成测试树
在从子系统树合并到主线树之前,需要进行集成测试。为此,存在一个特殊的测试存储库,几乎每天从几乎所有子系统树中拉取:
https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
这样,linux-next给出了一个概要的展望,即在下一个合并周期将会进入主线内核的内容。欢迎有冒险精神的测试者对linux-next进行运行时测试。
Bug报告
在主内核源目录中的'Reporting issues'文件描述了如何报告可能的内核错误,并详细说明了内核开发人员需要的信息类型,以帮助跟踪问题。
管理Bug报告
实践您的编程技能的最佳方式之一是修复其他人报告的错误。这样不仅可以帮助使内核更加稳定,还可以学会解决现实世界的问题,提高自己的技能,其他开发人员也会注意到您的存在。修复错误是获得其他开发人员认可的最佳方式之一,因为不多的人喜欢浪费时间修复其他人的错误。
要处理已报告的错误报告,找到您感兴趣的子系统。检查MAINTAINERS文件,了解该子系统的错误报告位置;通常会是一个邮件列表,很少是一个bug跟踪器。搜索该位置的存档,帮助您认为合适的地方。您还可以查看https://bugzilla.kernel.org以获取错误报告;只有少数内核子系统积极使用它进行报告或跟踪,尽管如此,整个内核的错误都会在那里报告。
邮件列表
正如上述文件描述的那样,大多数核心内核开发人员参与Linux内核邮件列表。有关如何订阅和取消订阅列表的详细信息,请参见:
http://vger.kernel.org/vger-lists.html#linux-kernel
网上有许多不同地方的邮件列表存档。使用搜索引擎找到这些存档。例如:
强烈建议在列表上发布主题之前搜索存档中的内容。许多详细讨论的内容只记录在邮件列表存档中。
大多数个别内核子系统也有自己单独的邮件列表,他们在那里进行开发工作。有关不同组的这些列表的列表,请参见MAINTAINERS文件。
许多列表托管在kernel.org上。有关它们的信息可以在以下网址找到:
http://vger.kernel.org/vger-lists.html
请记住在使用列表时遵循良好的行为习惯。尽管有点陈词滥调,但以下网址提供了与列表互动的简单准则:
http://www.albion.com/netiquette/
如果有多人回复您的邮件,收件人的CC:列表可能会变得非常庞大。没有充分理由时不要删除任何人的CC:列表,也不要仅回复到列表地址。习惯接收两次邮件,一次来自发送者,一次来自列表,不要试图通过添加花哨的邮件头来调整,人们不会喜欢。
请记住保持回复的上下文和归因完整,保留“John Kernelhacker写道...:”行在回复的顶部,并在各个引用部分之间添加您的陈述,而不是在邮件顶部写。
如果在邮件中添加补丁,请确保它们是纯文本可读的,如Documentation/process/submitting-patches.rst中所述。内核开发人员不希望处理附件或压缩的补丁;他们可能希望评论您的补丁的各行,这只有这样才能实现。确保使用不会破坏空格和制表符的邮件程序。一个很好的第一次测试是将邮件发送给自己,并尝试自己应用您的补丁。如果不起作用,请修复您的邮件程序或更改它直到它起作用。
最重要的是,请记住尊重其他订阅者。
与社区合作
内核社区的目标是提供最好的内核。当您提交补丁以供接受时,它将仅根据其技术价值进行审查。那么,您应该期待什么呢?
- 批评
- 评论
- 要求更改
- 要求理由
- 沉默
请记住,这是将您的补丁纳入内核的一部分。您必须能够接受有关您的补丁的批评和评论,从技术层面评估它们,并重新调整您的补丁,或者提供清晰简洁的理由说明为什么不应该进行这些更改。如果您的帖子没有得到回应,请等几天然后再试一次,有时候事情会在庞大的信息量中被遗忘。
您不应该做什么?
- 期望您的补丁会毫无疑问地被接受
- 变得防御性
- 忽视评论
- 在不进行任何要求的更改的情况下重新提交补丁
在一个寻求最佳技术解决方案的社区中,对于补丁的益处会有不同的看法。您必须要合作,并愿意调整您的想法以适应内核,或者至少愿意证明您的想法是值得的。请记住,只要您愿意朝着正确的解决方案努力,即使错误也是可以接受的。
对于您的第一个补丁,答复可能只是一系列您应该纠正的事项。这并不意味着您的补丁不会被接受,也不是针对您个人的。只需纠正所有针对您的补丁提出的问题并重新发送即可。
内核社区与企业结构的差异
内核社区的工作方式与大多数传统的企业开发环境不同。以下是一些可以尝试避免问题的事项:
关于您提出的更改的好话:
- "这解决了多个问题。"
- "这删除了 2000 行代码。"
- "这是一个解释我试图描述的内容的补丁。"
- "我在 5 种不同的架构上进行了测试..."
- "这是一系列小补丁..."
- "这提高了典型机器的性能..."
应避免说的不好的话:
- "我们在 AIX/ptx/Solaris 中是这样做的,所以这一定是好的..."
- "我已经做了 20 年了,所以..."
- "这对我的公司赚钱很重要"
- "这是我们企业产品线的需求。"
- "这是我描述我的想法的 1000 页设计文档"
- "我已经在这上面工作了 6 个月..."
- "这是一个 5000 行的补丁..."
- "我重写了所有当前的混乱,这就是结果..."
- "我有最后期限,这个补丁现在就需要被应用。"
内核社区与大多数传统软件工程工作环境不同的另一种方式是交互的无面性质。使用电子邮件和 IRC 作为主要的沟通形式的一个好处是不会因为性别或种族而受到歧视。Linux 内核工作环境接受女性和少数族裔,因为您只是一个电子邮件地址。国际化方面也有助于平等竞争,因为您无法根据一个人的名字猜测性别。一个男人可能叫 Andrea,一个女人可能叫 Pat。大多数在 Linux 内核工作并表达意见的女性都有积极的经历。
语言障碍可能会给一些不熟悉英语的人带来问题。在邮件列表上正确表达想法可能需要对语言有很好的掌握,因此建议您在发送邮件之前检查一下,确保它们在英语中是通顺的。
分解您的更改
Linux 内核社区不会欣然接受大量代码的大块投放。更改需要被适当地引入、讨论,并分解成小的、独立的部分。这几乎与公司习惯做的事情完全相反。您的提议也应该在开发过程的早期阶段引入,以便您可以获得对您所做的事情的反馈。这也让社区感到您是在与他们合作,而不仅仅是将他们作为您功能的倾倒场所。然而,不要一次向邮件列表发送 50 封电子邮件,您的补丁系列几乎在大多数情况下都应该比这小。
分解事物的原因如下:
- 小的补丁增加了您的补丁被接受的可能性,因为验证其正确性不需要太多时间或精力。一个 5 行的补丁几乎可以在不经过仔细检查的情况下被维护者应用。然而,一个 500 行的补丁可能需要数小时的时间来验证其正确性(所需时间与补丁的大小呈指数比例关系,或者类似的)。
- 小的补丁在出现问题时也使得调试变得非常容易。逐个撤销补丁要比在应用后(并且出现问题后)解剖一个非常大的补丁容易得多。
- 不仅发送小的补丁很重要,重写和简化(或者重新排序)补丁在提交之前也很重要。
以下是内核开发者 Al Viro 的一个类比:
"想象一下老师批改数学学生的家庭作业。老师不想看到学生在得出解决方案之前的尝试和错误。他们想看到最干净、最优雅的答案。一个好的学生知道这一点,绝不会在最终解决方案之前提交她的中间工作。
内核开发也是如此。维护者和审阅者不想看到解决问题的思维过程。他们想看到一个简单而优雅的解决方案。"
在呈现一个优雅的解决方案和与社区合作并讨论您未完成的工作之间保持平衡可能是具有挑战性的。因此,最好尽早参与过程以获得反馈以改进您的工作,但也要保持您的更改小,这样它们可能已经被接受,即使您的整个任务现在还没有准备好被纳入。
同时也要意识到,发送未完成并将来会“修复”的补丁以供纳入是不可接受的。
证明您的更改
除了分解您的补丁,让 Linux 社区知道为什么他们应该添加这个更改也是非常重要的。新功能必须被证明为是必要的和有用的。
记录您的更改
在发送您的补丁时,特别注意您在电子邮件中的文本。这些信息将成为补丁的 ChangeLog 信息,并将被保存供所有人永远查看。它应该完整地描述补丁,包括:
- 为什么更改是必要的
- 补丁中的整体设计方法
- 实现细节
- 测试结果
有关这一切应该是什么样子的更多细节,请参阅文档的 ChangeLog 部分:
"The Perfect Patch"
https://www.ozlabs.org/~akpm/stuff/tpp.txt
所有这些事情有时是非常难做到的。要完善这些做法可能需要多年的时间(如果有可能的话)。这是一个需要很多耐心和决心的持续改进过程。但不要放弃,这是可能的。许多人以前都做到了,每个人都必须从您现在所处的地方开始。
感谢 Paolo Ciarrocchi 允许基于他撰写的文本来制作“开发过程”(https://lwn.net/Articles/94386/)部分,并感谢 Randy Dunlap 和 Gerrit Huizenga 提供了一些您应该说和不应该说的事项。还要感谢 Pat Mochel、Hanna Linder、Randy Dunlap、Kay Sievers、Vojtech Pavlik、Jan Kara、Josh Boyer、Kees Cook、Andrew Morton、Andi Kleen、Vadim Lobanov、Jesper Juhl、Adrian Bunk、Keri Harris、Frans Pop、David A. Wheeler、Junio Hamano、Michael Kerrisk 和 Alex Shepard 对他们的审查、评论和贡献。没有他们的帮助,这份文档就不可能存在。
维护者:Greg Kroah-Hartman greg@kroah.com