Mesonへの貢献
Mesonの大部分は、コアチーム外の開発者によって貢献されています。このドキュメントでは、Mesonの設計上の理由と、パッチを作成してMesonに提出する方法について説明します。
開発へのご参加への関心をお寄せいただき、ありがとうございます。
パッチの提出
すべての変更は、GitHubへのプルリクエストとして提出する必要があります。これにより、CIシステムで実行されます。すべての提出物は、提出前に完全なCIテスト実行に合格する必要があります。
プルリクエストの最新の状態を維持する
プルリクエストのレビュー中に、masterブランチに他の変更がコミットされ、マージの競合が発生する可能性があります。これに対する基本的なルールは非常に簡単です。リベース*のみ*を使用して、プルリクエストを最新の状態に保ってください。
ヘッドをブランチにマージしないでください。プルリクエストにマージコミットが含まれている場合、masterブランチへのマージは受け入れられず、削除する必要があります。
新機能に関する特別な手順
すべての新機能には、いくつかの追加手順が必要です。
test cases/
の下にプロジェクトテストを含める必要があります。それが不可能な場合、またはテストに特別な環境が必要な場合は、run_unittests.py
に含める必要があります。- FeatureChecksフレームワークに登録する必要があります。これは、古いMesonバージョンをターゲットにして新機能を使用しようとすると、ユーザーに警告します。
docs/markdown/snippets/
内にリリースノートのスニペットを含める必要があります。見出しと、機能の説明と例を記載した短い段落を含めます。
承認とマージ
マージ提案が受け取るレビューと承認の種類は、含まれる変更によって異なります。すべてのプルリクエストは、元の提出者ではないコミット権限を持つ誰かによってレビューおよび承認される必要があります。マージリクエストは、大まかに3つの異なるカテゴリに分類できます。
最初のカテゴリは、docs/markdown
下のMarkdownドキュメントのみを変更するMRです。アクセス権のある人は誰でも、これらの変更をmasterブランチに直接プッシュできます。主要な変更については、他の人がコメントできるようにMRを作成することをお勧めします。
2番目のカテゴリは、機能を変更せず、CIシステムの修正と回帰テストが追加されたバグ修正(下記参照)であり、既存の機能を変更しないマージです。正常にレビューされた後、マージ権限を持つ人は誰でもmasterブランチにマージできます。
最後のカテゴリは、新しい機能を追加するか、既存の機能を後方互換性のない方法で変更するマージです。これには、プロジェクトリーダーの承認が必要です。
簡略化されたリスト形式では、分割は次のようになります。
- コミットアクセス権を持つメンバーが行うこと
- ドキュメントの変更(必要に応じてmasterブランチに直接)
- 機能を変更しないバグ修正
- リファクタリング
- 新しい依存関係の種類
- 新しいツールのサポート(例:新しいDoxygenのようなツール)
- 既存の言語への新しいコンパイラのサポート
- プロジェクトリーダーの決定が必要なもの
- 新しいモジュール
- Meson言語の新しい関数
- Mesonファイルの構文の変更
- 後方互換性を壊す変更
- 新しい言語のサポート
緑色のCI実行はマージに必須です
完全に緑色のCI実行がない限り、マージリクエストはマージできません。CIが失敗する理由に関係なく、ハードブロッカーとなります。たとえMRが失敗とは関係がなく、明らかに許可されるべきであっても、マージできません。CIの問題を修正するMRのみがtrunkに配置できます。
これには1つ、そして1つだけの例外があります。執筆時点では、Apple CIは信頼性が低く、クロックスキューエラーで失敗することがあります。
マージによってCIが失敗した場合、開発者は誰でもmasterブランチからそれを元に戻すことができます。修正版を再提出する責任は、元の提出者にあります。
trunkへのプルリクエストのマージ戦略
Mesonのマージ戦略は、次のガイドラインを満たしている必要があります。
-
可能な限り多くの履歴を保持する
-
リポジトリにできるだけ多くのジャンクを入れない
-
"master lineage"内のすべてが常にすべてのテストに合格する
これらの目標はわずかに矛盾しているので、正しいことを行うには、多くの場合、マージを行う人の判断が必要です。GitHubは3つの異なるマージオプションを提供します。それらの間の選択に関する経験則は次のとおりです。
-
単一コミットのプルリクエストは常にリベースする必要があります。
-
1つのコミットと1つの「fixup」コミット(CIに合格するかどうかをテストするなど)を含むプルリクエストは、squashする必要があります。
-
多数のコミットを含む大規模なブランチは、マージコミットを使用してマージする必要があります。特に、コミットの1つがすべてのテストに合格しない場合(たとえば、大規模で困難なリファクタリングの場合)。
不明な点がある場合は、IRCでガイダンスを求めてください。
テスト
すべての新しい機能には、機能が期待どおりに動作することを徹底的に証明する自動テストが付属している必要があります。同様に、バグ修正には、バグを示し、修正されたことを証明し、将来機能が壊れるのを防ぐ単体テストが付属している必要があります。
特定のバグに対して単体テストを作成することが難しい場合があります。その場合は、プルリクエストにそれを記載してください。これらのケースでは、バグ修正マージリクエストを許可する場合があります。これはケースバイケースで行われます。場合によっては、テストを書く方が、メンテナンス担当者にテストが不要であることを納得させるよりも簡単です。判断を行い、問題のあるケースではヘルプを求めてください。
テストは、単体テストと完全なプロジェクトテストの2つの異なる部分に分かれています。すべてのテストを実行するには、./run_tests.py
を実行します。単体テストは./run_unittests.py
で、プロジェクトテストは./run_project_tests.py
で実行できます。
プロジェクトテスト
プロジェクトテストのサブセットは、./run_project_tests.py --only
オプションを使用して選択できます。Mesonの特定の部分のみをテストする場合、これにより多くの時間を節約できます。たとえば、Mesonへの役立つ簡単な貢献は、コンパイラの完全なセットがサポートされていることを確認することです。たとえば、FC=ifort
、FC=flang
、またはFC=flang-new
などを使用して、さまざまなFortranコンパイラをテストできます。./run_project_test.py --only 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.ini
とnativefile.ini
は、それぞれ--cross-file
オプションと--native-file
オプションを使用して構成ステップに渡されます。 -
mlog.cmd_ci_include()
は、Meson内のどこからでも呼び出して、失敗時に追加ファイルの内容を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
辞書には、インストールされると予想されるファイルを記述する辞書のリストが含まれています。各辞書には次のキーが含まれています。
ファイル
タイプ
-
プラットフォーム
(オプション) -
バージョン
(オプション) -
言語
(オプション)
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 は式です。このタイプは避けて、可能であれば削除する必要があります。 |
file
、python_file
、expr
タイプを除き、すべてのパスはサフィックスなしで提供する必要があります。
引数 | 適用先 | 説明 |
---|---|---|
バージョン
|
shared_lib 、pdb |
プラットフォームごとに適切なバージョンを検索するように設定します。 |
言語
|
pdb
|
このファイルの存在を決定するコンパイラ/リンカを決定します。 |
shared_lib
およびpdb
タイプは、オプションの追加パラメータversion
を取ります。これはX.Y.Z
形式の文字列であり、ライブラリに適用されます。テストする各バージョンは、単一のバージョンを持たなければなりません。ハーネスはこのバージョンをプラットフォームごとに正しく適用します。
python_file
、python_lib
、およびpy_implib
タイプは、@<VAR>@
構文を使用して文字列の構成を基本的にサポートしています。
-
@PYTHON_PLATLIB@
:プレフィックスを基準としたPythonのget_install_dir
ディレクトリ -
@PYTHON_PURELIB@
:プレフィックスを基準としたPythonのget_install_dir(pure: true)
ディレクトリ
pdb
はオプションのlanguage
引数を取ります。これは、pdbファイルを生成するべきコンパイラ/リンカを決定します。(dmdのoptlinkは生成しないため) pdbファイルを生成するコンパイラと生成しないコンパイラを混在させることが可能なためです。現在、これは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.dll
とlib-1.dll
を期待します。macOSではliblib.dylib
とliblib.1.dylib
を期待します。その他のUnix系システムでは、liblib.so
、liblib.so.1
、およびliblib.so.1.2.3
を期待します。
platform
キーが存在する場合、インストールされたファイルエントリは、プラットフォームが一致する場合にのみ考慮されます。現在サポートされているplatform
の値を以下に示します。
プラットフォーム | 説明 |
---|---|
msvc
|
msvcのようなコンパイラ(msvc 、clang-cl など)が使用されている場合に一致。 |
gcc
|
msvc ではない。 |
cygwin
|
プラットフォームがcygwinの場合に一致。 |
!cygwin
|
cygwin ではない。 |
matrix
matrix
セクションを使用して、異なるMesonオプションでプロジェクトテストを実行するテストマトリックスを定義できます。
options
ディクショナリには、可能なすべてのオプションとその値が指定されています。options
ディクショナリ内の各キーはMesonオプションです。これは、ディクショナリ形式で潜在的なすべての値のリストを格納します。
各値には、オプションの値を表すval
キーが含まれている必要があります。現在のオプションを含めないマトリックスエントリを追加するには、null
を使用できます。
現在の環境に基づいて、そのマトリックスエントリをスキップするために、skip_on_env
キー(下記参照)を使用できます。
現在の環境に基づいて、テストがスキップされることを期待するために、expect_skip_on_jobname
キーとexpect_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
キーには、期待される標準出力について説明するディクショナリのリストが含まれています。
各ディクショナリには、次のキーが含まれています。
line
-
match
(オプション) -
count
(オプション)
リスト内の各項目は、以前の一致の後、残りの実際の標準出力行に対して順番に照合されます。リスト内のすべての項目が照合される前に実際の標準出力が使い果たされた場合、期待される出力が見つからず、テストは失敗します。
ディクショナリのmatch
要素は、line
要素の照合方法を決定します。
タイプ | 説明 |
---|---|
literal
|
リテラルマッチ(デフォルト) |
re
|
正規表現マッチ |
count
要素は、行が何回出力されることが期待され、許容されるかを決定します。指定されていない場合、それは「任意の回数、少なくとも1回」出現する必要があります。
skip_on_env
skip_on_env
キーを使用して、環境変数のリストを指定できます。skip_on_env
リスト内の少なくとも1つの環境変数が存在する場合、テストはスキップされます。
expect_skip_on_jobname
expect_skip_on_jobname
キーには、文字列のリストが含まれています。MESON_CI_JOBNAME
環境変数が設定されており、それらのいずれかがその部分文字列である場合、テストはスキップされると予想されます(つまり、CI環境が実行できる環境ではないため、テストがMESON_SKIP_TEST
を出力すると予想されます)。
テストは、予期せずスキップされるか、予期せず実行されるかのいずれかの場合に失敗します。
expect_skip_on_os
expect_skip_on_os
キーを使用して、OS名(または!
を接頭辞として付けた否定)のリストを指定できます。expect_skip_on_os
リスト内の少なくとも1つの項目が一致する場合、テストはスキップされると予想されます。
テストは、予期せずスキップされるか、予期せず実行されるかのいずれかの場合に失敗します。
統合テストのスキップ
Mesonは、コミットをスキップする必要があることを示すインターフェースがわずかに異なるいくつかの継続的インテグレーションテストシステムを使用しています。
現在使用されている継続的インテグレーションシステム
-
Azure Pipelinesでは、コミットメッセージに
***NO_CI***
を使用できます。 - SiderはFlake8を実行します(下記参照)
一貫性のある命名ポリシーを促進するために、次を使用してください。
-
すべての統合テストを無効にする場合は、コミットタイトルに
[skip ci]
を使用します。
ドキュメント
docs
ディレクトリには、Meson Webサイトを生成するために使用される完全なドキュメントが含まれています。ほとんどの場合、行の長さは70文字を超えてはなりません(リンクまたは例を含む行は通常免除されます)。機能の変更はすべて、ドキュメントページを変更する必要があります。ほとんどの場合、これは参照ドキュメントページの更新を意味しますが、大きな変更では他のドキュメントの変更も必要になる場合があります。
すべての新しい機能は、リリースノートに記載する必要があります。これらの機能は、docs/markdown/snippets
ディレクトリにスタンドアロンファイルとして記述する必要があります。リリースマネージャーは、リリース時にそれらを1つのページにまとめます。
Pythonコーディングスタイル
Mesonは基本的なPythonコーディングスタイルに従います。追加のルールは次のとおりです。
- インデントは4スペース、タブは決して使用しません。
meson.build
ファイルは2スペースでインデントします。- 可能な限りコードをシンプルに保ちます。
- 無駄な労力を避けるため、大規模なプロジェクトに着手する前にメーリングリストに連絡してください。
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スペース、タブは決して使用しません。
- 中括弧は常にif/for/else/関数定義と同じ行にあります。
外部依存関係
Mesonの目標は、可能な限り簡単に使用できるようにすることです。ユーザーエクスペリエンスは、Windowsでも「Python3とNinjaを入手して実行する」である必要があります。残念ながら、これはPythonの標準ライブラリ以外のプロジェクトに依存することはできないことを意味します。ただし、これはコア機能のみに適用されます。追加のヘルパープログラムなどについては、外部依存関係の使用が許容される場合があります。このようなケースに対処していると思われる場合は、まず開発者にユースケースを連絡してください。
チューリング完全性
Mesonの主な設計原則は、定義言語がチューリング完全ではないことです。Mesonをチューリング完全にする変更は、自動的に拒否されます。実際には、meson.build
ファイル内で独自の関数を定義することと、一般的なループは言語に追加されません。
貢献するためにCLAに署名する必要がありますか?
いいえ、必要ありません。すべての貢献は大歓迎です。
残存状態なし
Mesonは、関数型プログラミング言語とほぼ同じ方法で動作します。入力には、meson.build
ファイル、オプションの値、コンパイラなどが含まれます。これらは関数に渡され、出力ビルド定義を生成します。この関数は純粋であるため、
- 任意の入力に対して、出力は常に同じです。
- Mesonを連続して2回実行すると、常に両方の実行で同じ出力が生成されます。
後者は重要です。これは、「秘密の状態」がMesonの連続した呼び出し間を渡す方法がないことを強制します。これが、たとえば、get_option
関数があるにもかかわらず、set_option
関数が存在しない理由です。
そうでない場合、ビルド出力が「安定」しているかどうかを知ることはできません。たとえば、set_option
関数とブール変数flipflop
があるとします。次に、これを行うことができます。
set_option('flipflop', not get_option('flipflop'))
このコードは決して収束しません。Mesonの実行ごとにオプションの値が変更され、このビルド定義から得られる出力はランダムになります。
Mesonは、このような隠れたチャネルを禁止することでこれを許可しません。
この規則には1つの例外があります。ユーザーはrun_command
を使用して外部コマンドを呼び出すことができます。そのコマンドの出力が純粋関数のように動作しない場合、この問題が発生します。Mesonはこのケースを防ごうとはしません。実行するコマンドが純粋関数のように動作することを確認することは、ユーザーの責任です。
環境変数
環境変数はグローバル変数に似ていますが、デフォルトでは非表示になっているという違いがあります。可能な限りenvvarを避けるべきです。すべての機能は、コマンドラインスイッチなど、より良い方法で公開する必要があります。
他に分類できないランダムな設計ポイント
-
すべての機能は90/9/1ルールに従う必要があります。すべてのユースケースの90%は簡単であるべきであり、9%は可能であるべきであり、複雑になりすぎる場合は最終的な1%をサポートしないことは完全に問題ありません。
-
ビルドディレクトリには、最大2つのツールチェーン(ネイティブとクロス)があります。
-
汎用フレームワークよりも具体的なソリューションを優先します。ユーザー自身にそれを実行するためのツールを提供するのではなく、エンドユーザーの問題を解決します。
-
Unixシェル(またはWindowsシェル)の機能は決して使用しないでください。
>
を使用して出力を転送したり、&&
を使用して複数のコマンドを呼び出したりすることは許可されていません。このような要件が発生する場合は常に、必要な機能を持つ内部Pythonスクリプトを作成して、代わりにそれを使用します。
検索結果は次のとおりです。