在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
原文地址: http://andelf.github.io/blog/2014/06/19/modules-for-swift/
Swift 中模块是什么?当写下 Swift 中一句 本文解决如下问题
第一部分 Clang 模块(系统模块)Clang 模块是来自系统底层的模块,一般是 C/ObjC 的头文件。原始 API 通过它们暴露给 Swift ,编译时需要链接到对应的 Library。 例如 我可不觉得这些定义全部都是官方生成后给封装进去的。所以在整个 Xcode-6 beta2 目录树里进行了探索。 在 Xcode 目录寻找相关信息,最后目标锁定到了一个特殊的文件名 原来这个文件叫 Module map(这个名字还真是缺乏想象力),属于 llvm 的 Module 系统。本来是用来颠覆传统的 C/C++/Objc 中的 关于 llvm Module 系统2012 年提出概念,所以其实这个东西已经很早就实现了 。简单说就是用树形的结构化描述来取代以往的平坦式
所以这么好的一个东西, Apple 作为 llvm 的主力,在它的下一代语言中采用几乎是一定的。 算了,我是个半路出家的,之前没接触过 iOS / MacOSX 开发,其实 2013 年的 WWDC, Apple 为 Objective-C 加入的 module.map 文件
文件的内容以 module MyLib { explicit module A { header "A.h" export * } explicit module B { header "B.h" export * } }
类似上面的语法,描述了 官方文档 [^3] 中有更多相关内容,可以描述框架,描述系统头文件,控制导出的范围,描述依赖关系,链接参数等等。这里不多叙述,举个 libcurl 的例子: module curl [system] [extern_c] { header "/usr/include/curl/curl.h" link "curl" export * }
将此 Xcode 选项位于 Build Settings 下面的 Swift Compiler – Search Paths 。添加路劲即可。 再举个复杂点的 framework module SDL2 [system] { umbrella header "SDL.h" link -framework SDL2 module Version { header "SDL_version.h" export * } module Event { header "SDL_events.h" export * } // .... export * module * { export * } }
小结Swift 的 C 模块(也是它的标准库部分)完全就是 llvm 的 Module 系统,在 import search path 的所有 module.map 中的模块都可以被识别,唯一缺点可能是如果有过于复杂用到太多高级 C 或者黑暗 C 语法的函数,无法很好识别,相信以后的版本会有所改善。 所以当有人问 Swift 到底有多少标准库的时候,答案就是,基本上系统里所有的 Objective-C 和 C 头文件都可以调用。自 iOS 7 时代,这些头文件就已经被组织为 Module 了,包括标准 C 库 一些有意思的模块可以探索探索,比如 另外 Swift 的 Xcode 项目的 Build Settings , Apple LLVM 6.0 – Language – Modules 有项目对 Module 支持的相关选项,默认是打开的。 第二部分 Swift 模块说完了系统模块,该说 Swift 模块了。 Swift 自身的这个系统还是很赞的。 本节介绍怎样用 Swift 创建一个可 import 的模块。 几个文件类型先清楚几个文件类型。假设
TODO: 目前有个疑问就是 .swift 源码文件先明确一个概念,一个 .swift 文件执行是从它的第一条非声明语句(表达式、控制结构)开始的,同时包括声明中的赋值部分(对应为 mov 指令或者 lea 指令),所有这些语句,构成了该 .swift 文件的 而所有的声明,包括结构体、类、枚举及其方法,都不属于 程序的入口是隐含的一个 不是所有的 .swift 文件都可以作为模块,目前看,任何包含表达式语句和控制控制的 .swift 文件都不可以作为模块。正常情况下模块可以包含全局变量( 这里说的表达式指 expression ,语句指 statement ,声明指 declaration 。可能和有些人对相关概念的定义不同。实际上我特无奈有些人纠结于概念问题,而不是问题本身,本来翻译过来的舶来品就有可能有误差,当你明白那指的是什么的时候,就可以了。 模块编译方法这里先以命令行操作为例, xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) ModName.swift -emit-library -emit-module -module-name ModName -v -o libswiftModName.dylib -module-link-name swiftModName 执行后获得 这三个文件就可以表示一个可 import 的 Swift 模块。目前看起来 dylib 是必须得有的,否则链接过程报错。实际感觉 多个源码文件直接依次传递所有文件名即可。 静态链接库 命令行参数解释相关命令行参数:
使用模块使用模块就很简单了,记住两个参数:
例如: xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) mymodtest.swift -I. -L. 此时表示所有 module 文件都在当前目录。 这两个选项都可以在 Xcode 中指定,所以如果你有小伙伴编译好的 module 想在你的项目里用是完全 ok 的。 For Xcode很不幸,没能在 Xcode 中找到编译模块的相关方法。等我发现如何搞定的时候我会补上这个坑。 不过在任何含 Swift 项目的编译过程中, 第三部分 瞎分析 .swiftmodule 文件简单分析下一个 .swiftmodule 所包含的信息。 Foundation这里先以标准库的 用 hexdump 查看发现它包含所有导出符号,以及 mangled name 。还有个文件列表,表示它是从哪些文件获得的(可以是 .swift 也可以是 .swiftmodule )。 用 strings 列出内容,发现 Foundation 库有如下特征: ... Foundation LLVM 3.5svn /SourceCache/compiler_KLONDIKE/compiler_KLONDIKE-600.0.34.4.8/src/tools/swift/stdlib/objc/Foundation/Foundation.swift /SourceCache/compiler_KLONDIKE/compiler_KLONDIKE-600.0.34.4.8/src/tools/swift/stdlib/objc/Foundation/KVO.swift /SourceCache/compiler_KLONDIKE/compiler_KLONDIKE-600.0.34.4.8/src/tools/swift/stdlib/objc/Foundation/NSStringAPI.swift CoreFoundation Foundation Swift swiftFoundation ...
可以大胆猜测对应下:
我由此猜测, 分析其他类似模块也得到相同结果。 Swift 标准库接下来有点好奇标准库 Swift 是怎么实现的。得到如下结果。 节选重要部分到 我的 Gist 里面有些很有意思的信息,有兴趣的同学可以去看看。 依赖模块 SwiftShims 是一个 其中 结论LLVM Module 作为 Apple 提出的特性,已经被 Swift 完全采用,直接在它基础上建立了自己的模块系统。我相信它会影响到我们处理第三方库的方式方法。相信不久就会有相关工具基于它来管理依赖关系,比如老的 cocoapods4 可以加入新特性。 用 Swift 写模块目前并没有很好的 IDE 支持,所以不是很方便。基于猜测验证,上面的方法可以实现在 Swift 里 import Swift 模块,方法和结果看起来完全和官方模块相同。 Swift 的标准库完全是上面两种模块的结合体,用 Swift 模块封装 Clang 模块。这就解决了文章一开始提出的问题:为什么标准库大部分看起来是自动生成代码,少部分又好像是人工写的接口代码。 参考文献 |
请发表评论