我在 github 上的 this project 中完成了该操作。它通过将 pthread_once_t 包装在 C 中并将其重新暴露给 swift 来替换它。这是一个有趣的练习,可以绕过 Swift 试图限制你的东西,因为 pthread_once_t 和 dispatch_once 不能直接使用。
这是Package.swift 文件的精简版:
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "Once",
products: [
.library(
name: "Once",
targets: ["OnceC", "Once"]),
],
dependencies: [
],
targets: [
.target(
name: "OnceC",
dependencies: [],
path: "Sources/OnceC"),
.target(
name: "Once",
dependencies: ["OnceC"],
path: "Sources/Swift"),
.testTarget(
name: "OnceTests",
dependencies: ["Once"]),
]
)
您可以轻松地将产品库替换为可执行文件。主要部分是产品的目标需要包含构建所需的 C 和 Swift 目标。
然后在您的目标部分中,让 swift 目标将 C 目标列为依赖项。
您可以在 SwiftPM Usage.md here 中了解有关 C 目标所需布局的更多信息
C 语言目标
C 语言目标类似于 Swift 目标,不同之处在于 C 语言
库应该包含一个名为include 的目录来保存公共头文件。
要允许 Swift 目标导入 C 语言目标,请添加目标
清单文件中的依赖项。 Swift 包管理器将
自动为这些 C 语言库目标生成一个模块映射
3个案例:
如果include/Foo/Foo.h 存在并且Foo 是该目录下的唯一目录
包含目录然后include/Foo/Foo.h 成为伞头。
如果include/Foo.h 存在且include 不包含其他子目录,则
include/Foo.h 成为伞头。
否则如果include目录只包含头文件而没有其他
子目录,它成为总目录。
如果是复杂的include 布局,可以自定义module.modulemap
在include 内提供。 SwiftPM 无法生成时会报错
一个符合上述规则的模块图。
对于可执行目标,只允许一个有效的 C 语言主文件,即它
main.c 和 main.cpp 在同一个目标中是无效的。
另一个重要的事情是,一旦将 C 代码编译为兼容模块,您实际上如何在 C 代码中执行您的 #import。如果您使用import/Foo/Foo.h 组织,则需要使用#include <Foo/Foo.h>,如果您使用import/Foo.h,则可以使用#import "Foo.h"。