MPS 2019.2ヘルプ

使い方-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";
最終更新日: 2019年8月30日