ビルド言語
MPS ビルド言語とは何ですか?
ビルド言語は宣言的な方法でビルドを定義するための拡張可能なビルド自動化 DSL です。Ant(英語) に生成された、Ant の実行機能を活用しながら、ソースをクリーンで無駄のない詳細情報から解放します。一番下に ANT がある MPS 言語のスタックとして編成されているため、ビルド手順の各部分を異なる抽象化レベルで表現することができます。(MPS プラグインのような)複雑なアーティファクトを構築することは、言語の慣習に従えば、たった 1 行のコードで指定できますが、同時に、ファイル管理や詳細のカスタマイズを妨げるものは何もありません。マニフェストプロパティ
多くのビルド自動化ツールと同様に、プロジェクト定義はスクリプトの中核です。さらに、他のほとんどのツールとは異なり、ビルド言語を使用すると、出力ディレクトリのレイアウトを完全に制御できます。期待されるビルド結果は、一部の(サードパーティの)プラグインの一部としてではなく、ビルドスクリプトで個別に定義されます。すべてのビルドスクリプトは、3 つの部分で構成されています。1 つ目は依存関係です。これは、すでに構築されている必要なものです。たとえば、ライブラリやサードパーティの言語について考えてみてください。次はプロジェクトの構造です。これには、リポジトリにあるすべてのものとビルドされるものの宣言、および必要なビルドパラメーターが含まれています。ここでアイテムを宣言しても、必要な場合、つまりスクリプトの最後の部分である出力レイアウトから参照されない限り、ビルドはトリガーされないことに注意してください。出力は、プレーンフォルダーとコピーされたファイルのセットのように単純なものでも、パッケージ化されたプラグインや MPS 言語などの zip 形式のアーティファクトではるかに複雑なものでもかまいません。例: Java ソースから jar ファイルをビルドするには、プロジェクト構造で Java モジュールを宣言し、出力レイアウトでモジュールへの参照を使用してそれぞれの jar ファイルを宣言する必要があります。
MPS のおかげで、ビルド言語には、簡潔なテキスト表記と、完了やオンザフライ検証などの優れた編集エクスペリエンスが備わっています。拡張言語(または他のビルドツールの用語に固執する場合はプラグイン)は、言語の上に追加の抽象化を追加します。私たちの経験では、Maven または Gradle プラグインを開発するよりも、新しいプラグインを作成するのは非常に簡単なプロセスです。
スクリプト構造を構築する
以下の Intellij IDEA 用のプラグインをビルドするビルドスクリプトの例を参照してください。

