【问题标题】:Swift Package Manager C-interop: Non-system librariesSwift Package Manager C-interop:非系统库
【发布时间】:2018-09-21 14:27:57
【问题描述】:

如何使用 Swift 包管理器来包含 C 代码(在我的例子中,一个 .c 文件和一个头文件) 不需要用户将我的 C 库安装到 @987654322 @?

我曾想过在包含头文件 + lib 的主包的子目录中创建一个包,并使用相对路径,最后使用swift build -Xlinker ./relative/path/to/mylib 构建,但是我没有成功解决依赖关系,因为它是预期的成为一个独立的 git 存储库。错误信息是:

error: failed to clone; fatal: repository '/absolute/path/to/mylib' does not exist

此外,我不清楚使用 -Xlinker 标志是否是正确的方法。

我不能使用带有纯 SwiftPM 方法的桥接头,并且在系统范围内安装我的库似乎有点矫枉过正,而且不太便携。

有什么想法吗?

【问题讨论】:

    标签: c swift interop swift-package-manager


    【解决方案1】:

    我在 github 上的 this project 中完成了该操作。它通过将 pthread_once_t 包装在 C 中并将其重新暴露给 swift 来替换它。这是一个有趣的练习,可以绕过 Swift 试图限制你的东西,因为 pthread_once_tdispatch_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.modulemapinclude 内提供。 SwiftPM 无法生成时会报错 一个符合上述规则的模块图。

    对于可执行目标,只允许一个有效的 C 语言主文件,即它 main.cmain.cpp 在同一个目标中是无效的。


    另一个重要的事情是,一旦将 C 代码编译为兼容模块,您实际上如何在 C 代码中执行您的 #import。如果您使用import/Foo/Foo.h 组织,则需要使用#include <Foo/Foo.h>,如果您使用import/Foo.h,则可以使用#import "Foo.h"

    【讨论】:

    • 天哪,这太棒了,感谢您的回答和示例项目,正是我想要弄清楚的。
    • 如果您有任何问题,请在此处提问,我很乐意帮助您将所有信息保存在一个地方。
    • 我正在尝试将项目从 Xcode 移动到在 Ubuntu 下编译,因此需要将桥接头带入包中。它应该很简单,但我找不到任何方法来做到这一点。这似乎是最接近的,但我仍然不知道该怎么做。以某种方式将包含打包到一个单独的库中真的有必要吗?如果是,如何?
    • 当您说桥接头时,您是指 ObjC 桥接头吗?如果是这样,则不支持这些。不过,您将需要一个适当的伞形标题或模块映射。
    • 也许有人觉得link to modulemap file syntax有用
    猜你喜欢
    • 2023-02-10
    • 2022-01-16
    • 1970-01-01
    • 2017-02-08
    • 1970-01-01
    • 2020-02-07
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    相关资源
    最近更新 更多