MyFirstTypoFix

簡介

本教學將引導您完成對 LLVM 進行變更,並將其貢獻回 LLVM 專案的流程。

注意

此處展示的程式碼變更僅為範例,並非您實際上應提交給 LLVM 專案的內容。對於您對 LLVM 的第一個實際變更,程式碼將會不同,但本指南的其餘部分仍然適用。

我們將對 Clang 進行變更,但 LLVM 其他部分的步驟是相同的。即使我們將進行的變更很簡單,我們也將涵蓋諸如建置 LLVM、執行測試和程式碼審查等步驟。這是良好的實務,您將為進行更大的變更做好準備。

我們假設您

  • 知道如何使用編輯器,

  • 具備基礎 C++ 知識,

  • 知道如何在您的系統上安裝軟體,

  • 熟悉命令列,

  • 具備 git 的基礎知識。

我們要做的變更

Clang 對於無限遞迴有一個警告

$ echo "void foo() { foo(); }" > ~/test.cc
$ clang -c -Wall ~/test.cc
test.cc:1:12: warning: all paths through this function will call itself [-Winfinite-recursion]

這已經夠清楚了,但並不是很吸引人。讓我們稍微改進一下措辭

test.cc:1:12: warning: to understand recursion, you must first understand recursion [-Winfinite-recursion]

相依性

我們需要一些工具

  • git:用於簽出 LLVM 原始碼,

  • C++ 編譯器:用於編譯 LLVM 原始碼。您會需要最新版本 <host_cpp_toolchain> 的 Clang、GCC 或 Visual Studio。

  • CMake:用於設定如何在您的系統上建置 LLVM,

  • ninja:執行 C++ 編譯器以(重新)建置 LLVM 的特定部分,

  • python:用於執行 LLVM 測試。

以 Ubuntu 為例

$ sudo apt-get install git clang cmake ninja-build python

建置 LLVM

簽出

原始碼儲存在 Github 上 的一個大型儲存庫(「單一儲存庫」)中。

下載可能需要一段時間!

$ git clone https://github.com/llvm/llvm-project.git

這將建立一個名為「llvm-project」的目錄,其中包含所有原始碼。(匿名簽出是可以的 - 推送提交使用不同的機制,我們稍後會看到。)

設定您的工作區

在我們可以建置程式碼之前,我們必須透過執行 CMake 來設定確切的建置方式。CMake 結合來自三個來源的資訊

  • 您做出的明確選擇(這是偵錯建置嗎?)

  • 從您的系統偵測到的設定(程式庫安裝在哪裡?)

  • 專案結構(哪些檔案是「clang」的一部分?)

首先,建立一個用於建置的目錄。通常,這是 llvm-project/build

$ mkdir llvm-project/build
$ cd llvm-project/build

現在,執行 CMake

$ cmake -G Ninja ../llvm -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS=clang

如果一切順利,您會看到很多「執行測試」的行,最後

Configuring done
Generating done
Build files have been written to: /path/llvm-project/build

您應該在目前目錄中看到一個 build.ninja 檔案。

讓我們稍微分解一下最後一個命令

  • -G Ninja:告訴 CMake 我們將使用 ninja 進行建置,並建立 build.ninja 檔案。

  • ../llvm:這是「主要」LLVM 專案原始碼的路徑

  • 兩個 -D 旗標設定 CMake 變數,這會覆寫 CMake/專案預設值

    • CMAKE_BUILD_TYPE=Release:以最佳化模式建置,這是(令人驚訝地)最快的選項。

      如果您想在偵錯工具下執行,您應該使用預設的 Debug(完全未最佳化,並且會導致 >10 倍的測試執行速度變慢)或 RelWithDebInfo,這是一個折衷方案。

      預設情況下,Release 建置中未啟用斷言。您可以使用 LLVM_ENABLE_ASSERTIONS=ON 來啟用它們。

    • LLVM_ENABLE_PROJECTS=clang:這列出了您有興趣建置的 LLVM 子專案,以及 LLVM 本身。可以列出多個專案,以分號分隔,例如 clang;lldb。在本範例中,我們將對 Clang 進行變更,因此我們僅新增 clang。

最後,建立 llvm-project/build/compile-commands.json 的符號連結(或複製)到 llvm-project/

$ ln -s build/compile_commands.json ../

(這對於建置和測試不是絕對必要的,但允許諸如 clang-tidy、clang-query 和 clangd 之類的工具在您的原始碼樹中工作)。

建置和測試

最後,我們可以建置程式碼了!首先執行此操作很重要,以確保我們在進行變更之前處於良好狀態。但是要建置什麼?在 ninja 中,您指定一個目標。如果我們只想建置 clang 二進位檔,我們的目標名稱是「clang」,我們執行

$ ninja clang

我們第一次建置會非常慢 - Clang + LLVM 是很多程式碼。但是增量建置很快:ninja 只會重新建置已變更的部分。當它最終完成時,您應該有一個可運作的 clang 二進位檔。嘗試執行

$ bin/clang --version