よく見てみましょう。スクリプトのヘッダーは、一般的なスクリプト情報で構成されています。スクリプトの名前(スクリーンショットでは複雑)、スクリプトが生成されるファイル(build.xml)、スクリプトのベースディレクトリ(スクリーンショットでは次のように表示されます)。スクリプトの場所 ../../ およびフルパスを基準にしています)。
スクリプトの本体は、以下のセクションで構成されています。
use plugins には、スクリプトで使用されるプラグインのリストが含まれています。ビルド言語のプラグインは Gradle のプラグインに似ています。これらは、java コードのコンパイル、単体テストの実行、モジュールのパッケージ化など、便利なことを行うための多くのタスクを提供する言語の拡張機能です。スクリーンショットでは、2 つのプラグインが使用されています。java および mps。これは、スクリプトが java および mps コードをビルドできることを意味します。
マクロセクションでは、プロジェクトで使用されるパスマクロと変数(idea_home と plugins_home)を、スクリプトの実行中にオーバーライドできるデフォルト値とともに定義します。
dependency は、他のビルドスクリプトに対するスクリプトの依存関係を定義します。スクリプトが他のビルドスクリプトで定義されたものを参照する場合、依存関係セクションでこのスクリプトを指定する必要があります。スクリーンショットのサンプルスクリプトは、他の 2 つのスクリプト IDEA と mpsPlugin に依存しています。これらは MPS によって提供されるため、使用するにはアーティファクトの場所、つまり ant が作業の結果を見つけることができる場所を指定する必要があります (例では、idea_home は Intellij IDEA jar と plugins_home の場所を指す必要があります) IDEA の MPS プラグインの場所を指す必要があります)。同じ MPS プロジェクト内のいくつかのビルドスクリプトに依存することもできます。その場合、アーティファクトの場所は必要なく、必要なスクリプトが現在のスクリプトの直前にビルドされることが想定されます (これを行うためのターゲット buildDependents があります)。
プロジェクト構造セクションには、プロジェクトの説明、つまり、プロジェクトに含まれるモジュール、ソースコードの場所、モジュールのクラスパスなどが含まれます。スクリーンショットのサンプルプロジェクトは、Complex という名前の単一のアイデアプラグインと、MPS モジュール。
デフォルトのレイアウトは、プロジェクトをディストリビューションにパッケージ化する方法を定義します。スクリーンショットのサンプルプロジェクトは、Complex.zip という名前の zip ファイルにパッケージ化されています。
追加の側面は、プロジェクトに関連する他のいくつかのことを定義します。たとえば、さまざまな設定、実行する統合テストなどです。
マクロ
マクロには 2 種類あります。
フォルダー - ファイルシステム内の物理フォルダーを表します。空のままにすると(デフォルト)、値は MPS で定義された同じ名前のパス変数から取得しようとします。
Var- 値を表すカスタム変数
変数は、いくつかの方法で初期化できます。
以前のマクロへの参照
date - 日付値、Java の日付フォーマット規則に従うパターンパラメーターを指定する必要があります。たとえば、yyyy-MM-dd。ビルドスクリプトが実行された時刻の日付値がマクロに挿入されます。
プロパティファイルからロード - 指定されたプロパティファイルから指定されたプロパティ値を読み取ります
load file - 指定されたファイルをプロパティにロードします
テキスト - プレーンテキスト値、潜在的に ${macro_ref} シンボルに包まれた他のマクロに埋め込まれた参照を持ちます。
組み込みプラグイン
ビルド言語はいくつかの組み込みプラグインを提供します。
Java プラグイン
Java プラグインは java コードをコンパイルしてパッケージ化する機能を追加します。ソースコードは java モジュールと java ライブラリとして表されます。
Java モジュールは、そのコンテンツ (ソースフォルダーの場所) と、他のモジュール、ライブラリ、jar への依存関係を定義します。コンテンツセクションでは、java モジュールには次のものを含めることができます。
フォルダー – ディスク上のソースフォルダーへのパス。
リソース – リソースのファイルセット。リソースフォルダーへのパスとセレクターのリスト(include、exclude、includes)で構成されます。
コンテンツルート – 複数のコンテンツフォルダーを持つルート。
依存関係セクションでは、java モジュールには次のものを含めることができます。
classpath – クラスパスを持つ任意の xml。
外部 jar – 他のビルドスクリプトレイアウトからの jar ファイル。
フォルダー内の外部 jar – 他のビルドスクリプトレイアウトからフォルダー内の名前で参照される jar ファイル。
jar – ローカル jar へのパス。
library – java ライブラリへの参照。
module – java モジュールへの参照。
各 java モジュールは、ソースモジュールの依存関係に従って他のターゲットに依存する独自の ant ターゲットに生成されます。循環モジュールの依存関係をコンパイルするために、2 段階のコンパイルが実行されます。
「サイクル」ターゲットは、サイクル内のすべてのモジュールをまとめてコンパイルします。
サイクル内の各モジュールは、クラスパス内の "cycle" ターゲットのコンパイル結果でコンパイルされます。
Java ライブラリは jar(パスまたは他のプロジェクトレイアウトへの参照として指定される)とクラスフォルダーで構成されています。利用可能な要素は以下のとおりです。
classes フォルダー – クラスを含むフォルダー。
外部 jar – 他のビルドスクリプトレイアウトからの jar ファイル。
external jars from – 他のビルドスクリプトレイアウトのフォルダーからの jar のコレクション。
jar – ローカル jar へのパス。
jars – jar とセレクターのリスト(include、exclude、includes)を含むローカルフォルダーへのパス。
java モジュールのコンパイル設定は、java オプションで指定されます。ビルドスクリプトには複数の java オプションがあり、デフォルトにできるのはそのうちの 1 つだけです。各モジュールは、コンパイルに使用される独自の java オプションを指定できます。

