Swift模組系統研究

2021-09-25 11:28:29 字數 4679 閱讀 9569

explicit module b  

}

module curl [system] [extern_c]
將此 module.map 檔案放入任意資料夾,通過 xcode 選項或者命令列引數,新增路徑到 import search path (swift 的 -i 引數)。 然後就可以在 swift **裡直接通過 import curl 匯入所有的介面函式、結構體、常量等,(實測,發現 curl_easy_setopt 無法自動匯入,看起來是宣告語法太複雜導致)。甚至可以直接從 swift repl 呼叫,體驗指令碼語言直譯器般的快感(因為我們已經指定了鏈結到 curl 庫)。

xcode 選項位於 build settings 下面的 swift compiler – search paths 。新增路勁即可。

再舉個複雜點的 sdl2.framework 的例子,看看如何實現樹形的模組結構,這個需要把 module.map 放到 .framework 目錄裡

framework module sdl2 [system]

module event

// ....

export *

module *

}小結swift 的 c 模組(也是它的標準庫部分)完全就是 llvm 的 module 系統,在 import search path 的所有 module.map 中的模組都可以被識別,唯一缺點可能是如果有過於複雜用到太多高階 c 或者黑暗 c 語法的函式,無法很好識別,相信以後的版本會有所改善。

所以當有人問 swift 到底有多少標準庫的時候,答案就是,基本上系統裡所有的 objective-c 和 c 標頭檔案都可以呼叫。自 ios 7 時代,這些標頭檔案就已經被組織為 module 了,包括標準 c 庫 darwin.c。同樣因為 module 系統來自於傳統的 c/c++/objc 標頭檔案,所以 swift 雖然可以有 import moda.modb.modc 的語句,但是整個模組函式名字空間還是平坦的。

一些有意思的模組可以探索探索,比如 simd,比如 python(沒錯是的,直接呼叫 python 直譯器)等。

另外 swift 的 -module-cache-path 引數可以控制這類模組預編譯頭的存放位置( .pcm 檔案: pre compiled module)。

第二部分 swift 模組

swift 建立乙個可 import 的模組:

幾個檔案型別

***先清楚幾個檔案型別。假設 modname.swift 是我們的 swift 原始碼檔案。

而所有的宣告,包括結構體、類、列舉及其方法,都不屬於 top_level_code() **部分,其中的**邏輯,包含在其他區域,top_level_code() 可以直接呼叫他們。

程式的入口是隱含的乙個 main(argc, ar**) 函式,該函式執行邏輯是設定全域性變數 c_argc c_ar**,然後呼叫 top_level_code()。

不是所有的 .swift 檔案都可以作為模組,目前看,任何包含表示式語句和控制控制的 .swift 檔案都不可以作為模組。正常情況下模組可以包含全域性變數(var)、全域性常量(let)、結構體(struct)、類(class)、列舉(enum)、協議(protocol)、擴充套件(extension)、函式(func)、以及全域性屬性(var )。這裡的全域性,指的是定義在 top level 。

這裡說的表示式指 expression ,語句指 statement ,宣告指 declaration 。可能和有些人對相關概念的定義不同。實際上我特無奈有些人糾結於概念問題,而不是問題本身,本來翻譯過來的舶來品就有可能有誤差,當你明白那指的是什麼 的時候,就可以了。

模組編譯方法

這裡先以命令列操作為例,

xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) modname.swift -emit-library -emit-module -module-name modname -v -o libswiftmodname.dylib -module-link-name swiftmodname
執行後獲得 modname.swiftdoc、modname.swiftmodule、libswiftmodname.dylib.

這三個檔案就可以表示乙個可 import 的 swift 模組。目前看起來 dylib 是必須得有的,否則鏈結過程報錯。實際感覺 .swiftmodule 檔案所包含的資訊還需要繼續挖掘挖掘。

多個原始碼檔案直接依次傳遞所有檔名即可。

靜態鏈結庫 .a 目前還沒有找到方法, -xlinker -static 會報錯。

命令列引數解釋

相關命令列引數:

-module-name name of the module to build 模組名

-emit-library 編譯為鏈結庫檔案

-emit-module-path

emit an importable module to 編譯模組到路徑(全路徑,包含檔名)

-emit-module emit an importable module

-module-link-name library to link against when using this module 該模組的鏈結庫名,就是 libswiftmodname.dylib,這個資訊會直接寫入到 .swiftmodule

