(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

CompilationPipelineを使ってコンパイルの開始と終了を検知【Unity】【エディタ拡張】


このエントリーをはてなブックマークに追加


この記事でのバージョン
Unity 2019.1.0a8


はじめに

今回はコンパイルの開始と終了を検知する方法のご紹介です。


ちなみにUnityではプログラムを修正し、コンパイルが開始されると右下にアイコンが表示されます。

なので、このアイコンが表示された時と消えた時を検知しようという感じです。


f:id:kan_kikuchi:20181110104504j:plain


イメージとしては以下のような感じ


f:id:kan_kikuchi:20181110112343g:plain


compilationStartedとcompilationFinished

コンパイルの開始と終了を検知したい時はCompilationPipelineを使うと便利です。

使い方は簡単、compilationStartedcompilationFinishedというイベントにメソッドを登録するだけ。

using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;

[InitializeOnLoad]//エディター起動時に初期化されるように
public static class CompilationPipelineExample {

  //=================================================================================
  //初期化
  //=================================================================================

  /// <summary>
  /// コンストラクタ(InitializeOnLoad属性によりエディター起動時に呼び出される)
  /// </summary>
  static CompilationPipelineExample() {
    //CompilationPipelineの各イベントにメソッド登録
    CompilationPipeline.compilationStarted  += OnCompilationStarted;
    CompilationPipeline.compilationFinished += OnCompilationFinished;
  }

  //=================================================================================
  //全体のコンパイル開始と終了の検知
  //=================================================================================

  //全体のコンパイル開始時に呼ばれる
  private static void OnCompilationStarted(object obj){
    Debug.Log("全体のコンパイル開始");
  }

  //全体のコンパイル終了時に呼ばれる
  private static void OnCompilationFinished(object obj) {
    Debug.Log("全体のコンパイル終了");
  }

}

f:id:kan_kikuchi:20181110110436g:plain


ただし、この2つのイベントはUnity2019.1で追加されたものなので、それ以前では使えません。

(EditorApplication.isCompilingを使えば検知自体は可能です。)


なお、引数のobjectはドキュメントに以下のように書いてあるので、

Context object can be used to match CompilationPipeline.compilationStarted and CompilationPipeline.compilationFinished events.


Google翻訳
Contextオブジェクトを使用して、CompilationPipeline.compilationStartedイベントとCompilationPipeline.compilationFinishedイベントを一致させることができます。

Unity - Scripting API: Compilation.CompilationPipeline.compilationStarted


開始と終了のイベントを一致させるために使うようです。

おそらくコンパイル中に新たなコンパイルが発生しても混同しないようにするためのものだと思います。

//コンパイル開始時のオブジェクト
private object _startObj = null;

//全体のコンパイル開始時に呼ばれる
private static void OnCompilationStarted(object obj){
  Debug.Log("全体のコンパイル開始");
  _startObj = obj;
}

//全体のコンパイル終了時に呼ばれる
private static void OnCompilationFinished(object obj) {
  Debug.Log("全体のコンパイル終了");

  //開始と終了が一致しているか(同じコンパイルか)
  if(_startObj == obj){
      
  }
}



assemblyCompilationStartedとassemblyCompilationFinished

CompilationPipelineには

assemblyCompilationStartedassemblyCompilationFinishedというイベントもあり、

これを使えば各アセンブリごとのコンパイルの開始と終了を検知する事が出来ます。


なお、ここで言うアセンブリとは複数のファイルをまとめたもの(ライブラリアセンブリ : DLL)の事で、

例えばEditorという特殊フォルダのファイルはAssembly-CSharp-Editor.dll、

それ以外の特殊じゃないフォルダのファイルはAssembly-CSharp.dllというアセンブリにまとめられます。


f:id:kan_kikuchi:20181110120217j:plain


余談ですが、Assembly Definition Filesを使えばアセンブリを任意に分割する事も可能です。



使い方は先程と同様にイベントにメソッドを登録するだけ。

using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;

[InitializeOnLoad]//エディター起動時に初期化されるように
public static class CompilationPipelineExample {

  //=================================================================================
  //初期化
  //=================================================================================

  /// <summary>
  /// コンストラクタ(InitializeOnLoad属性によりエディター起動時に呼び出される)
  /// </summary>
  static CompilationPipelineExample() {
    //CompilationPipelineの各イベントにメソッド登録
    CompilationPipeline.assemblyCompilationStarted  += OnAssemblyCompilationStarted;
    CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished;
  }

  //=================================================================================
  //各コンパイル開始と終了の検知
  //=================================================================================

  //各コンパイル開始時に呼ばれる
  private static void OnAssemblyCompilationStarted(object obj) {
    Debug.Log(obj + "のコンパイル開始"); 
  }

  //各コンパイル終了時に呼ばれる
  private static void OnAssemblyCompilationFinished(object obj, CompilerMessage[] messages) {
    Debug.Log(obj + "のコンパイル終了"); 

    //警告やエラー等のメッセージがあればログで表示
    foreach (CompilerMessage compilerMessage in messages) {
      Debug.Log(compilerMessage.type.ToString() + "\n" + compilerMessage.message); 
    }
  }

}

f:id:kan_kikuchi:20181110111425g:plain


なお上記のコードの通り、エラーや警告を検知する事も可能です。


f:id:kan_kikuchi:20181110111649j:plain


------------追記------------


CompilationPipelineを使って、

アセンブリごとのコンパイル時間を計測したり、閾値を越えたら警告を出したりするやつを作りました!


f:id:kan_kikuchi:20181127050927j:plain



------------追記おわり------------