Xcode 不提供
libbz2
的 Swift 包装器或模块映射文件。如果我想在 Swift 中使用 zlib
,我可以简单地这样做
import zlib
但是我该如何使用
libbz2
?我在网上找到的所有解决方案都建议三个解决方案之一:
创建一个混合(Swift + ObjC)Xcode 项目,将其链接到
libbzip2
并将 #include <bzlib.h>
添加到 Swift 桥接头 -> 此解决方案不起作用,因为我不需要 Xcode 项目。
创建您自己的本机 C/Obj-C 包装框架,然后定义可加载模块。 -> 这个解决方案不起作用,因为我不想将 C/Obj-C 代码或对 C 编译器的显式依赖项添加到项目中(Swift 目前总是附带 C 编译器,但我不想依赖它这将永远如此)。
定义一个 Swift 包。 -> 此解决方案不起作用,因为我不希望依赖 Swift 数据包管理器或任何自定义 Swift 包(尤其是没有第三方包!)
bz2 库默认安装在系统上,并且 SDK 会安装标头,那么为什么我不能在 Swift 中以某种方式使用它们呢?
技巧是简单地定义一个自己的模块映射文件并使用您自己的简单桥接标头。该文件将被命名为
module.modulemap
并具有以下内容:
module bzlib [system] {
header "bzlib-module.h"
link "bz2"
}
模块映射文件只能使用相对路径(相对于模块映射文件本身)或绝对路径引用标头。两者都没有意义,因为 SDK 嵌入在 Xcode 中并且可以更改位置,例如当您重命名 Xcode 时(因为您可能需要安装不同的 Xcode 版本)或当您移动 Xcode 时(因为 Xcode 不必在
/Applications
甚至主驱动器上抵抗)。
这就是为什么您创建自己的桥接标头,名为
bzlib-module.h
,其内容只是:
#include <bzlib.h>
正如
<...>
告诉 Swift,这是一个系统标头,因此它将在系统标头的标准位置中搜索它,该位置是当前活动 SDK 中的目录(请参阅 xcrun
和 xcurn --show-sdk-path
)。
现在您可以简单地执行以下操作:
import bzlib
var bzStream = bz_stream()
let result = BZ2_bzCompressInit(&bzStream, 9, 0, 30)
print("Result: \(result)")
并使用
进行编译swiftc -o bztest -I . bztest.swift
-I .
是让Swift在当前工作目录中查找模块映射文件,否则它只会在默认头搜索位置中查找那些文件。如果您的模块映射文件位于其他位置,您可以使用该路径而不是 .
。
或者您也可以直接引用模块映射文件
swiftc -Xcc -fmodule-map-file=<file>
在这种情况下,文件也可以有任何名称,不必命名为
module.modulemap
。