デバッグ情報の生成 - ant タスクの「コンパイル」の「デバッグ」属性を設定します
警告を生成しない - 「compile」ant タスクの「nowwarn」属性を設定します
fork - 並列コンパイルを可能にするために、「compile」ant タスクの fork 属性を設定します。
コンパイラー - 利用可能なコンパイラーのリストからコンパイルに使用するコンパイラーを選択します
java 準拠レベル - ant タスクの「コンパイル」および ant タスクの「生成」および「作成」のソースおよびバイトコードレベルを設定します
java コンパイラーオプション - ant タスクの「compile」タスクの「compileearg」要素を設定します。スペースで区切られた有効な「compileearg」値が必要です。「encoding」属性が存在しない場合、「-encoding」は「utf8」に設定されます。
ジェネレーター jvm オプション - 「generate」ant タスクの「jvmarg/arg」要素を設定します
リソースのコピー - コンパイル前にリソースファイルのコピーを作成します。source_gen にあるすべての非 Java ファイルがコピーされます。java オプション / リソースパターンが指定されている場合を除きます。これは、たとえば、jetbrains.mps.lang.resources 言語を使用して定義されたアイコンに必要です。
リソースパターン - ファイルがリソースを考慮するためのファイルマスク。
Java ターゲット
Java プラグインは以下のターゲットを追加します。
compileJava は、プロジェクト内のすべての java モジュールをコンパイルします。
追加のリソース処理のための processResources 拡張ポイント。
クラスは、プロジェクト内のすべてのコンパイルとリソース処理を行います。これは、ターゲットの compileJava、processResources に依存します。
単体テストを実行するためのテスト拡張ポイントターゲット。
check は、プロジェクトの正確性のすべてのテストとチェックを行います。ターゲットテストによって異なります。
MPS プラグイン
MPS プラグインを使用すると、スクリプトのビルド言語で mps モジュールをビルドできます。MPS プラグインを使用するには、jetbrains.mps.build.mps 言語を使用言語に追加する必要があります。
MPS モジュールとグループ
MPS プラグインはプロジェクト構造にモジュールを追加することを可能にします。スクリーンショットには、ビルドスクリプトで宣言された言語の例があります。

ビルドスクリプトで指定されたモジュールに関する多くの情報があり、そのほとんどがインスペクタツールウィンドウに表示されることに注意してください: uuid と完全修飾名、記述子ファイルへのフルパス 、依存関係、ランタイム(言語の場合)など。この情報モジュールのパッケージ化にはが必要です。依存関係が追加されるなど、このモジュールで何かが変更されるたびに、ビルドスクリプトも変更する必要があります。もちろん、それを簡単に行うためのツールはたくさんあります。スクリプトで mps モジュールを記述および管理する一般的なプロセスは、次のようになります。
スクリプトにモジュールを追加します。1 つは、追加するモジュールのタイプ (ソリューション、言語、開発キット) とモジュール記述子ファイルへのパスを指定します。次に、インテンション「ファイルから必要な情報をロード」を使用して、そのファイルを読み取り、残りのモジュール仕様を自動的に入力できます。
モジュールに加えられた変更を反映しています。モデルチェッカーを使用してモデルをビルドスクリプトでチェックし、モデルがモジュールファイルと一致しているかどうかを確認できます。モデルチェッカーは、スクリプト内のすべての問題を表示し、クイックフィックスを実行ボタンを使用して修正できるようにします。モデルチェッカーの代わりに、同じ「ファイルから必要な情報をロードする」インテンションを使用して、各モジュールを個別に修正することができます。
ビルドスクリプトでの MPS モジュール宣言について覚えておくべきもう 1 つのことは、MPS にロードされているモジュールに依存していないということです。すべての情報はディスク上のモジュール記述子ファイルから取得されますが、モジュール自体はビルドスクリプトからは使用できない可能性があります。
ビルドスクリプトを構造化するために、MPS モジュールを mps グループに追加できます。 MPS グループは、名前付きのモジュールセットであり、外部から参照できます。たとえば、モジュールグループを 1 つのユニットとして IDEA プラグインに追加できます。
モジュールリソース
モジュールに必要なリソース(イメージ、アイコンなど)は、リソースコンテンツルートを使って指定する必要があります。

