Meson 貢獻指南

Meson 的大部分程式碼是由核心團隊以外的人員貢獻的。本文檔說明 Meson 的一些設計原理,以及如何建立和提交您的修補程式以包含在 Meson 中。

感謝您有興趣參與開發。

提交修補程式

所有變更都必須以 GitHub 的 Pull Request 形式提交。這會使它們通過 CI 系統執行。所有提交都必須通過完整的 CI 測試執行,然後才會考慮提交。

保持 Pull Request 為最新狀態

在您的 Pull Request 正在審閱時,可能會將其他變更提交到 master,導致必須解決合併衝突。這的基本規則非常簡單:**僅**使用 rebase 保持您的 Pull Request 為最新狀態。

不要將 head 合併回您的分支。您的 Pull Request 中的任何合併 commit 都會使其無法接受合併到 master 中,您必須將它們移除。

新功能的特殊程序

每個新功能都需要一些額外步驟,即

  • 必須在 test cases/ 下包含專案測試,或者如果無法進行測試,或測試需要特殊環境,則必須將其放入 run_unittests.py
  • 必須向 FeatureChecks 框架 註冊,如果使用者在以較舊的 Meson 版本為目標時嘗試使用新功能,該框架將會警告使用者。
  • 需要在 docs/markdown/snippets/ 內有一個發行說明片段,其中包含標題和一個簡短的段落,解釋該功能的作用並附帶範例。

接受和合併

任何合併提案所獲得的審閱和接受類型取決於其中包含的變更。所有 Pull Request 都必須由具有 commit 權限且非原始提交者的人員審閱和接受。合併請求可以大致分為三個不同的類別。

第一個類別包含僅變更 docs/markdown 下的 markdown 文件之 MR。任何具有存取權限的人員都可以將這些變更直接推送至 master。對於重大變更,仍然建議建立 MR,以便其他人可以發表評論。

第二組包含不變更任何功能、對 CI 系統的修正,以及已新增回歸測試(請參閱下文)且不變更現有功能之錯誤修正的合併。一旦成功審閱,任何具有合併權限的人員都可以將這些合併至 master。

最後一種合併是新增新功能或以不向下相容的方式變更現有功能的合併。這些需要專案負責人的批准。

以簡化的列表形式,分割如下所示

  • 具有 commit 權限的成員可以執行
    • 文件變更(在必要時直接變更至 master)
    • 不變更功能的錯誤修正
    • 重構
    • 新的相依性類型
    • 新的工具支援(例如,新的 Doxygen 類型的工具)
    • 支援現有語言的新編譯器
  • 需要專案負責人決定的事項
    • 新模組
    • Meson 語言中的新函式
    • Meson 檔案的語法變更
    • 變更會破壞向下相容性
    • 支援新的語言

綠色 CI 執行是合併的必要條件

在完全綠色的 CI 執行之前,不得合併任何合併請求。CI 失敗的原因並不重要,這是一個硬性阻礙。即使 MR 可能與失敗無關,而且顯然應該允許,也不得合併。只有修正 CI 問題的 MR 才允許進入主幹。

只有一個例外。在撰寫本文時,Apple CI 不可靠,有時會因時鐘偏差錯誤而失敗。

如果合併導致 CI 失敗,任何開發人員都可以將其從 master 中還原。然後,原始提交者有責任重新提交修正的版本。

將 Pull Request 合併到主幹的策略

Meson 的合併策略應符合以下準則

  • 盡可能保留多的歷史記錄

  • 存放庫中應盡可能少包含垃圾

  • 「master 傳承」中的所有內容都應始終通過所有測試

這些目標略有矛盾,因此正確的做法通常需要合併人員進行一些判斷。GitHub 提供三個不同的合併選項,選擇它們的經驗法則是這樣的

  • 單一 commit Pull Request 應始終進行 rebase

  • 具有一個 commit 和一個「修復」commit(例如,測試某個內容以查看它是否通過 CI)的 Pull Request 應進行 squash

  • 具有許多 commit 的大型分支應使用合併 commit 進行合併,尤其是在其中一個 commit 未通過所有測試的情況下(例如,在大型且困難的重構中會發生這種情況)

