Edited at
Unity #2Day 12

ライブラリコードをDLL化してコンパイル時間を減らそう!

More than 1 year has passed since last update.

これは Unity #2 Advent Calendar 2017 の12日目の記事です。

昨日は @orangesuzuki さんの Unityのアニメーションデータを外部プログラムで利用するはじめの一歩

@Kan_Kikuchi さんの 日本語から変数や関数名を生成するエディタ拡張 でした。

今日は @Takaaki_Ichijo さんの Unityでフレンドとアイテム交換とかする機能をサーバーレスで作る その1 です。あわせてご覧ください!


Unityで何かを作っていると使い回しのできる便利なコードが溜まってくると思います。

普段はAssetsの中に入れてあるだけだと思いますが、その状態だとある一つの問題が・・・。


コンパイル時間が延びる

Assetsに存在しているC#のコードはRefresh1の度にコンパイルされています。

何かを更新する度に変更していないはずのコードをコンパイルする時間。その時間は無駄だと断言できます。

もちろん、修正が度々入るような出来たてのコードなら必要であるかもしれません。

しかしドッグフーディングも終わってバグも取れたようなライブラリコードや

AssetStoreやGithubなどからダウンロードしてきたコードなどを毎回コンパイルするのはすごく勿体無い

(消極的な理由として、ダウンロードしてきたコードの警告を見たくないということもありますが)

その問題を解決するのがDLL化なのです!


DLL化する手順

主に以下のような手順で進めていきます。

Windows上で行うため、VisualStudioを例に出していますが

MacやLinuxなどであればXamarinStudioやMonoDevelopment、dotnetコマンドでも可能だと思います。


  1. VisualStudioなどでDLLプロジェクトを作成する。

  2. DLLプロジェクトファイルをUnity用に編集する

  3. DLLプロジェクトにライブラリコードを追加する。

  4. DLLプロジェクトをビルドする

  5. DLLをAssetsの中にコピーする

  6. UnityEditorをRefreshする


VisualStudioなどでDLLプロジェクトを作成する

VisualStudio上でプロジェクトを作成します。

この時、Class Library (.NET Core)を選ぶと新しいcsproj形式2になるためそれを選択してください。

(今回は便宜上ClassLibrary1.csprojという名前で作成しています)

image.png


DLLプロジェクトファイルをUnity用に編集する


  1. ソリューションエクスプローラ上のプロジェクトを右クリックしてEdit ClassLibrary1.csprojを選択します。

    image.png


  2. 開いたcsprojにある

    <TargetFramework>netcoreapp2.0</TargetFramework>
    

    となっている部分を

    <TargetFramework>net35</TargetFramework>
    

    に書き換えてください。

    (.NET Framework 4.6を使用する場合はnet46)



  3. 自動で作成されているClass1.csは必要ないので削除してください。



using UnityEngine;をしているコードを含む場合に必要な対応


  1. ソリューションエクスプローラ上のプロジェクト内にあるDependenciesを右クリックしてAdd Referenceを選択します。

    image.png


  2. Browseを選択して、以下の2つを参照に追加します。

    相対パスで設定されてしまうため、gitなどで管理する場合はレポジトリ内に配置するなどの対策が必要です。

    image.png


    • C:\Program Files\Unity\Editor\Data\Managed\UnityEngine.dll

    • c:\Program Files\Unity\Editor\Data\UnityExtensions\Unity\GUISystem\UnityEngine.UI.dll




DLLプロジェクトにライブラリコードを追加する

ソリューションエクスプローラ上のプロジェクトを右クリックしてOpen Folder in File Explorerを選ぶと


プロジェクトファイルのあるディレクトリがエクスプローラによって開かれます。

対象のcsファイルをこのディレクトリにコピーしてください。(Editor拡張の場合は後述)

新しいcsproj形式の場合は自動で読み込まれます。(古い形式の場合は別途手動でプロジェクトへ追加してください)


DLLプロジェクトをビルドする

Build - Build Solution を選択するとDLLがビルドされます。

エラーが出る場合などは適時修正してください。

image.png


DLLをAssetsの中にコピーする

ClassLibrary1.csprojのパス\bin\Debug\net35\にDLLが作成されているのでAssets内にコピーします。

