編譯開源 Swift Foundation 庫

SwiftGG翻譯組發表於2018-10-23

作者:iAchieved.it原文連結,原文日期:2016-06-30
譯者:rsenjoyer;校對:numbbbbb智多芯;定稿:Forelax

編譯開源 Swift Foundation 庫

我最近在開源的 Swift Foundation 中遇到了 NSThread 實現的問題。如果不是嘗試在樹莓派 3 上執行程式碼,我也許就發現不了這個問題:

import Foundation
import Glibc
 
var counter = 0
while true {
  sleep(2)
  counter = counter + 1
  let t = Thread(){
    print("STARTED:(counter)")
    sleep(1)
    print("EXIT:(counter)")
  }
  print("START:(counter)")
  t.start()
}

複製程式碼

我所期望的是每 2 秒都會建立並銷燬一個執行緒。不幸的是在大約啟動 230 個執行緒之後,系統資源已經耗盡,不再有新的執行緒被建立。解決的方式正如 SR-1908 所提到的,初始化具有系統範圍的分離狀態的執行緒

public init(_ main: (Void) -> Void) {
  _main = main
  let _ = withUnsafeMutablePointer(&_attr) { attr in
    pthread_attr_init(attr)
    pthread_attr_setscope(attr,Int32(PTHREAD_SCOPE_SYSTEM))
    pthread_attr_setdetachstate(attr,Int32(PTHREAD_CREATE_DETACHED))
  }
}

複製程式碼

Philippe Hausler 在 SR-1908 中提出瞭解決方案。正巧我有個樹莓派 3 可以實現和測試該方案。

針對 Foundation 的構建

如果你閱讀了 開源庫 Foundation新手入門文件,你就會知道,它建議在構建 Foundation 之前,首先需要構建 Swift,clang 和 llvm。如果可以在一個有大量的 CPU 和快速磁碟的伺服器上工作,我絲毫不介意按照文件一步步構建。然而樹莓派 3 與其他老式的裝置一樣,效能提升有點慢。我也可以考慮交叉編譯 Swift,但我還沒有足夠時間來解決交叉編譯帶來的問題(如果你曾經使用過交叉編譯環境,你一定知道它需要很長時間來做相關的配置)。

我們所需要的是充分利用已有的構建環境並自行編譯 Foundation。事實證明是可以做到的,不然的話,我們也不會有這篇部落格了。

下面是你所需要的準備操作(無論你是在 x86 伺服器上還是在像 BeagleBone 或樹莓派的 ARM 的計算機上):

  • 全量構建 swiftc,通常位於 build/buildbot_linux/swift-linux-armv7/bin 目錄
  • 全量構建 swift,同樣位於 build/buildbot_linux/swift-linux-armv7/bin 目錄
  • 全量構建 clang(從開源庫中構建),位於 build/buildbot_linux/llvm-linux-armv7/bin 目錄中

我希望提供各種已經編譯過的“工具鏈”,但是現在你必須首先構建自己的工具鏈。然後你就可以自己構建 Foundation 了。

現在,讓我們來看看如何使用它來測試 Foundation 上的內容。請注意,我們克隆的是我們自己 fork 的 swift-corelibs-foundation 的分支。如果你打算給上游開源庫(即 Apple 開源庫)提交 PR,這一點非常的重要。

# git clone https://github.com/iachievedit/swift-corelibs-foundation
# export PREBUILT_ROOT=/root/workspace/Swift-3.0-Pi3-ARM-Incremental/build/buildbot_linux/
# SWIFTC=$PREBUILT_ROOT/swift-linux-armv7/bin/swiftc 
CLANG=$PREBUILT_ROOT/llvm-linux-armv7/bin/clang      
SWIFT=$PREBUILT_ROOT/swift-linux-armv7/bin/swift     
SDKROOT=$PREBUILT_ROOT/swift-linux-armv7             
BUILD_DIR=build ./configure Debug
# /usr/bin/ninja
...
[290/290] Link: build/Foundation/libFoundation.so

複製程式碼

首先,我們將環境變數 PREBUILT_ROOT 設定到預構建 Swift 及相關工具所在的位置,還可以在下一步操作前配置 ./configureDebug 模式(你也可以配置為 Release)。我們還需要將環境變數 SWIFTCCLANGSWIFTSDKROOT 配置指令碼指向我們的“工具鏈”。最後,環境變數 BUILD_DIR 設定為所有中介軟體和最終輸出(libFoundation.so)的放置位置。

注意:也許有時你會驚訝於評論中的某些內容。你的 PREBUILT_ROOT 是你工具鏈的位置。不要期望在 /root/workspace/Swift-3.0-Pi3-ARM-Incremental 上找到你係統上的任何內容!

最後,執行 /usr/bin/ninja 來執行我們的構建。一旦構建結束後,在 build/Foundation/ 目錄中會有一個 libFoundation.so 共享庫。
要使用已安裝的 Swift 來測試它,只需將 libFoundation.so 複製到 $YOUR_SWIFT_ROOT/usr/lib/swift/linux/ libFoundation.so

執行測試用例

你可以通過向 ./configure 新增 -DXCTEST_BUILD_DIR 引數來執行 Foundation 測試套件。


# export PREBUILT_ROOT=/root/workspace/Swift-3.0-Pi3-ARM-Incremental/build/buildbot_linux/
# SWIFTC=$PREBUILT_ROOT/swift-linux-armv7/bin/swiftc 
CLANG=$PREBUILT_ROOT/llvm-linux-armv7/bin/clang      
SWIFT=$PREBUILT_ROOT/swift-linux-armv7/bin/swift     
SDKROOT=$PREBUILT_ROOT/swift-linux-armv7             
BUILD_DIR=build ./configure Debug                    
-DXCTEST_BUILD_DIR=$PREBUILT_ROOT/xctest-linux-armv7
# /usr/bin/ninja test
[4/4] Building Tests
**** RUNNING TESTS ****
execute:
LD_LIBRARY_PATH= build/TestFoundation/TestFoundation
**** DEBUGGING TESTS ****
execute:
LD_LIBRARY_PATH= lldb build/TestFoundation/TestFoundation

複製程式碼

執行測試需要為 LD_LIBRARY_PATH 提供兩個路徑:libXCTest.so 共享庫和“library under test”的路徑。
如果我們按照上述步驟操作,libFoundation.so 就一定位於 ./build/Foundation 目錄中。

# LD_LIBRARY_PATH=./build/Foundation:$PREBUILT_ROOT/xctest-linux-armv7 ./build/TestFoundation/TestFoundation
...
Test Suite `All tests` passed at 03:16:45.315
     Executed 483 tests, with 0 failures (0 unexpected) in 37.621 (37.621) seconds

複製程式碼

結束語

需要強調的是使用這種技術,你需要一個“構建工具鏈”,它包含 Swift,clang 和 llvm。此外,您的工具鏈最後一次構建到您嘗試自行構建 Foundation 的時間間隔越長,Foundation 所依賴的語言特性在構建工具鏈時不存在的風險就越高。但如果您決定開始使用 Foundation,請首先構建完整的 Swift 工具鏈並儲存構建目錄以使用上述技術。

祝你好運!

本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問 swift.gg

相關文章