神刀安全网

向开源的 Swift 贡献代码

About the Speaker: Jesse Squires

Jesse Squires 是 Instagram 的一名 iOS 开发者。他在他的博客 jessesquires.com 上撰写了大量关于 Swift 和 Objective‑C 的相关文章,并且向 GitHub 上的多个开源项目贡献过代码。他喜欢跑步以及学习新知识,只要有着黑咖啡和黑金属音乐在手,他就能动力十足。

@jesse_squires

这篇文章会讲述很多内容:我们将会谈论 Swift 中的各种组成部分,以及各式各样的 Swift 项目,同时还会谈论一点点关于 LLVM 的内容,以及您所需要掌握的相关技能,此外还有您为什么需要以及如何向 Swift 贡献代码。希望您读完这篇文章之后,会觉得 Swift 变得更加亲切。

Apple 宣布 Swift 将要开源的时候,着实让我们感到十分惊讶。在 Swift 当中,有很多各式各样的项目。其中不仅仅只包含了编译器,还包含了核心库、标准库,以及正式的 Swift 演变进程。这样的好处在于,总有内容是大家都能够参与的,因此您没必要非得成为编译器方面的专家,才能向 Swift 贡献源码。

然而,这些杂七杂八的项目很容易让人无所适从,很难知道我们应该从何处起步。所有这些不同的部分是如何组合在一起的呢?下面是一个关于编译器是如何工作的表层概述,它可以帮助您将自己定位到您想要贡献代码的项目区域当中。

当您编译代码的时候,发生了什么?

Swift 是基于 LLVM 的顶层构建的,而 LLVM 是 Chris Lattner 所创建的。我们是如何将写下来的代码转变为本地的、可运行的二进制文件的呢?

向开源的 Swift 贡献代码

  1. 我们从前端 (Front End) 开始,或者说一个具体的编程语言开始。

  2. 前端负责解析源代码,然后产生 LLVM IR (Intermediate Representation, 中间码)。这个就是 LLVM 在编译器中表示您代码的方式。IR 是一个高层的汇编语言,其拥有独立的架构。要重点注意的是,对于一等类型 (first class) 的语言来说,具有良好定义的语义是非常重要的。

  3. 从这里,LLVM IR 将被传递给优化器 (Optimizer),在这里执行各种各样的分析和优化,以对代码进行改善。

  4. 优化后的 IR 接下来将被传递给后端 (Back End),后端负责基于所指定的架构或者指令集来产生本地的机器代码。

LLVM 是完全模块化的。事实上,通过中间的这个 LLVM IR 层,将语言本身和语法分析这个过程,和产生二进制文件的过程分离开来。这就是为什么 LLVM 是一个非常受欢迎的项目。

在 Swift 之前,我们所使用的是 Clang。Clang 是一个连接 LLVM 的 C、C++ 以及 Objective‑C 的前端。它的编译流 (Pipeline) 是以 C 或者 Objective‑C 源代码开始的。我们从中提取源代码,然后将其解析为一个抽象语法树 (Abstract Syntax Tree, AST),也就是一个表示您代码的树结构。AST 接下来会通过语义分析进行优化。修改后的 AST 接下来会进入一个代码生成阶段,从而生成 IR。随后 IR 会被传递给 LLVM 以及上面所述的编译流当中,从而生成二进制文件。

我不会深入到 Clang 架构当中,不过这同样也有一些遗留问题。因为我描述的并不是很清晰。解析和语义分析的过程是有一点交叉的,并且有一些代码重复的情况出现。不过这仍然不失为一个强大的工具,只不过仍然不够简明罢了。这可以通过很多种方式告知 Swift 编译器。

Swift 编译流从 Clang 中吸取了很多的经验教训,并且试图避免了许多错误的发生。

我们首先以 Swift 代码开始。代码会被解析为 AST,这和 Clang 所做的是一样的。然后 AST 同样也会通过语义分析,这个阶段负责获取解析后的 AST,然后将其转换为组织良好的、经过完全类型检查后的 AST 形式。

在这个阶段中,我们同样能够发现在源代码中发现的语义问题,然后将警告或者错误进行抛出。接下来 AST 就会被传递给 Swfit 中间语言 (Swift Intermediate Language, SIL) 生成阶段 (这一点和 LLVM IR 类似)。SIL 是一个基于 IR 的 Swift 风格化的封装形式。

