如何閱讀 Swift 標準庫中的源碼

做者:Ole Begemann,原文連接,原文日期:2016-10-28
譯者:X140Yu;校對:walkingway;定稿:CMBhtml

在進行完 GYP 預處理後,閱讀 Swift 標準庫源碼的最簡單的一種方式是執行一次完整的 Swift 編譯。(另外一種是寫一小段 shell 腳本。能夠看下面的更新)git

若是你想要開始閱讀 Swift 源碼,那它的標準庫應該是首先開始閱讀的地方。標準庫中的代碼是和每個使用 Swift 的開發者都息息相關的,若是你也曾經對某個 API 的表現和性能有過懷疑,那麼直接閱讀對應的源碼會是解決問題最快的方式。github

標準庫也是 Swift 項目中最容易接觸的地方。其中一點理由是,它由 Swift 寫的,而不是 C++。由於你天天都用它,因此對它的 API 也很是熟悉。這就意味着,在源碼中找到你想要的那段代碼不是特別困難。若是你只是沒有目標隨便看看,那麼在源碼中你可能會發現或者這塊金子。shell

在哪裏能找到標準庫的源碼?

標準庫的代碼在 stdlib/public/core,GitHub 上的 Swift 倉庫中。你能夠在裏面找到全部 public types,protocols 和 functions。你能夠在線或者把代碼 clone 到本地閱讀。可是,一個比較複雜的地方在於,大約 1/3 的文件都是 .swift.gyb 的後綴,若是你打開其中一個文件,例如:FixedPoint.swift.gyb(Int 類型被定義的地方),你會發現一種和 Swift 混合在一塊兒的模版語言:GYB。macos

gyb 表明 Generate Your Boilerplate(生成你的樣板文件)。 它是由 Swift 團隊開發的預處理的一個玩意。若是須要編譯十個很是類似的 Int,那就得把相同的代碼複製粘貼十次。若是你打開某個 gyb 文件,你會發現其中大部分都是 Swift 的代碼,可是也有一些是 Python 代碼。這個預處理器在 Swift 的代碼倉庫中的 utils/gyb,雖然大部分的代碼在 utils/gyb.pyswift

Brent Royal-Gordonxcode

咱們不但願看到 太多的 GYB,而更想要 Swift 代碼,由於它更具備表達性,可是如今,咱們不得不面對它們的混和。bash

處理 GYB

若是你只想要閱讀源碼(而不是向 Swift 貢獻代碼),GYB 則弊大於利。那麼怎麼來預處理這些文件呢?你能夠直接運行 gyb 腳本,可是它依賴於一個被 build 腳本建立的特殊環境。最好的方式是執行一次完整的 Swift build。也許對於閱讀源碼來講,build 一次可能會有點過了,可是我發現 build 之後,源碼閱讀起來會更容易一些。app

更新: Toni Suter 指出 gyb 的腳本只依賴於一個你能夠更改的變量(64-bit 和 32-bit 差異),若是你只想要處理 gyb, 這個小腳本比完整編譯一次 Swift 要好不少。函數

bash
#!/bin/bash
for f in `ls *.gyb`
do
    echo "Processing $f"
    name=${f%.gyb}
    ../../../utils/gyb -D CMAKE_SIZEOF_VOID_P=8 -o $name $f --line-directive ""
done

它會把全部的 .gyb 文件處理完畢後放到相同的位置並去掉 .gyb 後綴。去除 --line-directive "" 在處理完畢的文件中添加 source location 的註釋(就像 Swift build 中處理的同樣)。

從源碼編譯 Swift

環境的搭建能夠閱讀 Swift 倉庫中的 readme。 若是在 Mac 機器上,按照下面的步驟進行操做(使用 Homebrew 安裝各類依賴),可是別忘記檢查這些步驟的正確性:

bash
# Install build tools
brew install cmake ninja
# Create base directory
mkdir swift-source
cd swift-source
# Clone Swift
git clone https://github.com/apple/swift.git
# Clone dependencies (LLVM, Clang, etc.)
./swift/utils/update-checkout --clone