還有一個用於建置和執行所有 clang 測試的目標

$ ninja check-clang

這是 LLVM 中的常見模式:check-llvm 是所有針對 LLVM 核心的檢查,其他專案具有類似 check-lldbcheck-flang 等的目標。

進行變更

變更

我們需要找到包含錯誤訊息的檔案。

$ git grep "all paths through this function" ..
../clang/include/clang/Basic/DiagnosticSemaKinds.td:  "all paths through this function will call itself">,

出現在 DiagnosticSemaKinds.td 中的字串是 Clang 列印的字串。*.td 檔案定義表格 - 在這種情況下,它是 clang 可以發出的警告和錯誤及其訊息的列表。讓我們在您最喜歡的編輯器中更新訊息

$ vi ../clang/include/clang/Basic/DiagnosticSemaKinds.td

找到訊息(它應該在 warn_infinite_recursive_function 下)。將訊息變更為「in order to understand recursion, you must first understand recursion」。

再次測試

為了驗證我們的變更,我們可以建置 clang 並手動檢查它是否運作。

$ ninja clang
$ bin/clang -c -Wall ~/test.cc
test.cc:1:12: warning: in order to understand recursion, you must first understand recursion [-Winfinite-recursion]

我們也應該執行測試以確保我們沒有破壞任何東西。

$ ninja check-clang

請注意,這次建置速度快得多,但測試執行時間卻一樣長。Ninja 不知道哪些測試可能會受到影響,因此它會執行所有測試。

********************
Failing Tests (1):
    Clang :: SemaCXX/warn-infinite-recursion.cpp

嗯,這很有道理…而且測試輸出表明它正在尋找舊字串「call itself」,但找到了我們的新訊息。請注意,隨著時間的推移新增更多測試,可能會以類似的方式導致更多測試失敗。

讓我們透過更新測試中的預期結果來修正它。

$ vi ../clang/test/SemaCXX/warn-infinite-recursion.cpp

在我們看到 // expected-warning{{call itself}} 的任何地方(或來自原始警告文字的類似內容),讓我們將其替換為 // expected-warning{{to understand recursion}}

現在我們可以再次執行所有測試,但這是一個緩慢地迭代變更的方式!相反,讓我們找到一種方法來重新執行特定的測試。LLVM 中有兩種主要類型的測試

  • lit 測試(例如 SemaCXX/warn-infinite-recursion.cpp)。

這些是複雜的 shell 腳本,它們執行命令列工具並驗證輸出。它們位於諸如 clang/**test**/FixIt/dereference-addressof.c 之類的檔案中。像這樣重新執行