MPS モジュールの生成とコンパイルは内部でどのように機能するのか
上で書いたように、モジュールに関する多くの情報がビルドスクリプトに抽出され、そこに保存されます。これにより、モジュールの依存関係が変更されるたびに、ユーザーはスクリプトを適切に更新する必要があります。ソリューションの場合、スクリプトに抽出されるのは、再エクスポートされた依存関係と再エクスポートされていない依存関係の両方です。言語の場合、依存関係とは別に、ランタイムソリューションと拡張言語も抽出されます。
ビルドスクリプトを使用したモジュールの「ビルド」は、このモジュールの生成とモジュールソースのコンパイルの 2 つの部分で構成されます。生成は、ソースコードをバージョン管理システムに保存し、モデルとの同期を保つプロジェクトのオプションのステップです。生成では、ビルドスクリプト内のすべてのモジュールを生成する 1 つのターゲットが作成されます。モジュールは「チャンク」(一緒に生成できるモジュールのグループ)に分割され、生成タスクはチャンクを 1 つずつ生成します。例: 言語とその言語で記述されたソリューションは一緒に生成できないため、別々のチャンクに分割されます。生成タスクには、生成するチャンクのリストとは別に、ロードするアイデアプラグインのリストと、生成に必要な他のビルドスクリプトのモジュールのリストが提供されます。このプラグインとモジュールのリストは依存関係から計算されるため、生成を成功させるにはそれらが正確であることが非常に重要です。これは、MPS からモジュールを生成する場合とビルドスクリプトからモジュールを生成する場合の大きな違いです。一方、MPS からモジュールを生成する場合、ジェネレーターにはプロジェクト内のすべてのモジュールがロードされ、使用可能になります。ビルドスクリプトからモジュールを生成する場合、ジェネレーターにはモジュールの依存関係で明示的に指定されたもののみが含まれます。ビルドスクリプトは、モジュールの依存関係が正しいかどうかを検証する手段として使用できます。
モジュールのコンパイルは少し異なります。MPS モジュールごとに java モジュールが生成されるため、最終的に各 MPS モジュールは通常の ant javac タスク(または Java オプションで選択されている場合は同様の他のタスク)によってコンパイルされます。
そのため、生成してコンパイルするために、モジュールの依存関係が収集され、生成されたビルド xml ファイルに埋め込まれます。使用されている言語と devkits はモジュール記述子ファイルからビルドスクリプトを生成する間に集められます。その他の情報はビルドスクリプトノード内に格納されています。下の図では、「myproject」というプロジェクトのモジュール構造が示されています。このプロジェクトは、「mylibrary」というサードパーティの MPS ライブラリを使用しています。

矢印はモジュール間の依存システムを示しています。紫色の矢印はビルドスクリプトに抽出される依存関係を示し、青い矢印はどの依存関係が抽出されないかを示します。私のプロジェクトからモジュールをコンパイルして生成するために、mylibrary の中の「青い矢印」の知識が必要とされないことは容易に観察されることができます。つまり、私のライブラリの実際のモジュールファイルは、myproject ビルドスクリプトの生成中にも存在しないかもしれません。ジェネレーターが必要とするすべての情報はビルドスクリプトに含まれています。これは非常に便利です。ビルドの生成中にライブラリ全体をダウンロードしてその完全な場所を指定する必要がないため、生成プロセスではプロジェクトの依存関係からすべてのモジュール記述子をロードしないため時間とメモリを節約できます。
ソースとテスト
MPS ソリューションにテストモデル、すなわちステレオタイプ "@tests" のモデルが含まれている場合、それらはデフォルトではコンパイルされないフォルダー "tests_gen" に生成されます。テストをコンパイルするには、ソリューションにテストモデルがあることをビルドスクリプトで指定する必要があります。これはインスペクタで手動で行われます。解決策に利用可能な 3 つのオプションがあります: "with sources"(デフォルト)、"with testing" そして "with sources and tests"。