最後一句命令會把 build Swift 須要的其它部分的 repo 給 clone 下來,好比 LLVM,Clang,LLDB 等等。就像對於 Linux 的 Foundation 和 libdispatch 模塊同樣。在這一步事後,你的 swift-source 文件夾看起來是這樣:

bash
du -h -d 1
250M    ./clang
4,7M    ./cmark
 47M    ./compiler-rt
 15M    ./llbuild
197M    ./lldb
523M    ./llvm
221M    ./swift
 26M    ./swift-corelibs-foundation
7,8M    ./swift-corelibs-libdispatch
1,1M    ./swift-corelibs-xctest
316K    ./swift-integration-tests
960K    ./swift-xcode-playground-support
7,0M    ./swiftpm
1,3G    .

如今就能夠開始運行 build 腳本了,它會先開始 build LLVM,而後構建 Swift:

bash
./swift/utils/build-script -x -R

參數是很重要的:

  • -x 會生成一個 Xcode project,你就能夠在這個 project 中使用 Xcode 閱讀源碼了。

  • -R 表明 release 模式的編譯。它會比 debug 模式更快,在我 2.6 GHz 的 core i7 2013 電腦上,25 分 vs 70 分。佔用的空間也更少,2GB vs 24GB。

Orienting yourself

當 build 構建完成後,你能夠在 ./build/Xcode-ReleaseAssert/swift-macosx-x86_64/ 的子文件夾中 swift-source 找到結果。其中會有一個 Swift.xcodeproj Xcode 項目,已經處理好的標準庫代碼在 ./stdlib/public/code/8/ 中。注意,這個文件夾中只有從 .gyb 文件處理過來的文件,以前以 .swift 結尾的文件還在原來的位置。

不幸的是, 在 Xcode 中使用 Open Quickly (⇧⌘O) 打不開特定的 API. 我一般使用 Find in Project (⇧⌘F) 來進行導航。若是你使用只出如今函數定義時的字符串來搜索,那就很容易搜索到了。好比要搜索 print 函數的定義,搜索 「func print(「 而不是 「print」。

你也能夠運行 swift REPL 或者 swiftc 編譯器了。它們都在 ./Release/bin/ 中。若是還想測試一些以前在 release 中出現,可是在 master 中已經被修復的 bug,就會很方便。

更新

若是你想在之後更新本地的 clone,從新運行 update-checkout 腳本,而且 rebuild:

bash
./swift/utils/update-checkout
./swift/utils/build-script -x -R

這些都是增量編譯,比第一次要快得多。

切換到指定的版本

若是你想要驗證一個在生產環境中已經使用的 Swift 特定版本 API 的表現,你就須要查看那個版本的 Swift 代碼,而不是當前 master 分支。可是簡單地切換分支並不能解決問題,由於若是一些依賴的版本對不上的話,編譯是會失敗的。

update-checkout 腳本可以讓你指定一個特定的 tag 或者 branch。它會幫你切換全部依賴的版本:

bash
# Either
./swift/utils/update-checkout --tag swift-3.0-RELEASE
# or
./swift/utils/update-checkout --scheme swift-3.0-branch

swift-3.0-RELEASE tag 和 swift-3.0-branch branch 的區別是,tag 至關於一個 mailstone,表明 Swift 的某個特定的 release 分支。然而分支是會伴隨着 bug 修復和功能改進不斷更新的。如今來看,在官方 release Xcode 8.1 的 Swift 3.0.1 時,swift-3.0-branch 分支已經包含了一些 Swift 3.0.2 中的修復。

不幸的是,我發現 update-checkout --scheme 的命令很是脆弱(--tag 在我看來能好一些)。這個腳本會對代碼進行 rebase 操做,而且切換到指定的分支,這會在子項目中帶來合併衝突,然而我並無對代碼做出任何更改。我不明白爲何這個腳本會這樣。

本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg

相關文章
相關標籤/搜索