如果有疑問,請在 IRC 上尋求指導。

測試

所有新功能都必須附帶自動測試,以充分證明該功能是否如預期般運作。同樣,錯誤修復必須附帶一個單元測試,以示範該錯誤、證明它已修正,並防止該功能在未來中斷。

有時很難為給定的錯誤建立單元測試。如果發生這種情況,請在您的 Pull Request 中註明。在這些情況下,我們可能會允許錯誤修正合併請求。這是在個案的基礎上完成的。有時,撰寫測試可能比說服維護人員不需要測試更容易。在有問題的情況下,請運用判斷力並尋求幫助。

測試分為兩個不同的部分:單元測試和完整專案測試。若要執行所有測試,請執行 ./run_tests.py。可以使用 ./run_unittests.py 執行單元測試,使用 ./run_project_tests.py 執行專案測試。

專案測試

可以使用 ./run_project_tests.py --only 選項選取專案測試的子集。當僅測試 Meson 的特定部分時,這可以節省大量時間。例如,對 Meson 的一個有用且簡單的貢獻是確保支援全套編譯器。例如,可以通過使用 ./run_project_test.py --only fortran 設定 FC=ifortFC=flangFC=flang-new 或類似的設定來測試各種 Fortran 編譯器。某些測試系列需要特定的後端才能執行。例如,所有 CUDA 專案測試都通過 ./run_project_tests.py --only cuda --backend ninja 在 Windows 上執行並通過。

每個專案測試都是一個可以自行編譯的獨立專案。它們都在 test cases 子目錄中。執行單一專案測試的最簡單方法是執行類似 ./meson.py test\ cases/common/1\ trivial builddir 的命令。唯一的例外是下面討論的 test cases/unit 目錄。

common 子目錄中的測試案例旨在始終針對所有後端執行。它們應僅依賴 C 和 C++,而沒有任何外部相依性,例如程式庫。需要這些的測試位於 test cases/frameworks 目錄中。如果 common 目錄中需要外部程式(例如程式碼產生器),則應將其實作為 Python 指令碼。測試專案的目標也是提供範例專案,讓終端使用者可以使用這些專案作為自己專案的基礎。

所有專案測試都遵循相同的模式:它們已設定、編譯、執行測試,最後執行安裝。通過表示設定、建置和測試成功,並且已安裝的檔案與預期的檔案相符。

任何需要更徹底分析的測試(例如檢查是否可以在命令列中找到某些編譯器引數,或產生 pkg-config 檔案是否實際運作)都應使用單元測試來完成。

此外

  • crossfile.ininativefile.ini 分別通過 --cross-file--native-file 選項傳遞至設定步驟。

  • 可以從 Meson 內的任何位置呼叫 mlog.cmd_ci_include(),以在失敗時將其他檔案的內容擷取到 CI 記錄中。

單元測試所需的專案位於 test cases/unit 子目錄中。它們不會作為 ./run_project_tests.py 的一部分執行。

設定專案測試

測試案例根目錄中的(可選)test.json 檔案用於設定測試。test.json 中的所有下列根項目都是獨立的,並且可以根據需要進行組合。

test.json 範例

{
  "env": {
    "VAR": "VAL"
  },
  "installed": [
    { "type": "exe", "file": "usr/bin/testexe" },
    { "type": "pdb", "file": "usr/bin/testexe" },
    { "type": "shared_lib", "file": "usr/lib/z", "version": "1.2.3" },
  ],
  "matrix": {
    "options": {
      "opt1": [
        { "val": "abc"   },
        { "val": "qwert" },
        { "val": "bad"   }
      ],
      "opt2": [
        { "val": null    },
        { "val": "true"  },
        { "val": "false" },
      ]
    },
    "exclude": [
      { "opt1": "qwert", "opt2": "false" },
      { "opt1": "bad"                    }
    ]
  },
  "tools": {
    "cmake": ">=3.11"
  }
}

