程式碼樣式方針
在參與貢獻 Godot 原始碼時需要遵守下述樣式方針。其中的一些規則會在 CI (持續整合, Continuos Integration) 過程中自動檢查,而審閱者也會要求你修正一些潛在的問題。因此,最好先依照下屬方式設定系統,並確保你的 Commit 都有符合本方針。
C++ 與 Objective-C
雖然沒有正式文件記載,Godot 的 C++ 與 Objective-C 程式碼樣式由開發者共識透過 clang-format 自動強制執行,這個美化工具會協助你遵守所有慣例。舉例如下:
縮排與對齊均採 Tab 字元(分別為 1 個與 2 個 Tab)
數學與賦值運算子前後,以及逗號之後須有一個空格
指標與參照運算子應緊貼變數名稱,而非型別名稱
關於標頭檔引用的細節請見下文
clang-format 採用的規則詳見 Godot 原始碼庫中的 .clang-format 檔案。
只要您確保您的風格符合周圍的程式碼,並且沒有引入行尾空白字元或以空白字元為基礎的縮排,您就沒問題了。然而,如果您打算定期貢獻,我們強烈建議您在本地端設定 clang-format,以檢查並自動修正您所有的提交。
警告
Godot 的程式碼風格*不*應套用於第三方程式碼,亦即包含在 Godot 原始碼樹中但並非專為我們的專案所編寫的程式碼。此類程式碼通常來自於具有其自身風格指南 (或沒有) 的不同上游專案,且不希望引入會使與上游儲存庫同步變得更加困難的差異。
第三方程式碼通常位於 thirdparty/ 資料夾,因此能輕鬆排除於格式化腳本之外。若少數情況下需將第三方程式碼片段直接寫入 Godot 檔案,可用 /* clang-format off */ 及 /* clang-format on */ 來讓 clang-format 忽略該區段。
也參考
本規範僅涵蓋程式碼格式化。關於拉取請求允許的語言功能,請參閱 C++ 使用規範。
在本機使用 clang-format
您需要使用 clang-format 17 才能與 Godot 的格式相容。較新的版本可能適用,但較舊的版本可能不支援所有使用的選項,或以不同方式格式化某些內容,導致拉取請求中出現樣式問題。
Pre-commit 掛鉤
為方便使用,我們提供 Git 的掛鉤,搭配 pre-commit Python 框架,這會自動在您所有的提交上執行正確版本的 clang-format。設定方式如下:
pip install pre-commit
pre-commit install
你也可以手動執行 hook,指令為 pre-commit run。
備註
先前我們在 misc/hooks 資料夾中提供了 hook。如果你是手動複製腳本,這些 hook 應該仍可運作,但符號連結會失效。如果你已經改用新系統,請執行 rm .git/hooks/*,移除不再需要的舊 hook。
安裝
clang-format 的安裝方式如下:
Linux:大部分發行版的 clang 工具鏈都會直接內建。若版本不符需求,可至 LLVM 網站 下載預編譯版本,或若你使用的是 Debian 衍生版,則可參考 上游套件庫。
macOS 與 Windows:你可以從 LLVM 官方網站 下載預先編譯好的執行檔。你可能需要把執行檔所在的資料夾路徑新增到系統的
PATH環境變數,才能直接執行 clang-format。
你可以用多種方式將 clang-format 套用至你的變更:
手動使用
你可以用以下指令手動將 clang-format 套用到一個或多個檔案:
clang-format -i <path/to/file(s)>
-i代表改動應直接寫入到檔案內 (clang-format 預設只會將修正後的版本輸出到終端機上)。路徑可指向多個檔案,無論是逐一列出或用萬用字元(與一般 Unix shell 相同)。使用萬用字元時請避免誤用於 Godot 專案資料夾內的編譯物件檔(如 .o、.a)。建議用
core/*.{cpp,h}而非core/*。
IDE 外掛
大多數的 IDE 或程式碼編輯器都有美化外掛,可以設定在每次儲存檔案時自動執行 clang-format。
此處僅列出部分用於一些 IDE 的美化外掛:
Qt Creator: Beautifier plugin
Visual Studio Code: Clang-Format
Visual Studio:Clang Power Tools 2022
vim: vim-clang-format
CLion:自
2019.1版起不需額外外掛,直接啟用 ClangFormat 即可
(歡迎提出 Pull Request,協助擴充此清單以納入更多經過驗證的外掛。)
標頭檔引用
新增 C++ 或 Objective-C 檔案,或對既有檔案引用新標頭時,請遵守以下規範:
檔案開頭應放置 Godot 版權標頭與 MIT 授權條款,可從其他檔案複製,並確保檔名正確。
在
.h標頭檔內,應以FILENAME_H形式加入 include guard(防止重複引用)。在
.cpp檔案(如filename.cpp)中,第一個 include 應為該類別宣告檔(如#include "filename.h"),並於其後加一空行分隔。接著是 Godot 自身程式碼的標頭檔,須以字母順序(clang-format 會自動排序)並使用相對於根目錄的路徑引用,且以引號包覆(如
#include "core/object.h")。Godot 標頭檔引用區塊結束後應加一空行分隔。最後是第三方標頭檔(來自
thirdparty或系統 include 路徑),應以 < > 包覆(如#include <png.h>)。第三方標頭區段結束後同樣需加一空行分隔。Godot 與第三方標頭檔應於實際需要的檔案引用,若於宣告式程式碼中使用請於 .h 檔 include,僅於實作(命令式)程式碼中使用則於 .cpp include。
範例:
/**************************************************************************/
/* my_new_file.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef MY_NEW_FILE_H
#define MY_NEW_FILE_H
#include "core/hash_map.h"
#include "core/list.h"
#include "scene/gui/control.h"
#include <png.h>
...
#endif // MY_NEW_FILE_H
/**************************************************************************/
/* my_new_file.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "my_new_file.h"
#include "core/math/math_funcs.h"
#include "scene/gui/line_edit.h"
#include <zlib.h>
#include <zstd.h>
Java
Godot 的 Java 程式碼(多數位於 platform/android)也由 clang-format 強制格式化,請參考上方設定說明。請注意,本樣式指南僅適用於 Godot 開發與維護的程式碼,第三方程式碼(如 java/src/com/google 目錄)不在此限。
Python
Godot 的 SCons 建置系統以 Python 寫成,原始碼樹中也有多個 Python 腳本。
針對這些,我們使用 Ruff linter 與程式碼格式化工具。
在本機使用 ruff
首先,你需要安裝 Ruff。執行 Ruff 需要 Python 3.7 以上版本。
安裝
安裝 ruff 的方式如下:
pip3 install ruff --user
你可以用不同方式將 ruff 套用到你的變更上:
手動使用
你可以用下列指令手動將 ruff 套用到一個或多個檔案:
ruff -l 120 <path/to/file(s)>
-l 120表示每行最多允許 120 個字元。這個數字是由多位開發人員公認的。路徑可以指向多個檔案,可以直接寫出多個檔案,或是使用如一般 Unix Shell 的萬用字元。
Pre-commit 掛鉤
為了方便使用,我們提供了 Git 的 pre-commit Python 框架 hook,可以在每次提交時自動以正確版本執行 ruff。設定方式如下:
pip install pre-commit
pre-commit install
你也可以手動執行 hook,指令為 pre-commit run。
備註
先前我們在 misc/hooks 資料夾中提供了 hook。如果你是手動複製腳本,這些 hook 應該仍可運作,但符號連結會失效。如果你已經改用新系統,請執行 rm .git/hooks/*,移除不再需要的舊 hook。
編輯器整合
許多 IDE 或程式碼編輯器都有美化外掛,可以設定在每次儲存檔案時自動執行 ruff。詳細資訊請參考 Ruff Integrations。
C# 風格指南
本注釋風格指南適用於Godot程式碼庫中使用的所有程式設計語言.
以空間字元開始注釋, 以將其與禁用程式碼區分開來.
注釋使用句子大小寫. 注釋以大寫字母開頭, 並始終以句號結束.
使用反引號引用變數和函式名和值.
將注釋控制在~100個字元。
你可以在需要時使用
TODO:、FIXME:、NOTE:、WARNING:或HACK:作為提示標註。範例:
不要在註解中重複程式碼的內容,應解釋*為什麼*這麼做,而不是*怎麼做*。
錯誤範例:
你可以在函式或巨集定義上面使用Javadoc風格的注釋. 建議只對不公開給腳本的方法使用Javadoc風格的注釋. 這是因為公開的方法應該在 class reference XML 中進行記錄.
範例:
對於成員變數,請不要使用 Javadoc 風格註解,改用單行註解: