做者: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.py
。swift— Brent Royal-Gordonxcode
咱們不但願看到 太多的 GYB,而更想要 Swift 代碼,由於它更具備表達性,可是如今,咱們不得不面對它們的混和。bash
若是你只想要閱讀源碼(而不是向 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 倉庫中的 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。
當 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。