我的第一個錯誤修復¶
簡介¶
本教學將引導您完成對 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-lldb
、check-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
下)。將訊息更改為「要理解遞迴,您必須先理解遞迴」。
再次測試¶
為了驗證我們的更改,我們可以建置 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
)
這些是調用 LLVM 函數並驗證結果的 C++ 程序。它們位於 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 blame
和 git log
可用於尋找可以審閱的前任作者。
我們的 GitHub 機器人也會標記並通知 LLVM 周圍的各個「團隊」。團隊成員會定期貢獻和審查這些特定領域的程式碼,因此如果您沒有選擇任何特定人員,他們其中之一將會審查您的變更。
審閱流程¶
當您開啟拉取請求時,某些自動化功能會新增註解,並根據您變更的部分通知子專案的不同成員。
在幾天內,應該會有人開始審閱。他們可能會將自己新增為審閱者,或者只是開始留下註解。每當審閱更新時,您都會收到另一封電子郵件。如需更多詳細資訊,請參閱 程式碼審查政策。
更新您的變更¶
如果您根據審閱者的註解進行變更,只需使用更多提交更新您的分支,並將其推送到您在 GitHub 上的 llvm-project
分支。最好的做法是直接回覆審閱者的註解,而不是期望他們再次閱讀所有變更。
例如,您可以註解「我已經這樣做了。」或「我可以做到這個部分,但有一個關於……的問題。」
審閱期望¶
為了使 LLVM 成為一項長期且可持續的努力,程式碼需要具有可維護性和良好的測試。程式碼審查有助於實現該目標。特別是對於新的貢獻者而言,這通常意味著需要進行多輪審查,並且在設計決策與專案的整體架構不符時,會遭到拒絕。
對於您的第一個修補程式,這意味著
要友善,並期望審閱者也以友善的態度回應 - LLVM 有一個 行為準則,每個人都應該遵守;
要有耐心 - 了解新功能如何融入專案的架構通常是一項耗時的任務,人們必須在處理生活中其他責任的同時兼顧這一點;如果沒有回應,請每週提醒一次審閱;
如果您無法同意,通常最好的方法是按照審閱者的要求進行修改;我們以程式碼的可讀性為優先,而審閱者更能判斷這一點;如果您認為這不是正確的選擇,您可以在評論中詢問他們或新增另一位審閱者以獲得第二意見。
接受拉取請求¶
當審閱者對變更感到滿意時,他們將會**批准**拉取請求。他們可能會留下一些您在合併前應該處理的較小意見,但此時審閱已完成。是時候將其合併了!
提交權限¶
代理提交¶
由於這是您的第一次變更,您還沒有權限自行合併。**審閱者不知道這一點**,所以您需要告訴他們!在審閱中留下如下評論:
謝謝 @<審閱者的使用者名稱>。我沒有提交權限,您可以幫我合併這個拉取請求嗎?
拉取請求將會被關閉,GitHub 會通知您。
取得提交權限¶
一旦您貢獻了一些修補程式到 LLVM,就可以開始考慮自己取得提交權限。如果符合以下條件,這可能是一個好主意:
您已經提交了 3-5 個範圍大於「修復錯字」的修補程式
您願意審閱與您的變更密切相關的變更
您想繼續為 LLVM 做出貢獻。
此過程在開發者政策文件中有說明。
能力越大¶
事實上,這也是閱讀開發者政策其餘部分的好時機。
提交拉取請求後的議題¶
一旦您的變更被提交,它將會被自動建置機器人提取,這些機器人將會在各種配置中建置和測試您的修補程式。
位於http://lab.llvm.org/buildbot/#/console的「控制台」視圖顯示了特定提交的結果。如果您想追蹤您的變更如何影響建置機器人,這裡應該是您首先查看的地方。
欄是建置配置,列是單個提交。沿著這些列是彩色的氣泡。氣泡的顏色代表建置的狀態。綠色代表通過,紅色代表失敗,黃色代表建置中。
在您的變更提交之前,紅色建置可能已經失敗。這意味著您並沒有破壞建置,但您應該檢查您是否因為添加了新的問題而使情況變得更糟。
注意
控制台視圖中只會顯示最近的變更。如果您的變更不在那裡,請依靠拉取請求評論和建置機器人電子郵件來通知您任何問題。
如果包含您變更的建置出現問題,您可能會收到電子郵件或拉取請求評論形式的報告。請檢查問題是否是由於您的變更而特別引起的。因為建置包含來自許多作者的變更,並且有時會因為不相關的基礎設施問題而失敗。
要查看建置的詳細信息,請點擊控制台視圖中的氣泡,或問題報告中提供的鏈接。您將能夠查看和下載該建置每個階段的日誌。
如果您需要幫助理解問題,或有任何其他問題,您可以在您的拉取請求評論中或在Discord上提出。
如果您沒有收到任何問題報告,則無需採取任何行動。您的更改按預期工作,做得很好!
還原¶
如果您的更改導致問題,則應盡快還原。這是LLVM 開發的正常部分,每個提交者(無論經驗多麼豐富)都會經歷。
如果您不確定您的更改是否可以快速修復,請還原它。這樣您就有充足的時間進行調查並提出可靠的修復。
其他人可能會為您還原您的更改,或者您可以使用GitHub 介面建立還原拉取請求。如果可能,請將您原始的審閱者新增到這個新的拉取請求中。
結論¶
現在您應該了解對 LLVM 專案貢獻的生命週期。
如果某些細節仍不清楚,請不要擔心。LLVM 專案的流程確實與您在 GitHub 其他地方可能習慣的不同。在專案中,不同子專案的期望也可能有所不同。
因此,無論您貢獻什麼,都要知道我們並不要求完美。當您不確定時,請隨時提出問題,並且如果您遺漏了什麼,請期待有人會禮貌地指出並幫助您解決。
註解¶
審閱者可以在變更上留下註解,而您可以回覆。有些註解放置在特定的行上,並與程式碼交錯顯示。您可以回覆這些註解。也許是為了澄清所詢問的內容,或者告訴審閱者您已經完成了所要求的內容。