env

env 金鑰包含一個字典,其中指定要在測試的設定步驟期間設定的其他環境變數。

有些基本支援可以使用 @<VAR>@ 語法來設定字串

  • @ROOT@:來源目錄的絕對路徑
  • @PATH@PATH 環境變數的目前值

installed

installed 字典包含字典清單,說明預期要安裝的檔案。每個字典都包含以下金鑰

  • file
  • type
  • platform(可選)
  • version(可選)
  • language(可選)

file 項目包含實際安裝檔案的相對路徑(相對於安裝根目錄)。

type 項目指定應如何根據目前平台解譯 file 路徑。目前支援下列值

type 說明
file 無後處理,僅使用提供的路徑
python_file 使用提供的路徑,同時取代 python 目錄。
dir 要包含目錄中的所有檔案(用於產生的文件等)。路徑必須是有效的目錄
exe 用於可執行檔。在 Windows 上,.exe 字尾會新增至 file 中的路徑
shared_lib 對於共用程式庫,一律寫為 name。由平台新增適當的字尾和字首
python_lib 對於 python 程式庫,同時取代 python 目錄。由平台新增適當的字尾
pdb 用於 Windows PDB 檔案。PDB 項目在非 Windows 平台上會遭到忽略
implib 用於 Windows 匯入程式庫。這些項目在非 Windows 平台上會遭到忽略
py_implib 用於 Windows 匯入程式庫。這些項目在非 Windows 平台上會遭到忽略
implibempty implib 類似,但在程式庫中未匯出任何符號
expr file 是一個運算式。應該避免使用此類型,並在可能的情況下移除

除了 filepython_fileexpr 類型之外,所有路徑都應在 沒有 字尾的情況下提供。

引數 適用於 說明
version shared_libpdb 設定每個平台要適當尋找的版本
language pdb 決定哪個編譯器/連結器決定此檔案是否存在

shared_libpdb 類型採用可選的額外參數 version,這是 X.Y.Z 格式的字串,將應用於程式庫。每個要測試的版本都必須具有單一版本。安全帶會依據平台正確地應用此設定

python_filepython_libpy_implib 類型基本支援使用 @<VAR>@ 語法來設定字串

  • @PYTHON_PLATLIB@:相對於字首的 python get_install_dir 目錄
  • @PYTHON_PURELIB@:相對於字首的 python get_install_dir(pure: true) 目錄

pdb 接受一個可選的 language 參數。這會決定應該由哪個編譯器/連結器產生 pdb 檔案。因為有可能混用會產生 pdb 檔案和不會產生 pdb 檔案的編譯器(例如 dmd 的 optlink 就不會)。目前只有在混用 D 語言和 C 語言程式碼時才需要這個參數。

{
  "type": "shared_lib", "file": "usr/lib/lib",
  "type": "shared_lib", "file": "usr/lib/lib", "version": "1",
  "type": "shared_lib", "file": "usr/lib/lib", "version": "1.2.3.",
}

這會根據不同平台做適當的應用。在 Windows 上,它預期會有 lib.dlllib-1.dll。在 macOS 上,它預期會有 liblib.dylibliblib.1.dylib。在其他 Unix 系統上,它預期會有 liblib.soliblib.so.1liblib.so.1.2.3

如果存在 platform 鍵,只有當平台相符時,才會考慮已安裝的檔案項目。目前支援的 platform 值如下:

platform 說明
msvc 當使用類似 msvc 的編譯器時(msvcclang-cl 等)匹配。
gcc msvc
cygwin 當平台是 cygwin 時匹配。
!cygwin cygwin

matrix

可以使用 matrix 區段定義一個測試矩陣,以使用不同的 Meson 選項執行專案測試。

options 字典中,會指定所有可能的選項及其值。options 字典中的每個鍵都是一個 Meson 選項。它會以字典格式儲存所有潛在值的列表。

每個值都必須包含選項值的 val 鍵。null 可以用來加入沒有目前選項的矩陣項目。

可以在值中使用 skip_on_env 鍵(如下所述),以根據目前環境跳過該矩陣項目。

可以使用 expect_skip_on_jobnameexpect_skip_on_os 鍵(如下所述),以根據目前環境預期測試將被跳過。

同樣地,可以使用 compilers 鍵來定義編譯器到此值所需的語言的映射。

{
  "compilers": {
    "c": "gcc",
    "cpp": "gcc",
    "d": "gdc"
  }
}

可以使用 exclude 區段排除特定的選項組合。應該注意的是,exclude 不需要完全匹配。而是,任何包含 exclude 中所有選項值組合的矩陣項目都會被排除。因此,一個空的字典 ({}) 將匹配測試矩陣中的**所有**元素。

上面的範例會產生以下矩陣項目:

  • opt1=abc
  • opt1=abc opt2=true
  • opt1=abc opt2=false
  • opt1=qwert
  • opt1=qwert opt2=true

do_not_set_opts

目前支援的值為:

  • prefix
  • libdir

tools

此區段以簡單的鍵值格式指定工具需求的字典。如果指定了某個工具,它必須存在於環境中,並且必須滿足版本需求。否則,整個測試會被跳過(包括測試矩陣中的每個元素)。

stdout

stdout 鍵包含描述預期 stdout 的字典列表。

每個字典都包含以下鍵:

  • line
  • match(選用)
  • count(選用)

列表中的每個項目都會依序與任何先前匹配之後剩餘的實際 stdout 行進行匹配。如果實際 stdout 在列表中的每個項目都匹配完之前就已耗盡,則表示未看到預期的輸出,且測試失敗。

字典的 match 元素會決定如何匹配 line 元素。

類型 說明
literal 文字匹配(預設)
re 正規表示式匹配

count 元素決定該行預期且允許在輸出中出現的次數。如果未指定,則它必須「出現任意次數,但至少一次」。

skip_on_env

skip_on_env 鍵可用於指定環境變數的列表。如果 skip_on_env 列表中至少有一個環境變數存在,則會跳過測試。

expect_skip_on_jobname

expect_skip_on_jobname 鍵包含字串列表。如果設定了 MESON_CI_JOBNAME 環境變數,並且它們中的任何一個是它的子字串,則預期測試會被跳過(也就是說,預期測試會輸出 MESON_SKIP_TEST,因為 CI 環境並不是它可以運行的環境,無論出於何種原因)。

如果測試意外跳過或意外運行,則測試會失敗。

expect_skip_on_os

expect_skip_on_os 鍵可用於指定 OS 名稱列表(或其否定,以 ! 開頭)。如果 expect_skip_on_os 列表中至少有一個項目匹配,則預期測試會被跳過。

如果測試意外跳過或意外運行,則測試會失敗。

跳過整合測試

Meson 使用多個持續整合測試系統,這些系統對於表示應跳過的 commit 有略微不同的介面。

目前使用的持續整合系統

為了推廣一致的命名策略,如果您想要停用所有整合測試,請在 commit 標題中使用:

  • [skip ci]

文件

docs 目錄包含將用於產生 Meson 網站的完整文件。在大多數情況下,行長度不應超過 70 個字元(包含連結或範例的行通常可以豁免)。功能的每次變更都必須變更文件頁面。在大多數情況下,這表示更新參考文件頁面,但更大的變更可能也需要變更其他文件。

所有新功能都需要在版本說明中提及。這些功能應以獨立檔案的形式寫在 docs/markdown/snippets 目錄中。發布管理員在發布時會將它們合併到一個頁面中。

Python 編碼風格