$ bin/llvm-lit -v ../clang/test/SemaCXX/warn-infinite-recursion.cpp
  • 單元測試(例如 ToolingTests/ReplacementTest.CanDeleteAllText

這些是 C++ 程式,它們呼叫 LLVM 函式並驗證結果。它們位於諸如 ToolingTests 之類的套件中。像這樣重新執行

$ ninja ToolingTests && tools/clang/unittests/Tooling/ToolingTests --gtest_filter=ReplacementTest.CanDeleteAllText

在本機提交

我們將變更儲存到本機 git 分支。這讓我們可以在審查變更時處理其他事情。變更應具有標題和描述,以向審查者和程式碼的未來讀者解釋進行變更的原因。

目前,我們只新增標題。

$ git checkout -b myfirstpatch
$ git commit -am "[clang][Diagnostic] Clarify -Winfinite-recursion message"

現在我們準備好將此變更發送到世界各地!

[clang][Diagnostic] 前綴是我們所謂的標籤。這種寬鬆的慣例告訴 git 記錄的讀者,變更正在修改哪些區域。如果您不知道您已變更的模組的標籤,您可以查看儲存庫這些區域的提交歷史記錄。

$ git log --oneline ../clang/

或使用 GitHub,例如 https://github.com/llvm/llvm-project/commits/main/clang

標籤是不精確的,因此如果您不確定要放什麼,請不要擔心。如果審查者認為需要標籤,他們會建議一些。

程式碼審查

上傳變更以供審查

LLVM 程式碼審查透過 GitHub 上的提取請求進行,請參閱 GitHub 文件,以了解如何在 GitHub 上開啟提取請求。

尋找審查者

LLVM 社群中的任何人都可以審查變更。對於較大和較複雜的變更,重要的是審查者具有 LLVM 領域的經驗,並且非常了解設計目標。變更的作者通常會指派特定的審查者。git blamegit log 可用於尋找可以審查的先前作者。

我們的 GitHub 機器人也會標記和通知 LLVM 周圍的各種「團隊」。團隊成員定期為這些特定領域貢獻和審查程式碼,因此如果您沒有選擇任何特定的人,他們中的一人會審查您的變更。

審查流程

當您開啟提取請求時,某些自動化功能會新增註解,並根據您已變更的部分通知子專案的不同成員。

在幾天之內,應該有人開始審查。他們可能會將自己新增為審查者,或只是開始留下評論。每次審查更新時,您都會收到另一封電子郵件。有關更多詳細資訊,請參閱 程式碼審查政策

評論

審查者可以對變更留下評論,您可以回覆。有些評論附加到特定行,並與程式碼交錯顯示。您可以回覆這些評論。也許是為了澄清所要求的內容,或告訴審查者您已完成所要求的內容。

更新您的變更

如果您根據審查者的評論進行變更,只需使用更多提交更新您的分支,然後推送到您的 llvm-project GitHub 分支。最好直接回覆審查者的評論,而不是期望他們再次閱讀所有變更。

例如,您可能會評論「我已完成此操作」或「我能夠完成此部分,但對…有疑問」。

審查期望

為了使 LLVM 成為一項長期可持續的努力,程式碼需要可維護且經過良好測試。程式碼審查有助於實現該目標。尤其是對於新的貢獻者而言,這通常意味著多輪審查和對不符合專案整體架構的設計決策的反駁。

對於您的第一個修補程式,這意味著

  • 友善,並期望審查者友善地回報 - LLVM 有一個 行為準則,每個人都應該遵守;

  • 要有耐心 - 了解新功能如何融入專案的架構通常需要耗費時間,而且人們必須將其與生活中的其他責任兼顧;每週 ping 一次審查,如果沒有回應;

  • 如果您無法達成共識,通常最好的方法是按照審查者的要求去做;我們針對程式碼的可讀性進行最佳化,審查者更適合判斷;如果感覺這不是正確的選項,您可以透過評論詢問他們或新增另一位審查者以獲得第二意見。

接受提取請求

當審查者對變更感到滿意時,他們將核准提取請求。他們可能會留下一些更小的評論,您應該在合併之前處理這些評論,但此時審查已完成。是時候將其合併了!

提交權限

透過代理提交

由於這是您的第一個變更,因此您還沒有權限自行合併它。審查者不知道這一點,因此您需要告訴他們!在審查中留下評論,例如

感謝 @<審查者的使用者名稱>。我沒有提交權限,您可以為我合併此 PR 嗎?

提取請求將被關閉,您將收到 GitHub 的通知。

取得提交權限

一旦您為 LLVM 貢獻了一些修補程式,就可以開始考慮自行取得提交權限。如果符合以下條件,這可能是一個好主意

  • 您已提交 3-5 個範圍比「修正錯字」更大的修補程式

  • 您願意審查與您的變更密切相關的變更

  • 您希望繼續為 LLVM 做出貢獻。

該流程在 開發人員政策文件 中有所描述。

能力越大

實際上,現在是閱讀 開發人員政策 其餘部分的好時機。

PR 提交後的問題

一旦您的變更被提交,它將被自動建置機器人拾取,這些機器人將在各種組態中建置和測試您的修補程式。

http://lab.llvm.org/buildbot/#/console 上的「主控台」檢視顯示特定提交的結果。如果您想追蹤您的變更如何影響建置機器人,這應該是第一個要查看的地方。

欄是建置組態,列是個別提交。沿著列是彩色氣泡。氣泡的顏色代表建置的狀態。綠色表示通過,紅色表示失敗,黃色表示正在建置中。

紅色建置可能在您的變更提交之前就已經失敗。這表示您沒有破壞建置,但您應該檢查您是否沒有透過新增新問題使其變得更糟。

注意

主控台檢視中僅顯示最近的變更。如果您的變更不在那裡,請依靠 PR 評論和建置機器人電子郵件來通知您任何問題。

如果包含您的變更的建置中存在問題,您可能會透過電子郵件或作為 PR 上的評論收到報告。請檢查問題是否是專門由您的變更引起的。由於建置包含來自許多作者的變更,並且有時會因不相關的基礎架構問題而失敗。

要查看建置的詳細資訊,請按一下主控台檢視中的氣泡,或問題報告中提供的連結。您將能夠查看和下載該建置每個階段的記錄。

如果您需要幫助理解問題,或有任何其他問題,您可以在您的 PR 上或在 Discord 上以評論的形式提出。

如果您沒有收到任何問題報告,則無需您採取任何行動。您的變更按預期運作,做得好!

還原

如果您的變更導致了問題,應盡快還原。這是 LLVM 開發 的正常部分,每個提交者(無論經驗多麼豐富)都會經歷。

如果您對您的變更是否可以快速修復有任何疑問,請還原它。然後您有充足的時間來調查並產生可靠的修復。

其他人可能會為您還原您的變更,或者您可以使用 GitHub 介面 建立還原提取請求。如果可能,請將您的原始審查者新增到這個新的提取請求中。

結論

現在您應該了解對 LLVM 專案的貢獻生命週期。

如果某些細節仍然不清楚,請不要擔心。LLVM 專案的流程確實與您在 GitHub 上其他地方可能習慣的流程有所不同。在專案內部,不同子專案的期望也可能有所不同。

因此,無論您貢獻什麼,要知道我們並不期望完美。如果您不確定,請隨時提出問題,並期望如果您遺漏了某些內容,有人會禮貌地指出並幫助您解決。