本文档解释了 Swift 如何处理模块加载和序列化,这是 Swift 编译器基础设施的关键部分。它描述了模块在内存中的表示方式、序列化到磁盘以及在需要时如何重新加载。本页面涵盖了序列化模块格式(.swiftmodule)和模块接口(.swiftinterface),以及用于优化编译时间的缓存机制。
有关 Clang 导入器的具体信息,请参阅 Clang 导入器。
Swift 编译器将代码组织成模块,模块是代码分发和命名空间的基本单元。一个模块由一个或多个文件单元组成,这些文件单元可以是 Swift 源文件、序列化模块或其他导入的内容。
来源: include/swift/AST/Module.h227-786 include/swift/AST/FileUnit.h29-38 include/swift/AST/ModuleLoader.h50-67
Swift 模块系统由几个关键类组成。
ModuleDecl:代表一个完整的模块,包含一个或多个文件单元。FileUnit:表示模块作用域声明容器的抽象基类。SourceFile:包含 Swift 源代码的文件。SerializedASTFile:一个二进制 .swiftmodule 文件。ClangModule:一个导入的 Clang 模块。BuiltinUnit:特殊的 Swift 内建模块。ModuleLoader:加载模块的抽象基类。SerializedModuleLoader:加载序列化的 .swiftmodule 文件。ModuleInterfaceLoader:加载 .swiftinterface 文件并从中构建模块。ClangImporter:导入 C、C++ 和 Objective-C 声明。SourceLoader:将 Swift 源文件直接作为模块加载。来源: lib/AST/Module.cpp749-802 include/swift/AST/FileUnit.h35-110 include/swift/AST/ModuleLoader.h50-67
当导入一个模块时,Swift 编译器会尝试通过各种加载器来定位和加载它,遵循特定的优先级顺序。
来源: lib/Serialization/SerializedModuleLoader.cpp200-260 lib/Frontend/ModuleInterfaceLoader.cpp505-580
模块加载器在各种搜索路径中查找模块,这些路径通过编译器选项指定。
-I 路径)-F 路径)在查找模块时,加载器会在此类路径中查找
.swiftmodule 文件或目录.swiftinterface 文件来源: lib/Serialization/SerializedModuleLoader.cpp143-264
Swift 模块被序列化为 .swiftmodule 文件,其中包含模块声明和类型的压缩位流表示。
来源: lib/Serialization/ModuleFile.h52-65 lib/Serialization/ModuleFileSharedCore.h31-43
序列化模块会跟踪其依赖项,以确保在依赖项更改时重新构建模块。依赖项包括:
每个依赖项都记录了检测更改所需的信息,例如:
来源: lib/Serialization/ModuleFile.h94-124 include/swift/Serialization/SerializationOptions.h70-97
模块接口(.swiftinterface 文件)是模块的文本表示形式,可以编译成二进制 .swiftmodule 文件。这是 Swift ABI 稳定性故事的关键部分,因为它允许模块在需要时从源代码重新构建。
来源: lib/Frontend/ModuleInterfaceLoader.cpp531-677 lib/Frontend/ModuleInterfaceBuilder.cpp98-180
使用复杂的缓存策略,尽可能避免从接口重新构建模块。ModuleInterfaceLoader
-module-cache-path 指定).swiftinterface 文件旁的邻近位置。-prebuilt-module-cache-path 指定)对于缓存的模块,加载器通过检查其依赖项来验证它们是否是最新的。
来源: lib/Frontend/ModuleInterfaceLoader.cpp65-104 lib/Frontend/ModuleInterfaceLoader.cpp605-645
在加载序列化模块之前,需要对其进行验证,以确保它与当前编译器和目标兼容。
来源: include/swift/Serialization/Validation.h37-88 lib/Serialization/ModuleFileSharedCore.cpp310-450
验证过程包括几项检查:
对于每项检查,如果验证失败,则会返回适当的错误代码。
来源: lib/Serialization/SerializedModuleLoader.cpp307-344 lib/Serialization/ModuleFile.cpp275-316
转发模块是一种特殊的 .swiftmodule,它指向另一个模块文件,通常在预构建缓存中。它们为基于哈希的预构建模块添加了基于修改时间的依赖项。
来源: lib/Frontend/ModuleInterfaceLoader.cpp65-145
预构建模块是预编译的 .swiftmodule 文件,通常随 SDK 一起发布。它们使用内容哈希而不是修改时间来进行依赖项跟踪,使其更具可重定位性。
来源: lib/Frontend/ModuleInterfaceLoader.cpp658-686
Swift 编译器会跟踪模块之间的依赖关系,以确保正确的构建并实现增量编译。
来源: include/swift/AST/ModuleLoader.h95-119 lib/AST/ModuleLoader.cpp35-54
模块具有不同类型的依赖关系,这些依赖关系具有不同的可见性规则
这些可见性规则会影响导入模块时传递性地加载依赖项的方式。
来源: lib/Serialization/ModuleFile.cpp318-332 lib/Serialization/SerializedModuleLoader.cpp479-526
Swift 使用高效的查找机制来查找已加载模块中的声明。
来源: lib/AST/Module.cpp973-986 lib/Serialization/ModuleFile.cpp345-372
模块系统使用多种缓存机制来提高性能
SourceLookupCache:缓存源文件中的查找来源: lib/AST/Module.cpp139-247 lib/AST/Module.cpp920-928
Swift 的模块加载和序列化系统是编译器基础设施的关键组成部分,它支持单独编译、快速增量构建和 ABI 稳定性。该系统平衡了对性能的需求以及现代编译器所需的灵活性。
该系统的关键方面包括:
了解此系统对于任何从事 Swift 编译器或开发与 Swift 模块交互的工具的人来说都至关重要。