csc で Unity 用 DLL を作る
表題の通り、csc
で DLL を作成するにあたって調べた内容を備忘録として残します。
以前書いた記事の続編的な内容です。
検証した環境は次の通りです。
はじまりはじまり
事の起こりは、mcs
による DLL 作成時に下記のエラーが起きたことです。
error CS1644: Feature `default literal' cannot be used because it is not part of the C# 7.0 language specification
原因になったのは次のような書き方です。
public void Hoge(Vector3 position = default)
原因はエラーで指摘されているように、default
リテラルが C# 7.1 以降でないと利用できないことです。
どうやら、mcs
はデフォルトだと C# 7.0 以前のものを利用しているようです。
エラーの解消
この現象の解決策は二つあります。 一つは型推論に頼らず、スクリプトで型を記述することです。
public void Hoge(Vector3 position = default(Vector3))
もう一つは、mcs
実行時に言語バージョンをオプションで指定することです。
csc への乗り換え
前記事で検証したとおり、Unity 2018 ではコンパイラとして csc
が利用されています。
せっかく DLL 作成コマンドを修正するのであれば、そのまま Unity と挙動を合わせたいと考えました。
まず、Unity 内部で利用されている csc
は次のものです。(ファイルをリネームするとエラーになります)
/Applications/Unity/Hub/Editor/2018.4.9f1/Unity.app/Contents/Tools/Roslyn/csc
試しに現在使っている mcs
と入れ替えると、次のエラーが大量に発生します。
error CS0518: 定義済みの型 'System.Void' は定義、またはインポートされていません error CS0518: 定義済みの型 'System.ValueType' は定義、またはインポートされていません error CS0518: 定義済みの型 'System.Object' は定義、またはインポートされていません
Visual Studio のオプションを流用
対処としては、必要な DLL を参照するオプションをつける必要があります。 具体的な内容は、前回の記事で Visual Studio を用いて DLL を作成した際の処理を参考にします。
- mscorlib.dll
- System.dll
- SystemCore.dll
これら三つを参照することで先ほどのエラーは起きなくなります。
その他の気になるオプション
そのほかの参照に関連するオプションとして次のものがあります。
結論から言うと、今回の検証の中ではこれらがあってもなくても挙動は変わりませんでした。
まず、noconfig
は csc.rsp
という参照を記述するファイルの設定を無視するものです。
ただし、利用している csc
と同じディレクトリには同ファイルは存在していませんでした。
nostdlib+
は mscorlib
を参照しなくなるオプションです。
Visual Studiio の例では mscorlib
を明示的に指定しているため、いずれにせよ参照は必要だと思われます。
今回の場合、意図せぬ参照が発生するよりは必要最低限に絞った方が良いと判断し、これらも付与したコマンドにしていきました。
参照するべき DLL の見極め
Unity 内部で System.dll
を検索すると、複数のファイルが存在します。
./Tools/Roslyn/System.dll ./NetStandard/compat/2.0.0/shims/netfx/System.dll ./MonoBleedingEdge/lib/mono/4.5.2-api/System.dll ./MonoBleedingEdge/lib/mono/unity/System.dll ./MonoBleedingEdge/lib/mono/4.7.1-api/System.dll ./MonoBleedingEdge/lib/mono/4.5.1-api/System.dll ./MonoBleedingEdge/lib/mono/4.5-api/System.dll ./MonoBleedingEdge/lib/mono/4.6.2-api/System.dll ./MonoBleedingEdge/lib/mono/2.0-api/System.dll ./MonoBleedingEdge/lib/mono/4.6-api/System.dll ./MonoBleedingEdge/lib/mono/4.6.1-api/System.dll ./MonoBleedingEdge/lib/mono/4.5/System.dll ./MonoBleedingEdge/lib/mono/4.0-api/System.dll ./MonoBleedingEdge/lib/mono/unityjit/System.dll ./MonoBleedingEdge/lib/mono/unity_web/System.dll ./MonoBleedingEdge/lib/mono/unityaot/System.dll ./Mono/lib/mono/unity/System.dll ./Mono/lib/mono/2.0/System.dll ./Mono/lib/mono/unity_web/System.dll
いくつかそれっぽい DLL で検証したところ、次のような結果となりました。
DLL | 成否 | メモ |
---|---|---|
./MonoBleedingEdge/lib/mono/4.7.1-api/System.dll | 成功 | Visual Studio が使っていたものに近いバージョン |
./Tools/Roslyn/System.dll | 失敗 | System 関連でエラーのまま |
./MonoBleedingEdge/lib/mono/unity/System.dll | 失敗 | Task 関連のエラー、C# 7.0 未満? |
Roslyn のものなら上手くいくのではと思っていたので、ここは少し予想外でした。 ただし、上手くいったファイルと比べてみると Roslyn のものはファイルサイズがかなり小さいです。(結果は一部割愛です)
$ ls -a /Applications/Unity/Hub/Editor/2018.4.9f1/Unity.app/Contents/MonoBleedingEdge/lib/mono/4.7.1-api/System.dll admin 500224 $ ls /Applications/Unity/Hub/Editor/2018.4.9f1/Unity.app/Contents/Tools/Roslyn/System.dll admin 41472
どちらのファイルも、リネームして参照できない状態にすると Unity でエラーが発生します。 また、Roslyn の System.dll をリネームする(参照できない状態にする)と、4.7.1-api/System.dll を使おうとした時でもエラーが発生します。
このことから、標準的な System
の実装は 4.7.1-api/System.dll に定義されており、Roslyn 用の実装が Roslyn/System.dll に定義されていると推測されます。
(これらを示すドキュメントを確認できた訳ではないので、あくまで推測です)
結論
ここまでの検証結果を考慮し、次のようなコマンドを用意しました。
Mono := $(UnityDirectory)/Contents/MonoBleedingEdge/lib/mono/4.7.1-api Csc := $(UnityDirectory)/Contents/Tools/Roslyn/csc LangVersion := 7.3 make_dll: $(Csc) \ -r:$(UnityDirectory)/Contents/Managed/UnityEngine.dll \ -r:$(Mono)/mscorlib.dll \ -r:$(Mono)/System.Core.dll \ -r:$(Mono)/System.dll \ -noconfig \ -nostdlib+ \ -target:library \ -recurse:'Assets/Scripts/*.cs' \ -out:AROW.dll \ -langversion:$(LangVersion)
このコマンドで DLL を作成できること、普段行っているテストに関して不備がないこと、は一通り確認できました。 もし何か不備が見つかれば対応と合わせて追記します。
ポエム
Unity で行われているコンパイル部分が公開されればありがたいなと思いつつ、一般的に Unity で扱うアセットは Asset Store かオープンソースでの公開が主流な印象があるため、DLL 作成はそこまで強く想定されていないのかなと感じた年末です。