使用模組

使用模組就很簡單了,記住兩個引數:

-i 表示 import search path ,前面介紹過,保證 .swiftmodule 檔案可以在 import search path 找到(這點很類似 module.map 檔案,找得到這個就可以 import 可以編譯)

-l 表示 鏈結庫搜尋路徑,保證 .dylib 檔案可以在其中找到,如果已經在系統鏈結庫目錄中,就不需要這個引數。

例如:xcrun swift -sdk $(xcrun --show-sdk-path --sdk macosx) mymodtest.swift -i. -l.

此時表示所有 module 檔案都在當前目錄。

for xcode

很不幸,沒能在 xcode 中找到編譯模組的相關方法。等我發現如何搞定的時候我會補上這個坑。

不過在任何含 swift 專案的編譯過程中, .swiftmodule 檔案總是伴隨著 .o 檔案傳遞。

第三部分 瞎分析 .swiftmodule 檔案

foundation

這裡先以標準庫的 foundation.swiftmodule 下手。

用 hexdump 檢視發現它包含所有匯出符號,以及 mangled name 。還有個檔案列表,表示它是從哪些檔案獲得的(可以是 .swift 也可以是 .swiftmodule )。

用 strings 列出內容,發現 foundation 庫有如下特徵:

... 

foundation

llvm 3.5svn

/sourcecache/compiler_klondike/compiler_klondike-600.0.34.4.8/src/tools/swift/stdlib/objc/foundation/foundation.swift

/sourcecache/compiler_klondike/compiler_klondike-600.0.34.4.8/src/tools/swift/stdlib/objc/foundation/kvo.swift

/sourcecache/compiler_klondike/compiler_klondike-600.0.34.4.8/src/tools/swift/stdlib/objc/foundation/nsstringapi.swift

corefoundation

foundation

swift

swiftfoundation

...

可以大膽猜測對應下:

-module-name => foundation

編譯環境 => llvm 3.5svn

原始檔列表 => …

依賴列表 => corefoundation, foundation, swift

-module-link-name => swiftfoundation

我由此猜測, foundation 的確是只有少量 swift **做橋接。然後通過 clang 模組將剩下工作交到底層。

分析其他類似模組也得到相同結果。

swift 標準庫

接下來有點好奇標準庫 swift 是怎麼實現的。得到如下結果。

節選重要部分到 我的 gist

裡面有些很有意思的資訊,有興趣的同學可以去看看。

依賴模組 swiftshims 是乙個 module.map 定義的模組,橋接的部分標頭檔案。原始檔有相關資訊和注釋。大致意思是用來實現幾個底層介面物件,比如 nsrange 鄧。

其中-module-link-name 是 swift_stdlib_core。

結論用 swift 寫模組目前並沒有很好的 ide 支援,所以不是很方便。基於猜測驗證,上面的方法可以實現在 swift 裡 import swift 模組,方法和結果看起來完全和官方模組相同。

swift 的標準庫完全是上面兩種模組的結合體,用 swift 模組封裝 clang 模組。這就解決了文章一開始提出的問題:為什麼標準庫大部分看起來是自動生成**,少部分又好像是人工寫的介面**。

DOS系統研究

這裡說的特指ms dos,一款由微軟從seattle computer products購買來的針對16位8086 8088系列處理器的作業系統。它隨著由16位的80x86處理器的桌面電腦的普及而成為曾經的主流作業系統,但是當更先進的處理器在桌面電腦中流行後,它的主流地位也讓位於其他更成熟的作業系統...

ACARS系統研究

1 概述 acars aircraftcommunication addressing reporting systems 飛機通訊定址報告系統,美國arinc公司開發,採用迴圈冗餘校驗碼 crc 進行校驗。航空器與地面站之間通過無線電或衛星傳輸短訊息 報文 的數字資料鏈系統。具有傳輸速度快 抗干擾...

Qt事件系統研究

qt中的事件基本概念 事件是對各種應用程式需要知道的由應用程式內部或者外部產生的事情或者動作的統稱。qt中使用乙個物件來表示乙個事件,這個物件繼承自qevent類。事件和訊號並非同一概念,在qt中,任何qobject子類例項都可以接受和處理事件。qt事件處理過程中發生的傳遞類似於冒泡,如果在乙個窗體...