MPS の設定
mps 設定を使用すると、ビルドスクリプトの MPS 固有のパラメーターを変更できます。「追加の側面」セクションのビルドスクリプトには、mps 設定のインスタンスが 1 つしか存在できません。変更できるパラメーター:
bootstrap – このフラグを「true」に設定すると、スクリプト内のモジュール間にブートストラップの依存関係が存在することを示します。通常、フラグは false に設定されます。詳細については、ブートストラップ依存関係の問題の除去を参照してください。
テスト生成 – true に設定されている場合、ビルドスクリプトはモジュールの生成と、生成されたファイルとディスク上のファイルの違いをテストします。除外セクションでファイルを diff から除外できます。
generation max heap size in mb – 世代および世代テストの最大ヒープサイズ。
テストモジュール生成
生成されたソースファイルをバージョン管理で保持するプロジェクトでは、ビルドスクリプトを使用して、これらの生成されたファイルが最新であることを確認できます。mps 設定でテスト生成を true に設定すると、生成されたビルドスクリプトのテストターゲットに gentest タスクの呼び出しが表示されます。generate タスクと同様に、gentest は スクリプト内のモジュール、他のビルドスクリプトからの依存関係、および必要なアイデアプラグインをロードします。各モジュールに対して、gentest タスクは 2 つのテストを呼び出します: "%MODULE_NAME%.Test.Generating "と"%MODULE_NAME%.Test.Diffing"。Test.Generating はモジュールの生成中にエラーが発生すると失敗し、Test.Diffing は生成されたファイルがディスク上のファイル (バージョン管理からチェックアウト) と異なると失敗します。テスト結果と統計は、TeamCity ビルドサーバーでサポートされている xml ファイルにフォーマットされます。
IDEA プラグイン
アイデアプラグインの構築では、MPS モジュールを含む IntelliJ IDEA または MPS のプラグインを定義します。スクリーンショットでは、そのようなプラグインの例を見ることができます。

プラグイン宣言の最初のセクションは、プラグインを説明するさまざまな情報 (名前と説明、フォルダーの名前、プラグインのベンダーなど) で構成されます。ここで重要な文字列は、キーワード idea plugin の後に続く plugin id です。これは、他のすべてのプラグインの中でのプラグインの一意の識別子です。plugin.xml ファイルの構築方法には 3 つのオプションがあります。ビルドスクリプトのアイデアプラグインセクションに含まれる情報のみを使用することも、提供された plugin.xml ファイルのコンテンツで情報を強化することも、カスタム plugin.xml ファイルのみを使用することもできます。

アイデアプラグインの中の次のセクションは実際のプラグインコンテンツです - プラグインに含まれるモジュールまたはモジュールグループのセットです。
最後のセクションは他のプラグインへのプラグインの依存関係について書かれています。ルールは、"pluginB" にある "moduleB" に依存する "pluginA" にある "moduleA" がある場合、"pluginB" に対する "pluginA" の依存関係があるはずです。そのような問題を識別して報告する型システムチェックが存在します。
プラグインのレイアウトは最後に指定されています。プラグインをパッケージ化する方法は 2 つ考えられます。
自動パッケージ化 - 提供されているすべての言語とソリューションは、プラグインのルートディレクトリの「languages」フォルダーに配置されます。
手動パッケージ - 開発者はプラグイン全体のレイアウトを手動で定義する必要があります

MPS のターゲット
MPS プラグインは以下のターゲットを提供します。
generate- プロジェクト構造に含まれる mps モジュールを生成します。
cleanSources- 生成されたコードをクリーンアップします(ブートストラップ依存関係のないモジュールのみ)。記事ブートストラップ依存関係の問題の除去で、ブートストラップの依存関係の詳細を参照してください。
describe-mps-tasks - generate や copyModels などの mps タスクを宣言するユーティリティターゲット。
makeDependents- このスクリプトの依存関係(存在する場合)を一時的に閉じるための生成ターゲットを呼び出してから、アセンブルを呼び出してまとめます。各スクリプトは、すべての依存関係が構築された後にのみ実行されることが保証されています。
モジュールテストプラグイン
jetbrains.mps.build.mps.tests 言語によって提供されるモジュールテストプラグインは、MPS ソリューションで NodeTestCases と EditorTestCases を実行する機能をビルドスクリプトに追加します。テストは、すべてのモジュールがコンパイルされてディストリビューションにパッケージ化された後、つまりパッケージ化されたコードに対して実行されるため、コードの実際の使用を厳密に模倣する環境で呼び出されます。
テストモジュール構成
テストを含むソリューション / モジュールグループは、テストモジュール構成にグループ化されます。これは、同じ環境で一緒に実行されるテストを含むソリューションのグループです。必要なすべての依存関係(つまり、モジュールとプラグイン)がその環境にロードされます。スクリーンショットでは、ソリューション jetbrains.mps.execution.impl.tests とモジュールグループ debugger-tests を含む execution という名前のテストモジュール構成を確認できます。