Meson 遵循基本的 Python 編碼風格。其他規則如下:

  • 縮排 4 個空格,永遠不要使用 tab
  • 使用兩個空格縮排 meson.build 檔案
  • 盡可能保持程式碼簡單
  • 在開始大型專案之前,請聯繫郵件列表,以避免浪費精力

Meson 使用 Flake8 來強制執行樣式指南。專案的 Flake8 選項包含在 .flake8 中。

在 Meson 的本機複製上執行 Flake8:

$ python3 -m pip install flake8
$ cd meson
$ flake8

在提交之前自動運行它:

$ flake8 --install-hook=git
$ git config --bool flake8.strict true

C/C++ 編碼風格

Meson 有許多以多種語言編寫的測試程式碼。這些程式碼的規則很簡單。

  • 縮排 4 個空格,永遠不要使用 tab
  • 大括號始終與 if/for/else/函數定義在同一行

外部依賴項

Meson 的目標是盡可能易於使用。使用者體驗應該是「取得 Python3 和 Ninja,然後執行」,即使在 Windows 上也是如此。不幸的是,這意味著我們不能依賴 Python 標準函式庫以外的專案。這僅適用於核心功能。但是,對於其他輔助程式等,可以使用外部依賴項。如果您認為您正在處理這種情況,請先聯繫開發人員並說明您的使用案例。

圖靈完備性

Meson 的主要設計原則是,定義語言不是圖靈完備的。任何會使 Meson 成為圖靈完備的變更都會自動被拒絕。實際上,這表示不會將在 meson.build 檔案中定義自己的函數和廣義迴圈加入到語言中。

我需要簽署 CLA 才能貢獻嗎?

不需要。歡迎所有貢獻。

沒有殘留狀態

Meson 的運作方式與函數式程式設計語言非常相似。它具有輸入,包括 meson.build 檔案、選項的值、編譯器等。這些會傳遞給一個函數,該函數會產生輸出建置定義。這個函數是純函數,這表示:

  • 對於任何給定的輸入,輸出始終相同
  • 連續兩次運行 Meson *始終* 在兩次運行中產生相同的輸出

後者非常重要,因為它強制執行了 Meson 的連續調用之間無法傳遞「秘密狀態」。這就是為什麼,例如,即使有 get_option 函數,也沒有 set_option 函數的原因。

如果不是這種情況,我們就永遠無法知道建置輸出是否「穩定」。例如,假設有一個 set_option 函數和一個布林變數 flipflop。然後您可以這樣做:

set_option('flipflop', not get_option('flipflop'))

這段程式碼永遠不會收斂。每次 Meson 運行都會變更選項的值,因此您從這個建置定義中獲得的輸出將是隨機的。

Meson 不允許這種情況,因為它禁止這些秘密通道。

這個規則有一個例外。使用者可以使用 run_command 調用外部命令。如果該命令的輸出行為不像純函數,就會出現這個問題。Meson 不會嘗試防範這種情況,使用者有責任確保他們執行的命令行為像純函數。

環境變數

環境變數就像全域變數,只是預設情況下也是隱藏的。應盡可能避免使用環境變數,所有功能都應以更好的方式公開,例如命令列切換。

不適合放在其他地方的隨機設計點

  • 所有功能都應遵循 90/9/1 規則。90% 的使用案例應該很容易,9% 應該有可能,如果會使事情過於複雜,完全不支援最後的 1% 也是可以的。

  • 任何建置目錄最多將會有兩個工具鏈:一個本機工具鏈和一個交叉工具鏈。

  • 偏好特定的解決方案而不是通用的框架。解決最終使用者的問題,而不是為他們提供自己解決問題的工具。

  • 永遠不要使用 Unix shell(或 Windows shell,就此而言)的功能。不允許使用諸如使用 > 轉發輸出或使用 && 調用多個命令之類的操作。每當出現這些類型的需求時,請編寫具有所需功能的內部 Python 腳本並改用它。

子頁面

YAML 參考手冊 – 編輯和維護參考手冊

Meson CI 設定

搜尋結果如下: