WWDC 2018 Session 411: Getting to Know Swift Package Managerhtml
查看更多 WWDC 18 相关文章请前往 老司机x知识小集xSwiftGG WWDC 18 专题目录git
做者:KANGZUBINgithub
目前,在 macOS/iOS 开发中,咱们一般使用 CocoaPods 或 Carthage 等非官方工具来管理项目工程中对第三方开源库的依赖。shell
Swift Package Manager(Swift 包管理器,通常简称 SwiftPM 或者 SPM)是苹果官方提供的一个用于管理源代码分发的工具,旨在使分享代码和复用其余人的代码变得更加容易。该工具能够帮助咱们编译和连接 Swift packages(包),管理依赖关系、版本控制,以及支持灵活分发和协做(公开、私有、团队共享)等。swift
SwiftPM 于 2016 年随 Swift 3.0 一块儿发布,已经两年多了,今年 WWDC 2018 专门开了一个 Session 用来介绍如何使用它,咱们一块儿来了解一下吧。xcode
目前已经有不少优秀包管理器用于分享和复用代码,对于为何要为 Swift 专门开发一个新的包管理工具(Why a new package manager for Swift?),苹果的工程师在该 Session 中主要总结了以下几个理由:安全
首先,Swift 是一个跨平台开发语言,因此咱们须要一个强大的跨平台工具用于构建 Swift 代码,它能够用一致的方式轻松配置代码,而后在 Swift 所支持的全部平台上运行。SwiftPM 包含其本身的完整构建系统,使你可以仅在一个工具中完成代码的编译、测试和运行等。bash
苹果但愿在 Swift 项目中提供一个官方权威统一规范的包管理器,经过定义一个分发 libraries(库)的通用标准,让咱们尽量方便地在 Swift 生态系统中与他人分享 Swift libraries(库)。并发
在开发过程当中,核心标准库有时候不能知足咱们的需求,咱们可能会想扩展它,但为了保证核心库 API 的简洁,不可能随意往里添加内容。所以,有一个强大的包管理器就能够很容易地将这些扩展做为 package 来分发和共享,而没必要将它们放到核心库中,而那些好的扩展能够随着时间的推移持续地得到社区的支持而且变得愈来愈标准化。app
SwiftPM 自己是用 Swift 编写的,它能够充分利用 Swift 的强大功能和设计理念,经过与 Swift 语言和核心库项目密切合做,能够建立出更加出色的包管理器功能。
SwiftPM 是 Swift 开源项目中的一部分,它被包含在每一个 Swift 工具链中,同时它也包含在 Xcode 的每一个 Release 版本中,你能够很方便地使用它。
一个 package(包)由 Swift 源码文件和一个清单文件组成。这个清单文件被称为 Package.swift
,它使用 PackageDescription
模块来定义包的名称和内容。一个包一般有一个或者多个 targets(目标),每一个 target 指定一个 product(产品)并声明一个或者多个 dependencies(依赖)。
在 package(包)中的每个 target(目标)最终可能构建成一个 library(库)或者一个 executable(可执行文件)做为其 product(产品)。库是包含能够被其余 Swift 代码引用的模块,可执行文件是一段能够被操做系统运行的程序。
对于 SwiftPM 的一些基本概念,例如:Modules、Packages、Products、Dependencies、Targets 等,在 Swift.org 官网已经有很是详细的描述和定义,另外,也能够参见《Swift Package Manager 快速入门指引》这篇文章的翻译,咱们这里再也不赘述。
如上文所述,Swift Package Manager 提供了一个完整的系统用于构建 libraries(库)和 executables(可执行文件),以及能够跨不一样 packages(包)共享代码,下面咱们来介绍一下如何使用 SwiftPM。
swift build: 用于编译 package
swift run: 用于编译并运行一个可执行文件,该命令是在 Swift 4 中新增长的,详见这个提案,它至关于:
$ swift build
$ .build/debug/myexecutable
复制代码
swift test: 用于运行 package 中的单元测试
swift package: 在 package 中进行各类除编译/运行/测试以外的操做,如建立、编辑、更新、重置、修改编译选项/路径等
此外,你能够在命令行中执行 swift package --version
查看当前 SwiftPM 的版本:
$ swift package --version
Apple Swift Package Manager - Swift 4.1.0 (swiftpm-14050)
复制代码
也能够执行 swift package --help
查看关于命令的更多帮助。
关于上述 4 个基本命令的使用和更多信息,能够查阅官方使用示例和文档。
$ mkdir helloword // 建立 helloword 文件夹
$ cd helloword // 进入 helloword 文件夹
$ swift package init --type executable // 在当前文件下初始化 package 为可执行项目
$ swift run // 编译并执行
Hello, world!
复制代码
执行 swift package init --type executable
命令后,在 helloword
文件夹中会自动生成以下目录和文件:
此外,你也能够在当前文件夹下执行 swift package generate-xcodeproj
命令生成一个 Xcode 工程,例如:
$ mkdir MyPackage
$ cd MyPackage
$ swift package init # or swift package init --type library
$ swift build
$ swift test
复制代码
若是你的 package 须要依赖于其它 package,你只须要在 Package.swift
配置清单文件中添加依赖的 GitHub URL 和对应的版本号(关于版本号的规则,下文会详细讲)便可:
import PackageDescription
let package = Package(
name: "MyPackage",
dependencies: [
// 添加依赖包:PlayingCard
.Package(url: "https://github.com/apple/example-package-playingcard.git", from: "3.0.0"),
]
)
复制代码
接下来你就能够在当前 package 中的任何源文件中 import PlayingCard
,并调用它的公开 APIs。
同时,你也能够经过修改 Package.swift
文件中相关依赖的版本号,并执行 swift package update
命令来更新依赖包。
一个 package 一般就是一个的 git 仓库,并经过标签语义来表示版本(versioned tags)
所以,若是要对外发布一个 package,你只要在你的 git 仓库中添加一个用于表示版本号的标签(如 tag 1.0.0),便可提交到 GitHub 上对外发布:
$ git init
$ git add .
$ git remote add origin [github-URL]
$ git commit -m "Initial Commit"
$ git tag 1.0.0
$ git push origin master --tags
复制代码
执行上述命令后,其余 package 就能够经过 GitHub URL 依赖此 package 的当前版本(1.0.0)。
你也能够参考苹果发布的 package 示例:example-package-fisheryates
一个 package 主要由以下三个部分组成,它们的概念咱们前面已经介绍过:
Dependencies / 依赖
Targets / 目标
Products / 产品
一个常见的 Package.swift
配置文件内容大体以下:
其中,targets 是 package 的基本组成部分,它描述了如何将一组源文件构建成模块或测试用例,一个 target 能够依赖于当前 package 中的其它 target,也能够依赖于声明为依赖关系的其余 package 所导出的 product(产品)。
例如上述 package 中声明依赖了一个外部 package,名字为 DeckOfPlayingCards
,其版本为大于等于 3.0.0
,且 libdealer
target 依赖于该外部产品 DeckOfPlayingCards
,而 dealer
则依赖于本身 package 中的 libdealer
,最后 dealerTests
依赖于前面这两个 targets,用于对 package 相关功能进行单元测试。
另外,在该文件中定义了两个 products,分别为 libdealer
和 dealer
,它们与 targets 相对应,通常由一个或多个 targets 组成,并最终将被分别构建成 library(库)和 executable(可执行文件)。
Swift Package Manager 是 Swift 开源项目中的一部分,遵循 Swift 的理念:
Safe: 安全,隔离的构建环境
Fast: 快速,可扩展到大型依赖关系图
Expressive: 有表现力的,使用 Swift 语言定义 manifest 配置文件的格式
经过 SwiftPM 构建一个 package 主要包括以下几个步骤:
如上所述,SwiftPM 使用 Swift 语言来编写其配置清单的格式,容易理解,无需额外的学习成本,其遵循Swift API 设计准则,能够获得现有的 Swift 工具的支持。
苹果推荐在 Package.swift
中优先使用明确的语义,而少用变量替换和拼接,方便本身维护和用户更直观地阅读和理解:
SwfitPM 会自动包含磁盘上当前 package 中 Sources 目录中的源文件,且 Sources 目录下的各子文件夹中的代码会自动与同名的 target 关联,而不须要在清单文件中显式声明:
此外,它也支持编译其余语言,如 C/C++/Objective-C 等,可是目前不支持将这些语言与 Swift 混合编译放在同一个 target 中,须要分别放在不一样的 target。
SwiftPM 采用语义化版本来控制依赖的版本,规则以下:
版本格式:主版本号.次版本号.修订号,版本号递增规则为:
例如:.exact("0.2.1")
指定某一个具体的版本,from: "3.0.0"
指定获取大于等于 3.0.0
(但小于 4.0.0
)的最新版本,tag 3.1.4
指定获取某一标签,upToNextMinor(from: "1.5.8")
获取指定版本到下一个次版本号(即 1.5.8
~ 1.6.0
)之间的最新版本。
此外,packge 之间的依赖是能够传递的(递归),好比 A 依赖了 B,B 依赖了 C,那么 A 固然也自动会依赖于 C:
此外,SwiftPM 一样使用一个 Package.resolved
文件用于记录已经解析安装的 packages 版本,相似于 CocoaPods 中的 Podfile.lock
或 Carthage 中的 Cartfile.resolved
。
它能够用于共享可靠的编译结果,且易于进行新版本更新,但仅适用于顶层(top-level)的 package,例如上图中的 dealer
。
SwiftPM 使用 llbuild
做为其底层编译引擎,提供快速和正确的增量编译,它也被 Xcode 新的编译建系统使用,是 Swift 开源项目的一部分。
SwiftPM 进行构建 package 的编译环境是在一个沙盒中被隔离独立的,没法随意执行命令或 shell 脚本,所以保证了其安全性。同时也支持基于 XE.framework 单元测试,并发测试,或者指定测试某些场景(Test Filtering)等。
SwiftPM 提供了很是灵活的工做流程,你可让你的 package 依赖于某一处于编辑模式(Edit Model)的 package(把某一远程 package 下载到本地临时目录进行编辑),方便你进行调试。你也能够指定依赖 package 的某一分支或者标签,进行特定的功能测试。同时,它也容许你依赖本地的 Package(Local Package Dependencies)。
每一个 Package 中的 API 能够随 Swift 的新版本进行更新,但之前的 API 仍然可用,SwiftPM 容许在不更新清单的状况下使用新的 Swift 工具。
由于咱们能够在 Package.swift
清单文件中指定工具版本和语言版本。以下图所示,第一行注释用于指定 Swift 工具最低版本号,第二行用于指定该 package 中代码使用 Swift 语言版本,便于编译,它是一个列表,能够接受多个版本号。
本节简要介绍一下 Session 中提到的 SwiftPM 即将支持的一些新特性。
SwiftPM 官方的提供库 libSwiftPM
如今已经可用,苹果鼓励开发人员能够基于这个库为 SwiftPM 开发一些扩展工具,如:
Idea: Machine-Editable Package.swift,基于 libSyntax
库,当用户在编辑 Package.swift
时,能够自动根据用户的输入,预生成相应配置代码。
Idea: 标签和发布支持,目前 SwiftPM 的 package 依赖于 git 的标签来发布版本,流程比较繁琐,后续工具自己将添加新功能来简化并自动执行此过程。
Idea: 自动进行语义版本增长
Idea: 部署自动化
Idea: 支持图片等资源文件(Resources)
Idea: 支持编译设置(Build Settings)
Idea: 可扩展的编译工具,自动根据源文件的代码注释和相关配置,生成二进制文件及其使用文档
Idea: Package 内容的校验,防止被篡改
Idea: 跨平台的沙箱隔离(Cross-Platform Sandboxing)
Idea: 支持 Fork 操做
Idea: 支持建立 Package 索引,提高搜索速度
更多关于 SwiftPM 的将来新特性,能够在 swift-evolution 中找到更加详细的描述,你也能够在上面提交 proposals 贡献你的想法。
你能够经过如下几个渠道关注或参与 Swift 和 SwiftPM 等项目的进展:
https://swift.org/package-manager/
https://github.com/apple/swift-evolution
https://forums.swift.org/c/development/SwiftPM
https://bugs.swift.org
https://ci.swift.org
https://swift.org/download/#snapshots
https://github.com/apple/swift-package-manager
此外,随着 Swift 的发展,SwiftPM 在服务端(Server-Side Swift)开发和命令行工具(Command-Line Utilities)开发中也有愈来愈普遍的应用。
去年 Swift 4 发布时,咱们整理翻译了 swift-evolution 中新增的 Package Manager 相关的部分提案(proposals),详见:
后续咱们会继续翻译 swift-evolution 中的其余新提案,欢迎和咱们一块儿完善。
讲真,当看到 WWDC 2018 时间表中这个 Swift Package Manager 相关的 Session 时,我是很兴奋,感受它应该能够支持 iOS 开发了吧?
可是,等到大会结束时,我看到 GitHub 上 swift-package-manager 项目的 README 描述中,仍然保留着这句话:
Note that at this time the Package Manager has no support for iOS, watchOS, or tvOS platforms.
很遗憾,目前 Swift Package Manager 仍然仅支持在 macOS、Linux 开发中使用,并不支持 iOS/watchOS/tvOS 等平台,也许在 Swift 5 发布之后就能支持了吧?让咱们一块儿期待吧。