1.2 包的概念

原文链接: https://docs.swift.org/latest/documentation/packagemanagerdocs/introducingpackages/

1.2 包的概念

学习如何创建和使用 Swift 包。

概述

一个包由 Package.swift 清单文件,以及源代码文件、资源和其他资产构成。清单文件(或叫包清单)用 PackageDescription 模块定义包的名称和内容。

每个包都会声明自己的产品,也就是该包产出的东西。产品类型包括库、可执行文件和插件:

  • 库定义一个或多个可被其他代码导入的模块。
  • 可执行文件是可以由操作系统运行的程序。
  • 插件是 Swift Package Manager 可能用来提供额外命令或构建能力的可执行代码。

一个包可以声明依赖,它们提供来自其他 Swift 包的产品。依赖也可以指向系统库或二进制(非源码)产物。

每个产品由一个或多个目标构成,目标是 Swift 包的基本构建单元。每个目标对应一个模块,可以声明对同一包内其他目标的一个或多个依赖,也可以声明对包依赖所提供产品的一个或多个依赖。目标可以定义库、测试套件、可执行文件、宏、二进制文件等。

关于模块

Swift 包把代码组织成模块,也就是代码分发的单元。模块规定了命名空间,并对"模块之外可以使用哪些代码"实施访问控制。你在 Swift 包中定义的每个目标都是一个模块。

当包对外公开一个库时,你是把构成该库的各个目标的公开 API 暴露给其他包使用。在 Swift 中导入一个库,就是导入构成该库的模块以便在自己的代码中使用,无论这些模块是用什么语言创建的。Swift 包也可以把 C、C++ 或 Objective-C 代码作为模块承载;与 Swift 一样,它们也是代码分发的单元,但不同的是,你需要手工编写一个模块定义文件(module.modulemap)来暴露 API,该文件引用一个头文件或一组头文件。

一个程序可以把所有代码放在单个模块中,也可以导入其他模块作为依赖。除了少数系统提供的模块(例如 macOS 上的 Darwin、Linux 上的 Glibc)之外,大多数依赖都需要下载并构建代码才能使用。

把解决某个特定问题的代码抽出来放进独立模块,可以让这些代码在其他场景中复用。例如,一个提供网络请求功能的模块,可以被照片分享应用和天气预报程序共用;如果出现了一个做得更好的新模块,也能以极小的改动轻松替换。拥抱模块化之后,你可以专注于手头问题中有意思的部分,而不必陷在沿途遇到的各种问题上。

一条经验法则是:模块多一些通常比少一些更好。包管理器的设计目标,就是让创建多模块的包和应用尽可能简单。

关于依赖

现代开发因为使用外部依赖而提速(好坏参半)。这确实让你能在更短时间内完成更多工作,但给项目添加依赖也带来了相应的协调成本。

除了下载并构建依赖自身的源代码之外,还必须下载并构建该依赖自己的依赖,如此层层展开,直到整个依赖图都被满足。更麻烦的是,依赖可能会指定版本要求,而这些要求可能还要与同样依赖它的其他模块的版本要求协调一致。

包管理器的职责,就是自动化下载和构建项目全部依赖的过程,并尽量降低代码复用带来的协调成本。一个好的包管理器应当从一开始就致力于降低依赖解析失败的风险;在无法避免时,也要能缓解影响,并提供工具让用户以最小的麻烦解决这种情况。关于添加依赖的更多内容,参见为 Swift 包添加依赖;关于包管理器如何解析和记录依赖,参见解析与更新依赖。