毎回手動でコピーするのは面倒なのでCopyDllsAfterBuildを使って

ビルド時に自動でコピーされるようにする方法を紹介します。


CopyDllsAfterBuildを使用する



  1. ClassLibrary1.csprojのあるソリューションにConsole App (.NET Core)のプロジェクトを追加します。

    (今回は便宜上CopyDllsという名前で作成しました。)

    image.png

  2. DLLプロジェクトと同様にTargetFrameworknet35に変更します。

  3. 先と同様にAdd Referenceを選択し、ClassLibrary1を追加します。

    image.png


  4. CopyDlls.csprojDependenciesを右クリックしてManage Nuget Packagesを選択します。

    image.png

  5. CopyDllsAfterBuildを検索し、インストールします。

    image.png


  6. CopyDlls.csprojCopySettings.jsonという名前のファイルを作成し、以下のように記述します。

    {
    
    "destination": "UnityのAssetsまでのパス/DLLを配置するパス",
    "pattern": "*",
    "excludes": [ "UnityEngine", "UnityEditor", "CopyDlls" ]
    }


  7. 先と同様にビルドすると、ClassLibrary1.dllが所定に位置へコピーされているはずです。



エラーが発生した場合

もし以下のようなエラーが出た場合はPowerShellの実行に制限があるため、制限を解除します。

2>このシステムではスクリプトの実行が無効になっているため、ファイル C:\Users\ユーザー名\.nuget\packages\copydllsafterbuild\3.1.

2>2\tools\postbuild.ps1 を読み込むことができません。詳細については、「about_Execution_Policies」(https://go.microsoft.com/fwl
2>ink/?LinkID=135170) を参照してください。
2> + CategoryInfo : セキュリティ エラー: (: ) []、ParentContainsErrorRecordException
2> + FullyQualifiedErrorId : UnauthorizedAccess

コマンド プロンプト又はbatchファイルにて、以下のコマンドを実行します。

PowerShellの実行制限を解くことになるため、自己責任でお願いします

%WinDir%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -Command "Set-ExecutionPolicy RemoteSigned"

%WinDir%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "Set-ExecutionPolicy RemoteSigned"

Rebuild Solution すればエラーがない状態でコピーされているはずです。


UnityEditorをRefreshする

UnityEditorへ戻りRefreshされればこれまで通りライブラリコードが使用できます!


ライブラリコードをデバッグしたくなった場合

DLL化したライブラリコードをデバッグしたくなった場合、


Assetsの中にcsファイルを戻すことでも対応することはできますが、

UnitTestを作成しデバッグすることをおすすめします。


Editor拡張コードの場合

Editor拡張コードの場合は以下の点が異なります。



  • UnityEditor.dllへの参照が必要



    • C:\Program Files\Unity\Editor\Data\Managed\UnityEditor.dllを参照に追加してください



  • Editorディレクトリに配置することが必要(不要かも?要検証)


    • Editor用のCopyDllsを作成し、Editorディレクトリ内へコピーするよう設定します




VisualStudio 15.5 以降の場合

unsafeを含んだコードをDLL化した場合、UnityEditorが落ちるという現象を確認しています。

(unsafeコードのコンパイル結果が変わったため?)

その場合はDLLプロジェクト(ClassLibrary1.csproj)にNugetで

Microsoft.Net.Compilers2.4.0を入れることで解消できます。

(コンパイラを古いものに戻す対応)

詳しくは @ufcpp さんのブログを読んでみてください。

- 未確認飛行 ビルドで使う C# コンパイラーを差し替える


最後に

これにより、コンパイル時間が短くなっていると同時に、

DLLファイルにまとまったお陰でライブラリを他のプロジェクトへ共有しやすくなっていると思います!

ぜひお試しください!

明日は @kido0617 さんの フリーのビジュアルノベルアセットFungusを使ってRPGのイベントを作る

@keidroid さんの ScriptableObjectをマスターデータとして扱うあれこれ です。





  1. 規定ではEditorウィンドウがアクティブになったタイミング 



  2. ごちゃごちゃとした設定がなくなっているだけでなく、ディレクトリ内のcsファイルを自動で検索してくれるなどすごく便利になっています。