SILGen 将会生成原始的 SIL,然后 SIL 会进行分析和优化。这就是大多数 Swift 的 “迅捷 (Swiftiness)” 特性的由来。由于在这里存在一个中间层,因此我们可以在这个阶段中执行很多优化操作。比如说 Swift 特定的优化、架构优化、去虚拟化 (devirtualization),以及其他所有可以发生的操作。这会生成一个规范化的 SIL,然后其将会被传递给 IR 生成阶段,从而生成 LLVM IR。随后就如同之前一样,其将会传递给 LLVM 完成剩余的操作。

模块映射 (Module map) 是 Swift 编译流的另一块内容,其中描述了我们该如何与 C 以及 Objective‑C 交互的操作。您可能曾经看到(或者至少听说过)模块映射方面的内容。我们可以提取 Clang 模块,然后将其传递给 Clang 导入器 (importer) 当中,随后它们会生成 AST,从而可以通过语义分析来进行引用。这就使得 Swift 与 C 或者 Objective-C 交互成为可能。

我知道上面所说的可能会有点多了。因为编译器是计算机科学中具有挑战性的领域之一。我并不是这方面的专家,不过说实话,没有人能够精通我们所说的这些阶段。即使是编写整个编译流的核心团队中的人员,也都有他们各自专精的区域。

// hello.swift print("hello swift!")

>swiftc hello.swift >./hello

现在我们生成了一个基本的 Hello World 程序了,我们可以对其进行编译,然后在命令行中运行。我们实际上可以像这样生成和检查 AST:

>swiftc -dump-ast hello.swift

所生成的 AST 看起来是有点可怕的。您可以使用您自己的代码试着生成一个 AST 看看。您同样可以使用这个命令来发送 SIL,在这里我们可以将编译后的符号名还原为之前的函数名 (demangle)(如果您对此不熟悉的话,只要知道 Swift 使用了命名粉碎规则 (name mangling) 就可以了)。

>swiftc -emit-silgen hello.swift  | xcrun swift-demangle

阅读 SIL 有点像是在阅读汇编语言。这其中包含了非常详细的内容,但是并不像汇编那样难以阅读。我们同样也可以发送 LLVM IR 以及汇编:

>swiftc -emit-ir hello.swift

>swiftc -emit-assembly hello.swift

再重复一遍,要向开源项目贡献代码的话,您不必对所有这些领域都必须精通,不过总的来说,我觉得如果能够广泛涉猎这些领域并且深入理解编译流的话,对于贡献代码是有极大的帮助的。

我们此前所查看的编译流基本上都会分解到各个项目当中。在主要的 Swift 仓库当中,对于每个编译流阶段,都拥有着相应的子目录。

向开源的 Swift 贡献代码

如果您想要给某个特定领域贡献代码,或者提交 BUG 报告的话,您可以使用上面这个图片作为地图,找到对应的目录。

在右上角,这里有 LLVM、Clang 以及 LLDB,因为它们只专注于自己的任务,很少向外传递信息。在编译流的起始位置,有标准库、核心库,以及 Swift 包管理器。这样也是有意义的:这些 Swift 以及 C 库不仅可以通过编译流传送,还可以通过 Swift 或者通过 Clang导入器进行解析,就像您会编写自己的代码然后进行编译一样。

对于每个项目,我将会列出其相关的难度级别。这些级别可能会有点不那么客观,不过我会尽力覆盖所有的项目的。

编译器(Compiler)

难度 : 难

语言 : C++

GitHub 活跃度 : 高

如果您从未写过或者用过 C++ 的话,那么这个项目将会非常棘手,并且比 Swift 要更加复杂。它实际上有着很多 Swift 试图去解决的问题,比如说不确定的行为。

stdlib

难度 : 中等

语言 : Swift*

GitHub 活跃度 : 中等

这是我们大家都会使用的库。Swift 旁边之所以会加个星号,是因为它比起正常的 Swift 来说是略有不同的。在 stdlib 中,您必须要直接访问 LLVM 内置类型,也就是在 LLVM IR 中定义的原始类型。

SourceKit

难度 : 难

语言 : C++

GitHub 活跃度 : 低

最后就是 SourceKit 了,我们都知道,这个模块可以让 Xcode 能够执行语法高亮功能,并且不会导致崩溃发生(��呵呵)。这是用 C++ 编写的,所以它非常具有挑战性。

