MPS 2020.1 ヘルプ

使い方 -MPS Make フレームワークへの統合

ファセットを構築

概要

基本的に他のビルドシステムや make システムと同様に、MPS make はアーティファクトをビルドするために一連のステップ、つまりターゲットを実行します。必要な make ステップのグローバルな順序付けは、各ビルドターゲットに指定された相対的な優先順位から導き出されます(ターゲット A は B の前に実行し、B は C の前に実行する必要があるため、グローバル順序は A、B、C です)。

完全な構築プロセスは、モデルをテキストに生成すること、これらのモデルをコンパイルすること、サーバーにデプロイすること、および / または graphviz ソースファイルから .png ファイルを生成することなど、いくつかの懸念に対処することができます。MPS では、このようなさまざまなビルド側面がビルドファセットで実装されています。ファセットは、共通の懸念に対処するターゲットの集まりです。

facet10

ファセット内のターゲットは設定パラメーターを交換できます。例:全体的な make プロセスの早い段階で実行するように宣言されているターゲットは、設定パラメーターを収集し、第 2 のファセットに渡します。このファセット内パラメーター交換を実現するためのメカニズムは、プロパティと呼ばれます。さらに、ターゲットは、make プロセス中にクエリを使用してユーザーから情報を取得できます。

facet11

全体的な make プロセスは、パイプとフィルターのパターンに沿って編成されています。ターゲットはフィルターとして機能し、配信されているデータストリームを処理します。ターゲット間を流れるデータはリソースと呼ばれます。さまざまな種類のリソースがあり、すべて異なる Java インターフェースおよびタプルとして表されます。

facet12

  • MResource には、ユーザーが作成した MPS モデル、プロジェクトのソリューションおよび言語に含まれているモデルが含まれています。

  • GResource は、出力モデル、つまり生成が完了した後のモデルの最終状態を含む生成プロセスの結果を表します。これらは過渡モデルであり、過渡モデルを保存ビルドオプションを使用して調べることができます。

  • TResource は text-gen の結果を表する

  • CResource は Java クラスのコレクションを表する

  • DR リソースはモデルに対するデルタ変更のコレクションを表する ( IDelta )

  • TextGenOutcomeResource は、textgen によって生成されたテキストファイルを表します。

ビルドターゲットはインターフェースを指定します。パイプとフィルターのパターンに従って、インターフェースは make に出入りするデータの種類を記述します。
ターゲット。これは、上記のリソースタイプ、およびターゲットがこれらのリソースに適用する処理の種類の観点から指定されます。以下の 4 つの処理ポリシーが定義されています。

  • transform がデフォルトです。このポリシーは、入力リソースタイプのインスタンスを消費し、出力リソースタイプのインスタンスを生成します。(たとえばそれは
    MResources を消費し、TResources を作り出す。)

  • 宣言する入力を消費しますが、出力は生成しません。* produce は何も消費しませんが、出力を生成する

  • パススルーはいかなるリソースにもアクセスせず、生産も消費もしません。

make プロセスはモデル生成よりも粒度が粗いことに注意してください。つまり、すべてのモデルジェネレータを実行するファセットが 1 つあります。必要なら
(モデル生成の前または後に何かをするのではなく)MPS 生成プロセスに追加のターゲットを「挿入」するには、リファクタリングが必要です。
generate ファセットこれはこの議論の範囲を超えています。

サンプルファセットの構築

MPS 用の C ベース言語を構築する mbeddr.com プロジェクトの一環として、実際の C コンパイラを MPS ビルドプロセスに統合する必要があります。さらに
特に、C 言語で書かれたプログラムには Makefile を生成する方法が含まれています。この Makefile は一度実行しなければなりません
対応する .c ファイルと .h ファイルが生成されました。つまり、MPS の make プロセスの最後です。

これを行うために、2 つのターゲットを持つ make ファセットを構築しました。最初のモデルは入力モデルを調べて、次のものを含む可能性があるディレクトリの絶対パスを収集します。
textgen の後の Makefile 次に 2 番目のターゲットは、このディレクトリに Makefile というファイルが実際に存在するかどうかを確認してから、make make を実行します。二つ
上記の概要で説明したように、ターゲットはプロパティを介してディレクトリを交換します。

最初のターゲット : ディレクトリの収集

