【Unity】asmdef(Assembly Definition)について調べたことまとめ

asmdef(Assembly Definition)を使うプロジェクトに当たったので、どういうものなのか調べたことをまとめた。



【この記事を書いたときの環境】
・ Unity 2019.4.31f1 Personal (Windows64bit)

asmdef とは何なのか

Unityでは、c#で書いたスクリプトはコンパイルされるとdllファイルにまとめられる。

作られたdllは、プロジェクトフォルダ\Library\ScriptAssemblies に作られる。
そして、通常、何もしていない場合は Assembly-CSharp.dll にまとめられています。


自分の作ったスクリプトがどのdllになるのかは、インスペクターでスクリプトを選択したときにもわかります。


最初に言ったように通常は Assembly-CSharp.dll にまとめられるが、
Assembly-CSharp.dllとは別のdllに分けたい場合、asmdefファイルを作るとdllを分けることができる。

そもそもなぜdllを分けたくなるのだろう?

配布するようなライブラリを作る場合は必須

理由はこちらの記事が非常にわかりやすい。 qiita.com

自分が使っているライブラリでもいくつかasmdefファイルが用意されていないものがありコンパイルエラーとなった。
そういう場合は、自分でasmdefを追加してあげる必要がある。

コンパイル時間の短縮になる?

理論上、dllを分けることで再コンパイルするスクリプトの量が少なくなるからコンパイル時間は短くなる。
が、あまり恩恵を感じれていないという声もあるし、自分もまだ感じれていない。
コンパイルが遅すぎて悩んでいるprjには適応してみる価値があると思う。

個人的にはコンパイルよりもビルド時間を短縮につながらないか?というところが気になるので後日試してみたいと思う。

asmdefファイルの作り方、設定の内容

どのゲームでも使える処理を「game_common」というフォルダ(サブリポジトリ)にまとめているので、
今回はこのフォルダ配下のスクリプトをAssembly-CSharp.dllとは別のdllにしてみたいと思う。

配置場所

asmdefファイルは配置したフォルダと同階層+その配下のフォルダにあるスクリプトに適応される。

フォルダA
 ∟フォルダAA
  ∟スクリプトAA.cs
 ∟asmdefファイル ←ここに作ったらスクリプトA,AAに適応される
 ∟スクリプトA.cs
フォルダB

どこにおいても言い訳ではないので注意!

作り方

asmdefファイルは以下の手順で作ることができる。

プロジェクトビューで右クリック -> Create -> Assembly Definition

インスペクタに表示されているasmdefファイル内の Name に設定した名前がdllの名前となるため、
asmdefファイル自体の名前と必ずしも合わせる必要はない模様。

ちなみにフォルダ階層をまたぐ場合(例:GameCommon/Debug を対象にしたい場合)、
GameCommon.Debug のように . で区切った名前にするのが多いみたいだ。

ここまででコンパイルが通っていれば、GameCommon.dll が プロジェクトフォルダ\Library\ScriptAssemblies に作られている。 さらに Assembly-CSharp.dll のサイズもかなり減った。

設定内容

General - Auto Referenced

Assembly-CSharp.dll に含まれるスクリプトから参照される場合はチェックをいれる。
テストコードやエディタスクリプトなら、チェックが外れるはずだ。

Define Constraints

ここに定義した文字列が PlayerSettings -> Scripting Define Symbols に定義されている場合にdllが作られる。
開発中のデバッグビルドでは「DEBUG_BUILD」というシンボルを定義する運用にしているので、 デバッグビルドでしか使わない(FPSの表示とか)スクリプトで使用してみた。

ちなみにScripting Define Symbols に定義されていない時は、上記のように赤く!マークがつくみたい。

本当にシンボル定義によってdllが作られるのかどうか確認するには、
先に挙げた通り、プロジェクトフォルダ\Library\ScriptAssemblies にdllが作られるので、
シンボル定義を消した時にdllが作られていないことをこのフォルダで確認すればよい。

Assembly Definition References

asmdef作成後に、このような参照エラー↓がでた場合、そのスクリプトは別のdllにあるスクリプトを参照(依存)しています。

The type or namespace name 'TextMeshProUGUI' could not be found (are you missing a using directive or an assembly reference?)

例えば上記のエラーの場合、TextMeshProのdllを参照しなければならないことがわかる。
参照できるようにする設定が、「Assembly Definition References」である。

Platform

この項目はdllを作成する特定のプラットフォームを指定できる項目。

注意点

Editor等の特殊フォルダーの効果がなくなる

通常 Editor という名前のフォルダを作ると、そのフォルダ配下にあるスクリプトはエディタでしかコンパイルされなくなる。
しかし、asmdef ファイルを置いたフォルダの配下に Editor フォルダがある場合、
asmdefの設定によってコンパイルされるかが決まるため、上述した Platform で Any Platform を選んでいると、android等のビルド時でもコンパイルに含めようとしてしまい、ビルドエラーとなる。

▼コンパイルエラーとなる例
Editorフォルダ配下にあるBuildProcesser をエディタ以外のプラットフォームでもコンパイルしようとしてしまう

こういう時はEditor フォルダにエディタスクリプト用のasmdef を作り、Platformを Editor のみにすればよい。

けっこうキャッシュがバグる

asmdef の設定をしているとそこそこの頻度でキャッシュが古いままになってしまうことがあり、
適切な設定をしたにも関わらずコンパイルエラーが消えない、という事象が発生した。

こういう場合は、
プロジェクトフォルダ\Library\ScriptAssemblies をフォルダごと消して、Unityエディタを再起動することで再コンパイルしてくれる。