Swift Package Manager C-互操作:非系统库 [英] Swift Package Manager C-interop: Non-system libraries
问题描述
如何使用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_t
和dispatch_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 andFoo
is the only directory under the include directory theninclude/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.c
和main.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屋!