Swift Package Manager C-interop:非系统库

时间:2018-04-11 15:54:09

标签: c swift interop 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方法的桥接头,并且在系统范围内安装我的库似乎有点矫枉过正,也不是非常便携。

有什么想法吗?

1 个答案:

答案 0 :(得分:6)

我在github上的this project中完成了这个。它通过将其包装在C中并将其重新暴露给swift来替换@echo off goto run_tests :stripquotes FOR /F "tokens=1,*" %%A IN ('echo.%*') DO set %%~A=%%~B goto :EOF :test call :stripquotes mynewvar %* echo DEBUG: mynewvar is now %mynewvar% start "" "%mynewvar%\app.exe" "par am 1" param2 "par am 3" goto :EOF :run_tests set OpenOCD_bin_Path=c:\foo bar\baz call :test %OpenOCD_bin_Path% set OpenOCD_bin_Path="c:\foo bar\baz" call :test %OpenOCD_bin_Path% 。这是一个有趣的练习,可以解决Swift试图限制你进入的问题,因为pthread_once_t并且pthread_once_t无法直接使用。

以下是dispatch_once文件的精简版本:

Package.swift

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

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

您可以在SwiftPM Usage.md here

中详细了解C目标所需的布局

C语言目标

C语言目标与Swift目标类似,但C语言除外 库应包含名为// 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"]), ] ) 的目录以保存公共标头。

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

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

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

  • 否则,如果include/Foo.h目录只包含头文件而不包含其他文件 子目录,它成为伞状目录。

如果出现复杂的include布局,则可以使用自定义includemodule.modulemap内提供。如果无法生成,SwiftPM将会出错 一个模块映射,符合上述规则。

对于可执行目标,只允许一个有效的C语言主文件,即它 <{1}}和include位于同一目标中无效。

唯一重要的一点是,在将C代码编译为兼容模块后,如何在C代码中实际执行main.c。如果您使用main.cpp组织,则需要使用#import,如果使用import/Foo/Foo.h,则可以使用#include <Foo/Foo.h>