菜单

模块系统

相关源文件

此页面描述了 Swift 的模块系统,它为代码组织、封装和程序不同部分之间的共享提供了基础。在 Swift 中,模块是代码分发的单元——它可以是框架、库、应用程序或系统组件。

模块系统处理 Swift 开发的几个关键方面:

  • 将代码组织成逻辑、可重用的单元
  • 管理组件之间的依赖关系
  • 实现与 C、Objective-C 和 C++ 代码的互操作性
  • 支持模块的二进制分发
  • 通过模块接口维护 API 稳定性

有关模块加载的更多信息,请参阅 模块加载和序列化。有关 Clang/C++ 互操作性的详细信息,请参阅 Clang 导入器

模块结构

在 Swift 中,模块由 ModuleDecl 类表示,该类包含一个或多个 FileUnit 对象。每个 FileUnit 代表可以成为模块一部分的不同类型的文件。

关键模块结构图

来源

模块类型

Swift 支持几种类型的模块,每种类型都由 FileUnit 的不同子类表示:

  1. Swift 源模块:由 SourceFile 对象表示的 Swift 源文件(.swift)集合。

  2. 已序列化的 Swift 模块:由 SerializedASTFile 对象表示的已编译 Swift 模块(.swiftmodule 文件)。

  3. Clang 模块:由 ClangModuleUnit 对象表示的导入的 C/C++/Objective-C 代码。

  4. 内置模块BuiltinUnit 包含 Swift 的内置类型、运算符和函数。

  5. DWARF 模块:在源代码不可用时使用的调试信息模块。

包单元

Swift 模块可以通过 PackageUnit 类组织到包中。包充当一个或多个模块的容器,并可提供额外的命名空间组织。

来源

模块加载系统

Swift 的模块系统包含几种用于不同模块类型的加载器,它们都继承自 ModuleLoader 基类。

模块加载器架构

来源

模块加载过程

当导入模块时,Swift 会遵循以下过程来定位和加载它:

来源

模块加载过程包括:

  1. 模块搜索:系统在特定位置搜索模块

    • 使用 -I 指定的模块搜索路径
    • 使用 -F 指定的框架搜索路径
    • 标准库位置
    • SDK 路径
  2. 模块验证:对于缓存的模块,系统会检查

    • 与当前编译器版本的兼容性
    • 自模块构建以来依赖项是否已更改
    • 模块是否使用兼容的标志构建
  3. 模块缓存:模块会被缓存以提高性能

    • 缓存 .swiftmodule 文件以避免重新编译
    • 模块缓存由 -module-cache-path 控制

Clang 导入器

ClangImporter 是一个关键组件,它使 Swift 能够与 C、C++ 和 Objective-C 代码进行互操作。

Clang 导入器架构

来源

Clang 导入器处理以下事项:

  • 将 C/C++/Objective-C 声明转换为 Swift 声明
  • 将 C 类型映射到 Swift 类型
  • 将 Objective-C API 桥接到更符合 Swift 的接口
  • 通过桥接头管理 Objective-C 互操作性
  • 为导入的 C 模块创建 Swift 接口

类型映射示例

C/Objective-C 类型Swift 类型
int, short, 等。CInt, CShort, 等。
char *UnsafePointer<CChar>
void *UnsafeMutableRawPointer
NSString *字符串
NSArray<NSString *> *[String]
blockSwift 闭包
va_listCVaListPointer
id任意

来源

模块依赖

模块可以依赖于其他模块,并且这些依赖关系在系统中得到仔细跟踪。

模块依赖系统

来源

模块依赖关系有几个目的:

  • 确保所有必需的模块都已加载
  • 跟踪依赖项是否被重新导出
  • 检测循环依赖
  • 验证缓存的模块是否是最新的

模块序列化

Swift 模块可以被序列化为二进制 .swiftmodule 文件,用于分发和更快的加载。

序列化模块结构

来源

二进制模块序列化提供了几项优势

  • 比重新编译源代码加载更快
  • 通过延迟加载声明来减少内存使用
  • API 的紧凑二进制表示
  • 版本验证以确保兼容性

模块接口

Swift 还支持文本模块接口(.swiftinterface 文件),它提供模块 API 的稳定、基于源的表示。

ModuleInterfaceLoader 负责

  • 编译 .swiftinterface 文件为二进制模块
  • 缓存编译后的模块以提高性能
  • 加载缓存模块时验证依赖项
  • 支持跨 Swift 编译器版本的 ABI 稳定性

模块接口对于 Swift 的 ABI 稳定性尤为重要,因为它们确保可以在需要时从源代码重新构建模块,而无需依赖可能与不同编译器版本不兼容的不透明二进制格式。

来源

模块中的名称查找

名称查找是模块系统的基本操作,它允许 Swift 在模块边界之间查找声明。

来源

名称查找因模块类型而异

  • 源文件使用 SourceLookupCache 进行快速内存查找
  • Clang 模块使用专门的查找表来查找导入的声明
  • 序列化模块会在需要时反序列化查找表
  • 查找时会根据访问控制规则进行可见性检查

结论

Swift 的模块系统构成了语言代码组织和依赖管理的基础。它提供了一个强大的基础架构,用于

  • 将代码组织成逻辑、可重用的单元
  • 无缝导入 C、Objective-C 和 C++ 代码
  • 支持二进制模块分发,使用 .swiftmodule 文件
  • 通过 .swiftinterface 文件保持 ABI 稳定性
  • 通过缓存实现快速高效的编译

模块系统的架构允许 Swift 在支持与其他语言互操作性的同时,保持源代码和二进制分发模型的优势。

来源