2016-08-22 71 views
6

我在Linux上編寫一些入門級的swift代碼作爲學習練習。Linux上的Swift - 導入第三方模塊

作爲一項常規任務,我希望在自己的代碼中使用第三方Swift模塊。我們稱這個模塊爲「Foo」。 Foo模塊有一個Package.swift文件,在該目錄中運行swift build後,它創建了.build/debug/libFoo.so

現在我希望做兩件事情是:

  1. 能夠import Foo在REPL。
  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 
    ^

我同時使用/無論是斯威夫特2.2或3.0 (對於2.2使用swim而不是swift build,因爲沒有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創建此模塊標記本地混帳回購協議。

然後回到在頂層我創建目錄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)) 

現在,當我swift build裏面Foo,它克隆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 

奇怪的是,如果我再次做同樣的build命令,我得到一個不同的錯誤:

$ 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 

我希望這會工作。

+0

我無法重現您最近一次嘗試的問題:我按照您所描述的步驟和'Foo'成功導入了'Bar'並稱爲'bar'函數。另一個問題:你是如何設法建立一個產生'libFoo.so'庫的模塊?當我從你最新的例子中構建'Bar'模塊時,在'.build/debug'中沒有'libBar.so' – OmniProg

+0

@OmniProg感謝你試用它。我不確定它爲什麼對你有用。我會嘗試使用不同版本的Swift。令人鼓舞的是,它確實對你有用。關於第二點,在我創建Foo/Bar示例之前,我使用了一個不叫'Bar'(它被稱爲Swifter)的第三方模塊,它確實生成了libSwifter.so文件,但我想要把這個問題作爲一個普遍問題來提出。我假定.so是標準輸出,但顯然不是。我沒有看到Swifter中的任何東西可以解釋爲什麼它會生成一個.so。 – meowsqueak

+0

對不起,忘了提及我使用的是完全相同的版本,swift-3.0-PREVIEW-4-ubuntu14.04,所以可能值得清理所有派生文件並重新嘗試。 – OmniProg

回答

0

正如文檔中所述,Linux上的Swift及其軟件包管理器工作正在進行中,所以難怪有缺陷和缺乏信息。然而,這是我通過實驗和閱讀幫助而找到的。

如果模塊Foo有一個圖書館,libFoo.so,在/ModuleLocation/LibLocationFoo.swiftmodule,然後就可以導入和迅捷的程序中使用Foo,稱之爲main.swift,然後通過做

swiftc -I /ModuleLocation -L /LibLocation -lFoo main.swift 
編譯

人們也可以做到這一點在REPL通過啓動它作爲

swift -I /ModuleLocation -L /LibLocation -lFoo 

即基本上給它相同的參數爲swiftc。順便說一句,如果模塊使用swift build構建,則ModuleLocation可能與LibLocation相同。

正如我在前面的評論中提及,與FooBar你的榜樣,無論是使用內置swift build,爲我工作得很好,所以我不能重現該問題。

順便說一句,除了閱讀swift.org文檔和命令行幫助外,還可以通過運行swift build和其他帶-v標誌的命令來蒐集大量有趣且潛在有用的信息。要了解可用的一些隱藏的選項與swiftc

swiftc -help-hidden 
2

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

使用你在你的問題發佈後,例如「編輯」,這似乎很好地工作只要你使用swift build。該Swift Package Manager將處理所有的依賴你,即使他們是在磁盤上(這適用於斯威夫特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 

注意,美孚/ .build /調試不包含任何。這樣的文件:

$ 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(本工程對斯威夫特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(這是針對雨燕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 /調試目錄中創建libBar.so:

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

如果你無法重現這些結果,我會建議清理出任何.build目錄和.so文件,並安裝一個乾淨的版本的雨燕(我建議swiftenv此)。