ファセットは言語定義の plugins という側面にあります。プラグインモデルに {{jetbrains.mps.make.facets} 言語を含めるようにしてください。
FacetDeclaration のインスタンスを作成することができます。モデル uses が次の言語である場合、ファセットはモデルの作成プロセスの一部として実行されます。
ファセットを宣言します。

ファセットは runMake と呼ばれます。 TextGenGenerate に依存します。これら 2 つのファセットへの依存関係は、それらのファセット内のターゲットに対するターゲットの優先順位を宣言できるように指定する必要があります。

facet runMake extends <none> Required: TextGen, Generate

最初のターゲットは collectPaths と呼ばれます。入力モデルと連絡を取るために、{{transform IMResource-> IMResource} として指定されます。の
ファセットは、優先順位として after configure および before generate を指定します。後者は明らかです。なぜなら、彼らがいる前にモデルに到達したいからです
テキストに生成されます。前者の優先順位は、基本的に、make プロセスが初期化された後にこのターゲットを実行したいということです。(言い換えれば:
「始めに」何かをしたいのであれば、これら 2 つの優先順位を使います。)

target collectPathes overrides <none> { resources policy: transform IMResource -> IMResource Dependencies: after configure before generate

それから、make ファイルを含むモジュールに関する情報と、その中にあるディレクトリへのパスを格納するために使用するプロパティ pathes を宣言します。
生成されたコードは存在します。

Properies: list<[string, string]> pathes;

それでは、ターゲットの実装コードを見てみましょう。これが基本構造です。最初に pathes リストを初期化します。それから、
(これはリソースの集まりです)各入力で何かをします(後述)。それから output ステートメントを使って入力を出力します。
データ、つまり、出てきたものはすべて通過します。このターゲットを正常に終了させるために success ステートメントを使用します( success を使用)。
これがデフォルトなので、最後のオプションはオプションです。問題が発生した場合は、failure ステートメントを使用してターゲットを正常に終了できません。

(input)->void { pathes = new linkedlist<[string, string]>; input.forEach({~inpt => (module, models) res = ((module, models)) inpt; // do stuff. See below. }); output input; success; }

実際の処理は、MPS データ構造に対する単純な Java プログラミングです。

res.models.forEach({~model => string path = res.module.getGeneratorOutputPath() + "/" + model.getLongName().replaceAll("\\.", "/"); string locationInfo = res.module.getModuleFqName() + "/" + model.getLongName(); pathes.add([path, locationInfo]); });

getGeneratorOutputPath メソッドを使用して、特定のモジュールがそのコードを生成するパスを取得します(これは
モデルプロパティ)。次に、モデルのドット付きの名前を取得し、ドットをスラッシュに置き換えます。これは、そのモジュール内のモデルの生成ファイルが生成される場所であるためです。
(これを見るためにどんな MPS プロジェクト例を調べても)終わる。次に、モジュールの名前とモデルの名前をスラッシュで区切って保存します。
2 番目のターゲットにメッセージを記録する(変数 locationInfo}). We add the two strings to the {{pathes コレクションを介して。この pathes プロパティ
ファセット内の 2 番目のターゲットによって照会されます。

2 番目のターゲット : 実行

リソースを扱う必要がないため、これは pass through ポリシーを使用します。それが必要とするすべての入力は、上記の collectPaths ターゲットのプロパティから取得できます。この 2 番目のターゲットは after collectPaths}, {{after textGenbefore reconcile を実行します。それが collectPaths}, since it uses the property data populated by it. It has to run after {{textGen}, otherwise the make files aren't there yet. And it has to run before {{reconcile}, because basically everything has to run before {{reconcile の後に走らなければならないのは明らかです

target callMake overrides <none> resources policy: pass through Dependencies: after collectPathes after textGen before reconcile

それでは、実装コードを見てみましょう。実際に collectPathes.pathes プロパティを含むエントリをすべて collectPathes.pathes プロパティから取得することから始めます。
Makefile 何も見つからない場合は、success を返します。

sequence<[string, string]> modelDirectoriesWithMakefile = collectPathes.pathes. where({~it => new File(it[0] + "/Makefile").exists(); }); if (modelDirectoriesWithMakefile.isEmpty) { success; }

次に、プログレスインジケータ言語を使用して、make ファイルを含むディレクトリがあるのと同じ数のワークユニットでプログレスバーを設定します。

begin work "run make" covering ALL units of total work left, expecting modelDirectoriesWithMakefile.size units;

その後、{{modelDirectoriesWithMakefile} コレクションのすべてのエントリを反復処理します。ループでは、進行状況インジケーターを進めてから Java を使用します
make ファイルを実行するための標準 API。

foreach dirInfoTuple in modelDirectoriesWithMakefile { try { advance 1 units of "run make" with comment "running make for " + dirInfoTuple[1]; Process process = Runtime.getRuntime(). exec("make", new string[0], new File(dirInfoTuple[0])); if (process.waitFor() > 0) { error "make failed with exit code " + process.exitValue() + " for " + dirInfoTuple[1]; } else { info "make finished successfully for " + dirInfoTuple[1]; } } catch (Exception ex) { error ex.getMessage(), ex; } }

ターゲットをまとめるには、finish ステートメントを使用してプログレスバーをクリーンアップします。

finish "run make";
最終更新日 : 2020 年 6 月 18 日