Swift 基础设施(Infrastructure)

LLVM, Clang 以及 LLDB

难度 : 非常难

语言 : C++

GitHub 活跃度 : 低

这三个项目都是 LLVM 项目集 (Umbrella Project) 的一部分,不过我们能进行贡献的是这些项目的 Swift 特有拷贝,其中拥有一些 Swift 特有的小的变化。这些部分是很难贡献代码的,因为这需要对编译器和 Clang/LLVM 拥有很深入的了解。我认为到 Swift 3 的时候,这一部分就应该会稳定下来了。

在这里需要另外注意的是,所有这些项目都是受到 LLVM 开发政策、编码标准以及相关许可的约束的:它们并不是真正的 Swift 项目的一部分。在许多情况下,您所贡献的变化很可能不会立即应用到 Swift 当中,因此您实际上需要等待您贡献的这些变化被同步到父类项目当中。这些项目会定时地与 LLVM 进行同步。

Swift 包管理器

难度 : 中等

语言 : Swift

GitHub 活跃度 : 高

包管理器是完全由 Swift 写成的,这一点非常赞。这里的入门难度在这方面是比较低的,但是由于它封装了很多的 C 库。因此有着大量的与 C 的交互操作,这些操作可能不为大家所熟悉。

swift-llbuild

难度 : 难

语言 : C++

GitHub 活跃度 : 低

接下来就是 llbuild 了,也就是一个底层的构建系统。这是一系列用以编译构建系统的库集合(也就是所谓的 meta,对吧?)。这通常而言是一个很有挑战的项目。

核心库(Core Libraries)

Foundation

难度 : 简单

语言 : Swift, C

GitHub 活跃度 : 高

XCTest

难度 : 简单

语言 : Swift

GitHub 活跃度 : 高

libdispatch (GCD)

难度 : 高

语言 : C

GitHub 活跃度 : 低

我认为核心库可能是最容易着手的部分了。这些内容对我们来说都是非常熟悉的,因为我们都在 Objective‑C 中大量的使用过它们。这里大部分代码是用 Swift 的,不过也有一些 C 和与 C 交互的代码。就像 Objective‑C Foundation 框架只是对 C 层次的核心框架做了一个封装,Swift 做的事情也是类似的。

最后,Swift 演变 (evolution) 包含了 Swift 正式的重大变化过程。社区中的所有人都可以撰写一个提案。这个仓库当中还包含了 Swift 开发和发布的时间表,因此这是一个值得驻足的地方,可以查看每一个发布版本都会推出一些什么新特性,下一个计划的功能是什么,以及哪些功能是有意没有进入计划,等等内容。

如果您准备提交提案的话,要确保这个提案能够给整个开发者社区带来实实在在的益处。您需要深思熟虑,并且应该首先在邮件列表中对其进行审核。已经有一些这样的情况出现过:有人说我想要这个功能,但是他们并没有真正地给出一个很好的理由。如果您切实想要给 Swift 提交一个变化的话,那么您真的需要有一个很好的理由描述为什么要这样做,并且尝试从社区中获取人们的支持。

关于代码贡献的讨论应该在邮件列表中进行,然后发现的问题应该提交给 JIRA Bug 跟踪器。这些事情都不应该在 GitHub 上进行。这样做的理由在于:记录是很重要的。我们很容易在 Pull Request 中开始一项讨论,但是核心团队要求我们,大多数的讨论应该在 JIRA 和邮件列表中进行。

您应当阅读官方的代码贡献指南,并且努力去遵循它。为了让您提交的更改得到接受,您最好遵循这些指南。

话虽如此,不过贡献的方式仍然有成百上千种,我们不一定非要去贡献代码。除了增加新功能和修复 BUG 之外,还有文档的撰写、文档的翻译、改正错别字、添加测试等等。所有这些工作都能对整个社区有着极大的帮助。

错别字更正看起来是一个很简单的任务,不过它们仍然也是非常重要的。非英语母语者可以找到更清晰易懂的文本,如果出现了错别字,这对他们来说无疑会增加阅读难度。没有错别字的文档也更容易翻译。如果您看到任何一个错别字,那么提交一个快速的 Pull Request,这将会是一个极大的帮助。