テストモジュール構成にソリューションを含めるための前提条件があります。解決策は、テストを含むものとして指定する必要があります(インスペクタで「テスト付き」または「ソースとテスト付き」を選択することによって)。モジュールグループには、テストを含むモジュールを少なくとも 1 つ含める必要があります。
テスト結果と統計は、xml ファイル(TeamCity でサポートされています)にフォーマットされています。
テストモジュールの実行構成構築は、MPS ant テスト実行中にロードされるべきである追加のアイデアプラグインを指定する可能性をサポートします。MPS ant テストの実行に必要なプラグインは、自動的に計算できないことがあります。テストが利用可能な特定のプラグインを必要とし、その情報が MPS ビルド言語エンジンによってテストを含むモジュールから推論できないというシナリオがあります。そのような場合、必要なプラグインは手動で指定できます。
他にもいくつかのオプションが利用可能です。
失敗の停止 - 最初のテストが失敗したときにテストの実行を停止します。
compress args - JAVA_TOOL_OPTIONS 環境変数を使用して Windows 上のコマンドラインのサイズ制限を回避するには、true に設定します。
jvm 引数 - 追加の jvm 引数を指定します。

MPS ランナープラグイン
Jetbrains.mps.build.mps.runner によって提供される MPS-runner プラグインは、新しいビルドスクリプトエントリを有効にし、ソリューションからコードを実行します。Java コードを保持するソリューションを指定すると、ビルドスクリプトはビルドプロセスの一部としてそのコードを実行できるようになります。

プロジェクトの「サンドボックス」ソリューションにある Java クラスを呼び出す最小限のビルドスクリプトは、次のようになります。

ソリューション命令からコードを実行すると、コードを実行する MPS インスタンスで選択したプラグインを有効にできます。対応するプラグインは、その依存関係とともに有効になります。

リポジトリを管理する
MPS ant タスクは、いくつかの新しいタグ(module、modules、allmpsmodules)を使用して、リポジトリの内容を完全に制御します。

使い方
以下の記事では、言語プラグインを構築する方法について説明します。
MPS を使ったビルドの話題に関する記事:
関連ページ:

ブートストラップ依存関係の問題の除去
定義::いつでもそれ自体を使用する言語または、言語を使用し、その言語が機能するために同じソリューションを必要とする(つまり、間接的または直接依存する)ソリューション、ブートストラップ依存関係の問題があります。なぜこれが問題なのですか:ビルドスクリプトを使用してプロジェクト全体をゼロから再構築することはできません、生成されたアーティファクトを VCS リポジトリに保持する必要があります、このブートストラップ依存関係サークルは、プロジェクトが完全に一から再構築されることを防ぎます。代わりに、言語を...

MPS 言語プラグインの構築
言語セットを作成し、それを対象ユーザーが利用できるようにしたいと考えています。このドキュメントでは、言語セットを、それらが依存するランタイムと一緒に、有効な MPS プラグインにパッケージ化する方法について説明します。注: MPS に付属の JavaExtensionsSample サンプルプロジェクトには、サンプルの Java 拡張機能をビルドしてプラグインにパッケージ化するための完全に機能的なビルドスクリプトが含まれています。そこからインスピレーションを受けることができます。出発点:あなた...

パターン
パターン言語:パターン言語には、モデル構造のパターンを定義するという単一の目的があります。これらのパターンは、マッチングしたいノードの視覚的表現を形成します。ノードのプロパティ値がパターンで指定された値と等しい場合、パターンはノードと一致し、ノードの参照はパターンのものと同じターゲットを指し、対応する子はパターンの適切な子と一致します。また、パターンにはノード、参照、プロパティの変数を含めることができます。これらの変数は、任意のノード / 参照 / プロパティに一致します。それに加えて、変数は...