Swift Package Manager C-互操作:非系统库 [英] Swift Package Manager C-interop: Non-system libraries

查看:186
本文介绍了Swift Package Manager C-互操作:非系统库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何使用Swift软件包管理器包含C代码(在我的情况下,是单个.c文件和头文件)而没有要求用户将我的C库安装到?

How can I use the Swift Package Manager to include C code (in my case, a single .c file and a header file) without requiring the user to install my C library into /usr/local/lib?

我曾考虑在主程序包的子目录中创建一个程序包,其中包含标头+ lib,并使用相对路径,最后使用swift build -Xlinker ./relative/path/to/mylib进行构建,但是我无法成功解决依赖关系,因为这是预期的成为一个独立的git仓库.错误消息是:

I had thought to create a Package in a subdirectory of my main package containing the header + lib, and use relative paths, and finally build with swift build -Xlinker ./relative/path/to/mylib, however I'm not having any success resolving the dependency since it's expected to be a standalone git repository. Error message is:

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

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

Moreover it's not clear to me whether using the -Xlinker flag is the correct approach.

我不能将桥接头文件与纯SwiftPM方法一起使用,并且在系统范围内安装我的库似乎是过分的,而且不太便于移植.

I can't use a bridging header with a pure SwiftPM approach and installing my library system-wide seems overkill as well as not very portable.

有什么想法吗?

推荐答案

我已经在此项目在github上.它通过将pthread_once_t包裹在C中并将其重新暴露给swift来代替它.这是一项有趣的练习,可以解决由于pthread_once_tdispatch_once无法直接使用而导致Swift试图限制您的情况.

I have done that in this project on github. It replaces pthread_once_t by wrapping it in C and re-exposing it to swift. It was done as a fun exercise in getting around what Swift tries to limit you into since pthread_once_t and dispatch_once are not available directly.

这是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目标.

You can easily replace the product library with an executable. The main part is that the product's targets needs to contain both the C and Swift targets needed to build.

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

Then in your targets section make the swift target lists the C target as a dependency.

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

You can learn more about the required layout for C targets in the SwiftPM Usage.md here

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

The C language targets are similar to Swift targets except that the C language libraries should contain a directory named include to hold the public headers.

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

To allow a Swift target to import a C language target, add a target dependency in the manifest file. Swift Package Manager will automatically generate a modulemap for each C language library target for these 3 cases:

  • 如果include/Foo/Foo.h存在并且Foo是该目录下的唯一目录 包含目录,然后include/Foo/Foo.h成为伞形标题.

  • If include/Foo/Foo.h exists and Foo is the only directory under the include directory then include/Foo/Foo.h becomes the umbrella header.

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

If include/Foo.h exists and include contains no other subdirectory then include/Foo.h becomes the umbrella header.

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

Otherwise if the include directory only contains header files and no other subdirectory, it becomes the umbrella directory.

对于复杂的include布局,可以自定义module.modulemap 提供在include内部.如果无法生成,SwiftPM将会出错 没有上述规则的模块图.

In case of complicated include layouts, a custom module.modulemap can be provided inside include. SwiftPM will error out if it can not generate a modulemap w.r.t the above rules.

对于可执行目标,仅允许使用一个有效的C语言主文件,即 在同一目标中包含main.cmain.cpp是无效的.

For executable targets, only one valid C language main file is allowed i.e. it is invalid to have main.c and main.cpp in the same target.

唯一重要的另一件事是,一旦将#import编译为兼容模块,您将如何真正地在C代码中进行操作.如果您使用import/Foo/Foo.h组织,则需要使用#include <Foo/Foo.h>;如果您使用import/Foo.h,则可以使用#import "Foo.h".

The only other important thing is how you actually do your #import in the C code once it is compiled as a compatible module. If you use the import/Foo/Foo.h organization you need to use #include <Foo/Foo.h> and if you do import/Foo.h you can use #import "Foo.h".

这篇关于Swift Package Manager C-互操作:非系统库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