此外,从每一个层面中出来的意见都很重要。无论您的编程经验有 20 年还是 20 天,您的观点都是非常重要的,编程经验是无关紧要的。Chris Lattner 曾多次强调,Swift 不仅是一门旨在取代 Objective-C 的语言,而且是一门对初学者友好的语言。

对于代码贡献这一方面,我这里列举了一些建议,因为我们大多数与核心团队的互动是发生在 Twitter、GitHub 或者邮件列表上的。

  • 保持礼貌

    人们往往会在邮件列表中发生争执。不要去辱骂他人。您应当尊重他人的意见。请记住,文本这种东西是很容易误读误解的,所以有些人对您文字的理解可能与您相距甚远。

  • 寻求帮助

    向他人寻求帮助的话有无数的方式可以进行。我们所有人都在 Twitter 上有帐号,并且我们会在那儿提供帮助。邮件列表同样也可以作为一个寻求帮助的好地方。

  • 遵循最佳实践

    尤其是提交一个 Pull Request 的时候:请包含测试,这样可以确保您的代码不会污染别的代码,并且您所做的事情一定要是我们知道该怎么做的。如果您遵循最佳实践和指南的话,这对于审查您代码的人来说,将会比较轻松和容易。

  • 被拒绝了?再接再厉!

    不要气馁。无论是提案还是 Pull Request 被拒绝了,这并不意味着您的水平很差。它只是意味着这并不是正确的时间实现您的诉求,或者是您的诉求不适用于 Swift 而已。请记住,核心团队才是掌控全局的人物:他们对所有项目都了然于心,有时可能会有他们考虑到而我们没有考虑到的事情。被拒绝的提案和 Pull Request 并不是世界末日,它会发生在每一个人身上,即使是那些杰出的贡献者。

  • CODE_OWNERS.txt

    每个项目都有一个这样的文件。这将告诉您核心团队的某个成员负责照看代码库的哪个部分。这样您就可以在 Pull Request 中 @ 他们,这将节省大家很多时间,可以让您的诉求能够很快得到审查并接受。

  • 没有人可以精通 一切

    提问并不羞耻,并且您也无法保证一切都是完美的。我再强调一遍, 核心团队其实是非常希望接受您的诉求的 。他们其实是希望大家都能来参与到其中。他们会在 Pull Request 中和您一同努力,让它能够以任何可能的方式得以接受。只能您收到来自他们的反馈很好的话,并且参照他们所提供的建议进行更改的话,如果这个诉求适合于 Swift 的话,那么他们会将您的诉求合并的。

最好的做法就是跟着示例来走一遍。在社区中有一些不在 Apple 工作的大神,他们已经完成了一些非常棒的工作。他们在自己的专长领域发热发光。我鼓励您找到所热爱的 Swift 某个部分或者其他项目,然后专注于这个领域。这会让您成为一个成功的个人贡献者,并且整体而言您也可以支持 Swift 的成功。

万事开头难,众擎易举。这对核心团队来说是非常重要的,因为 Swift 的成功离不开社区的参与。

我觉得,显然 Apple 对 Swift 做了巨大的投入。Swift 并不会昙花一现。这是 iOS 和 Mac OS 开发的下一个世代,甚至可能在其他平台也能够用上。Swift 可以成为、也终将成为整个社区所希冀的那个样子。

Swift 的整个演变过程是完全开放的。核心团队对我们的反馈反应迅速,这使得我们有机会让 Swift 成为我们理想中的语言。作为一名独立开发者,Swift 的成功就是我们的成功;Swift 的可移植性就是我们的可移植性。Swift 可用的平台越多,我们可以大展身手的地方就越广阔,这样就可以编写各式各样的应用了。

我们仍然处于发展的初始阶段,不过:

“10 年之后的 Swift 会是什么样子的呢?”

这几年绝对是决定性的时刻,我们有能力决定语言将何去何从。我们能决定的不仅仅是编译器、代码和库是什么样的,还能够决定我们该 如何 去写 Swift、以及 Swift 的最佳实践是什么。这完全是隐含在我们的贡献当中的问题:编写 Swift 代码的最好方式是什么呢?

Swift 不仅仅是一门编程语言。它是一个聚集着有梦想的人,我们都想要建造一个绝妙的东西。不要害怕贡献或者寻求帮助。最好的办法就是不停地尝试!

See the discussion on Hacker News .

Get new videos & tutorials — we won’t email you for any other reason, ever.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 向开源的 Swift 贡献代码

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