Swift Package Manager C-interop:非系统库

Sam*_*Sam 7 c interop swift swift-package-manager

如何使用Swift包管理器包含C代码(在我的情况下,单个.c文件和头文件),无需用户安装我的C库/usr/local/lib

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

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

此外,我不清楚使用-Xlinker旗帜是否正确.

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

有任何想法吗?

bsc*_*ern 8

我在github的这个项目中做到了这一点.它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"]),
        ]
)
Run Code Online (Sandbox Code Playgroud)

您可以使用可执行文件轻松替换产品库.主要部分是产品的目标需要包含构建所需的C和Swift目标.

然后在目标部分中,使swift目标将C目标列为依赖项.


您可以在此处了解有关SwiftPM Usage.md中C目标所需布局的更多信息

C语言目标

C语言目标类似于Swift目标,除了C语言库应该包含一个名为include保存公共头的目录.

要允许Swift目标导入C语言目标,请在清单文件中添加目标依赖项.对于这3种情况,Swift Package Manager将自动为每个C语言库目标生成一个模块映射:

  • 如果include/Foo/Foo.h存在并且Foo是include目录下的唯一目录,则include/Foo/Foo.h成为伞标题.

  • 如果include/Foo.h存在include且不包含其他子目录,则 include/Foo.h成为伞标题.

  • 否则,如果include目录只包含头文件而没有其他子目录,则它将成为伞状目录.

如果include布局复杂,module.modulemap可以在里面提供自定义include.如果无法按照上述规则生成模块映射,SwiftPM将会出错.

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


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

  • 也许有人发现有用的[模块映射文件语法链接](https://clang.llvm.org/docs/Modules.html#module-map-language) (2认同)