linux - Swift on Linux - 导入第三方模块

标签 linux swift import

我正在 Linux 上编写一些入门级的 swift 代码作为学习练习。

作为一般任务,我希望在自己的代码中使用第三方 Swift 模块。我们称这个模块为“Foo”。 Foo 模块有一个 Package.swift 文件,在该目录中运行 swift build 后,它创建了 .build/debug/libFoo.so

现在我想用它做两件事:

  1. 能够在 REPL 中导入 Foo
  2. 能够在我自己的 swift 程序中导入 Foo,或许可以通过链接到这个共享对象。

我觉得这两个任务是相关的,所以现在它们在同一个问题中。

对于 1.,我不明白 REPL 是如何“找到”包的。我试过 swift -F .build/debug -framework Foo 但我收到“没有这样的模块”错误。我还尝试了 swift -I .build/debug,结果相同。

对于 2.,我检查了 swiftc --help 并且有 -L-l 选项但是我找不到使用这些的正确方法:

$ swiftc main.swift -L ../foo.git/.build/debug -llibFoo.so
main.swift:1:8: error: no such module 'Foo'
import Foo
       ^

我正在使用 Swift 2.2 或 3.0(使用 swim 而不是 swift build 用于 2.2,因为没有 swift build - 但我相信它会产生相同的输出)。

请注意,我了解 swift build 可以自动下载和构建第三方模块,但是我想知道如何合并磁盘上的模块,因为它们可能是我自己的工作-进度模块。


编辑:我尝试了一个 swift3 的小实验,基于一个发现,你可以使用本地路径作为包的 dependencies: 列表中的 url: 参数,至少促进本地发展。

我创建了一个目录 BarBar/Package.swift:

import PackageDescription
let package = Package(name: "Bar")

我还创建了 Bar/Sources/bar.swift 包含:

public func bar(arg: Int) -> Int {
    return arg * 2
}

目的是模块 Bar 提供名为 bar(arg:) 的函数。

我做了一个 git initgit add .git commit -m "Initial commit." 然后是 git tag 1.0.0 为这个模块创建一个标记的 local git repo。

然后回到顶层,我创建了目录 FooFoo/Package.swift:

import PackageDescription
let package = Package(
    name: "Foo",
    dependencies: [ .Package(url: "../Bar", majorVersion: 1) ]
)

注意 ../Bar 的相对路径。

我还创建了 Foo/Sources/main.swift:

import Bar
print(bar(arg: 11))

现在,当我在 Fooswift build 时,它会克隆 Bar 并构建它。但是然后我收到以下错误; 没有这样的模块:

$ swift build
Compile Swift Module 'Bar' (1 sources)
Compile Swift Module 'Foo' (1 sources)
.../Foo/Sources/main.swift:1:8: error: no such module 'Bar'
import Bar
       ^
<unknown>:0: error: build had 1 command failures
error: exit(1): .../swift-3.0-PREVIEW-4-ubuntu14.04/usr/bin/swift-build-tool -f .../Foo/.build/debug.yaml

奇怪的是,如果我再次执行完全相同的构建命令,我会得到一个不同的错误:

$ swift build
Compile Swift Module 'Foo' (1 sources)
Linking .build/debug/Bar
.../Foo/Sources/main.swift:3:7: error: use of unresolved identifier 'bar'
print(bar(arg: 11))
      ^~~
<unknown>:0: error: build had 1 command failures
error: exit(1): .../swift-3.0-PREVIEW-4-ubuntu14.04/usr/bin/swift-build-tool -f .../Foo/.build/debug.yaml

我曾希望这会奏效。

最佳答案

Be able to import Foo in my own swift program, perhaps by linking with this shared object.

使用您在“编辑”之后在问题中发布的示例,如果您使用 swift build,这似乎可以正常工作。 Swift Package Manager将为您处理所有依赖项,即使它们在磁盘上(这适用于 Swift 3 和 4):

$ cd Foo

$ swift build
Cloning /path/to/Bar
HEAD is now at 0c3fd6e Initial commit.
Resolved version: 1.0.0
Compile Swift Module 'Bar' (1 sources)
Compile Swift Module 'Foo' (1 sources)
Linking ./.build/debug/Foo

$ .build/debug/Foo
22

请注意 Foo/.build/debug 不包含任何 .so 文件:

$ ls Foo/.build/debug
Bar.build  Bar.swiftdoc  Bar.swiftmodule  Foo  Foo.build  Foo.swiftdoc  Foo.swiftmodule  ModuleCache

我相信应该使用 .swiftdoc 和 .swiftmodule 文件。

Be able to import Foo in the REPL.

这部分有点乱,但我找到了解决方案 here .要将其应用于您的示例,您有两种选择:

  • Use swift build with extra flags (这适用于 Swift 3 和 4):

    $ cd Bar
    
    $ swift build -Xswiftc -emit-library
    Compile Swift Module 'Bar' (1 sources)
    
    $ swift -I .build/debug -L . -lBar
      1> import Bar
      2> bar(arg: 11) 
    $R0: Int = 22
      3> 
    

    这会在当前目录中创建 libBar.so:

    $ ls
    libBar.so  Package.swift  Sources
    


  • Update your Package.manifest (这是 Swift 4 特有的):

    1. 更新后的 Package.manifest 看起来像这样:

      // swift-tools-version:4.0
      import PackageDescription
      
      let package = Package(
          name: "Bar",
          products: [
              .library(
                  name: "Bar",
                  type: .dynamic,
                  targets: ["Bar"]),
          ],
          targets: [
              .target(
                  name: "Bar",
                  dependencies: [],
                  path: "Sources"),
          ]
      )
      
    2. 这就是构建和调用 REPL 的方式:

      $ cd Bar
      
      $ swift build
      Compile Swift Module 'Bar' (1 sources)
      Linking ./.build/x86_64-unknown-linux/debug/libBar.so
      
      $ swift -I .build/debug -L .build/debug -lBar
        1> import Bar 
        2> bar(arg: 11) 
      $R0: Int = 22
        3>  
      

    这会在 .build/debug 目录中创建 libBar.so:

    $ ls .build/debug
    Bar.build  Bar.swiftdoc  Bar.swiftmodule  libBar.so  ModuleCache
    

如果您无法重现这些结果,我建议清除所有 .build 目录和 .so 文件,并安装一个干净的 Swift 版本(为此我推荐 swiftenv)。

关于linux - Swift on Linux - 导入第三方模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39071564/

相关文章:

ios - 欢迎屏幕中的视频使用 AVPlayer 导致内存泄漏?

ios - 将 SKNode 从其当前位置移动一个 Tile

java - Android DownloadManager 不知道文件下载到哪里

github - 如何从 Google Colab 的 Github 存储库导入自定义模块?

linux - Powershell POST 到 Linux curl

linux - shell 脚本 grep 只处理文件的最后一行

linux - 使用 openssl 作为命令行计算 AES128 CMAC

linux - 如何在 Linux 上将正在运行的进程的标准输入从键盘更改为文件?

swift - 处理自动布局和核心动画之间的冲突

R - 从 .txt 文件中读取特定行之后的行