パッケージにdllを同梱する
FaceEmo1.4.2をUnity2022のプロジェクトにインストールしたときのエラー
Processing assembly Library/Bee/artifacts/1900b0aEDbg.dag/jp.suzuryg.face-emo.external.mathijs-bakker.extenject.Runtime.dll, with 119 defines and 217 references
processors: Unity.Jobs.CodeGen.JobsILPostProcessor, zzzUnity.Burst.CodeGen.BurstILPostProcessor
running Unity.Jobs.CodeGen.JobsILPostProcessor
Unity.Jobs.CodeGen.JobsILPostProcessor: ILPostProcessor has thrown an exception: Mono.Cecil.ResolutionException: Failed to resolve Zenject.IPoolable`1<Zenject.IMemoryPool>
at Unity.Jobs.CodeGen.TypeReferenceExtensions.CheckedResolve(TypeReference typeReference)
at Unity.Jobs.CodeGen.JobsILPostProcessor.VisitJobStructs(TypeReference t, ILProcessor processor, MethodBody body)
at Unity.Jobs.CodeGen.JobsILPostProcessor.PostProcessImpl()
at Unity.Jobs.CodeGen.JobsILPostProcessor.Process(ICompiledAssembly compiledAssembly)
at Unity.ILPP.Runner.PostProcessingPipeline.PostProcessAssemblyAsync(PostProcessAssemblyRequest request, Action`2 progressSink)
PostProcessing failed: Mono.Cecil.ResolutionException: Failed to resolve Zenject.IPoolable`1<Zenject.IMemoryPool>
at Unity.Jobs.CodeGen.TypeReferenceExtensions.CheckedResolve(TypeReference typeReference)
at Unity.Jobs.CodeGen.JobsILPostProcessor.VisitJobStructs(TypeReference t, ILProcessor processor, MethodBody body)
at Unity.Jobs.CodeGen.JobsILPostProcessor.PostProcessImpl()
at Unity.Jobs.CodeGen.JobsILPostProcessor.Process(ICompiledAssembly compiledAssembly)
at Unity.ILPP.Runner.PostProcessingPipeline.PostProcessAssemblyAsync(PostProcessAssemblyRequest request, Action`2 progressSink)
at Unity.ILPP.Runner.PostProcessingService.PostProcessAssembly(PostProcessAssemblyRequest request, IServerStreamWriter`1 responseStream, ServerCallContext context)
Unhandled Exception: System.InvalidOperationException: Post processing failed
at Unity.ILPP.Trigger.TriggerApp.<ProcessArgumentsAsync>d__1.MoveNext() + 0xf74
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
at Unity.ILPP.Trigger.TriggerApp.<ProcessArgumentsAsync>d__1.MoveNext() + 0x1149
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb6
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x42
at Unity.ILPP.Trigger.TriggerApp.<RunAsync>d__0.MoveNext() + 0xc7
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb6
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x42
at Program.<<Main>$>d__0.MoveNext() + 0x1a3
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() + 0x20
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task) + 0xb6
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task) + 0x42
at Program.<Main>(String[]) + 0x20
at Unity.ILPP.Trigger!<BaseAddress>+0x47849b
普通にDLLを参照できていない?
Assembly 'Library/ScriptAssemblies/jp.suzuryg.face-emo.usecase.Editor.Tests.dll' will not be loaded due to errors:
Unable to resolve reference 'jp.suzuryg.face-emo.external.mathijs-bakker.extenject.Runtime'. Is the assembly missing or incompatible with the current platform?
Reference validation can be disabled in the Plugin Inspector.
Assembly 'Library/ScriptAssemblies/jp.suzuryg.face-emo.appmain.Editor.dll' will not be loaded due to errors:
Unable to resolve reference 'jp.suzuryg.face-emo.external.mathijs-bakker.extenject.Runtime'. Is the assembly missing or incompatible with the current platform?
Reference validation can be disabled in the Plugin Inspector.
Failed to find entry-points:
System.Exception: Unexpected exception while collecting types in assembly jp.suzuryg.face-emo.usecase.Editor.Tests, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null ---> Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'jp.suzuryg.face-emo.external.mathijs-bakker.extenject.Runtime, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' ---> System.Exception: Failed to resolve assembly 'jp.suzuryg.face-emo.external.mathijs-bakker.extenject.Runtime, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' in directories: C:\Program Files\Unity\Hub\Editor\2022.3.6f1\Editor\Data\MonoBleedingEdge\lib\mono\unityjit-win32
Zenject-usage.dllのターゲットは.NET 3.5
.NET 3.5はUnity2018.3の時点で非推奨になっており、Unity2019.2からは対象外になっている
Unity2019.4で動いてたけど…
Unity2022ではさすがに動かなくなった?
コンパイル周りの処理が変更されたのが原因だった(UnityかVRCSDKのどちらか)
VRCSDKのdependenciesに3.5のアセンブリがわりとある…
.NET Framework 4.xは.NET Standard2.0に準拠しているが、2.1には準拠していない
2.0のAPIはすべて2.1に含まれている
Unity2022のAPI Compatibility Levelはデフォルトで.NET Frameworkになっている
.NET Standard2.0のdllが安全?
.NET Standard : NET Foundation が公開する .NET Standard 2.1
Microsoft が公開する .NET Framework 4.8 と、.NET Standard 2.1 の追加 API
Unity2022の .NET Framework互換実装は、.NET Standard 2.1の追加APIをすべて含んでいる
じゃあ2.1のパッケージがあったら462のパッケージを引っ張ってくる意味ないんじゃ…
.NET Standard2.0以降の.NET実装は、2.0のAPIをすべて含んでいるはず
2.1のアセンブリがインスペクタで"Targets .NET 4.x"と表示されるのはなぜ?
なんでだろう…
asmdefと同様にAuto Referenceは切っておく
Validate ReferencesはONでいい?
厳密な名前の参照で引っかかる?
Validate references の 実装をながめてて気づいたのですが、アセンブリが同じフォルダ内にある場合のみバージョンのチェックが無視されるみたいです。つまり、バージョンが完全一致しないアセンブリは、同じフォルダに置くか、Project Settings -> Player -> Other Settings -> Assembly Version Validationのチェックを外すのどちらかをしないといけないみたい。
マネージドプラグインは一つのディレクトリにまとめておくと無難。もしくはプロジェクトの設定でアセンブリのバージョンチェックを行わないようにするか。
dllが同名のケース?
NugetのPackagesをコピーしても同名エラーが出ない?
バージョンが同じだから?
R3 1.0.0と1.1.13を同時に入れてasmdefから参照してみたが、特にエラーは出ない
Assets/Packages外にR3のアセンブリが存在するとき、Nuget上でR3が未インストール状態でも、R3のインストールができなくなる
R3.dllのファイル名を変更するとインストールできるようになる
このことから、少なくともNugetForUnityはファイル名でdllを探索している
内部のアセンブリ名が同一のものが存在していても問題ない?
どちらも参照されているからmultipleのエラーが出る?
エラーではなく警告のケース?
4) Version Controlの形式を真似て自分のアセット専用の衝突しない Newtonsoft.Json を同梱する
手間の事を考慮しないのであれば3よりは4推奨。
- 多少手間がかかるものの一番後の事を考えなくても済む形。
- 無駄なファイルが増える。dllの場合のサイズが1MB未満。エディタ専用ならかなり有り?
「衝突しない」とは?
4の手抜き版、今後のアップデートでいつ消えても不思議ではない。
- 過去や未来のバージョンまでは調べていませんが少なくとも 2.0.4 だと名前空間もdllも衝突しない形式でNewtonsoft.Jsonが使用できます。
- 名前空間:Unity.Plastic.Newtonsoft.Json
- パス:com.unity.collab-proxy@2.0.4/Lib/Editor/PlasticSCM/Unity.Plastic.Newtonsoft.Json.dll
dllが単一であれば名前を変えればいいが、複数あって互いに依存している場合はそうもいかない
内部のアセンブリ名が不変ならいい?
このケースは名前空間も変わってるので、アセンブリ名も変更してビルドしてそう
asmdefから依存dllが見えていればよさそう?
dllの名前を変更して、asmdefのreferenceに追加するととりあえずコンパイルエラーは出ない
名前変更の有無に関わらず、auto referenceをfalseにした状態でasmdefのreferenceから外すとエラーが出る
asmdefで参照を追加していると、名前を変更していてもRiderで依存関係が正しく表示されるようになる?
asmdefに追加していない場合は「?」マーク表示だった
TimeProviderを消すとR3.dllのロードでエラー
他のスクリプトからR3を参照していない状態でもエラーが出る
名前の変更ではエラーにならない
Annotationを消してもエラーが出ない
standard環境でNugetを使用すると落ちてくるが、結局不要ということ?
UnSafeを消すとエラー
Powershellで下記を実行するとアセンブリ名が分かる
code: powershell
# DLLのパスを指定
$dllPath = "C:\path\to\your.dll"
# アセンブリをロード
# アセンブリ名を表示
$assembly.GetName().Name
ファイル名を変更してもアセンブリ名は変わらない
あー、UnityのManaged PluginのAssembly参照の限定方法完全に理解した。
Auto Reference をオンにしている限りはあまり旨みがないということだ。
R3のdllと依存dllをすべてdependencies GUIで確認したところ、互いに依存していなかった
asmdefの依存に入れておけば名前を変更してもOK?
その場合、NuGetでR3の依存にそれらのパッケージが含まれていたのはなぜ?
Riderで見ると依存先が分かる
dependencies GUIとは異なり、きちんとTimeProvider等に依存していることが確認できた
名前の変更不可?
NugetForUnityのターゲットフレームワーク関連の話
net462のMicrosoft.Extensions.TimeProvider.Testingを入れると付随してBcl.AsyncInterfacesがくっついてくるが、こいつがUnity側の.NET Standardの定義とぶつかって死ぬ。
てかどのみちNuGetForUnity.CliがTargetFramework指定に対応してないからそもそも上手く動かねぇじゃん、ってことに気づいた。つまり現時点ではMicrosoft.Extensions.TimeProvider.Testingは手でdll引っこ抜いて突っ込むのが正解かもしれない。
NuGetForUnityのtargetFrameworkはまだ今は使えない。理由はNuGetForUnity.Cli側が対応していないため、CI時などに困ったことになるから。
で、NuGetForUnityのtargetFrameworkが使えない以上、Microsoft.Extensions.TimeProvider.Testingの導入はNuGetForUnityからはできない。
TimeProvider.TestingがNuGetForUnityから導入できない理由
【UnityのApiCompatibilityLevelが「.NET Standard」のとき】
→ TimeProvider.Testingに「.NETStandarad」の定義が無いためNugetForUnityでは解決できず導入に失敗する。
【ApiCompatibilityLevelが「.NET Framework」のとき】
→ TimeProvider.Testingがnet462版で解決できる。ただその場合は依存するMicrosoft.Bcl.AsyncInterfacesもnet462版が必要になる。そしてAsyncInterfaces内の定義はUnity側提供のmscorlib内に同じ定義のインタフェースが存在するため衝突する。
じゃあどうすればいいかというと、ApiCompatibilityLevelを「.NET Standard」に設定した上で、TimeProvider.Testingだけnet462版をNuGetを介さずに手動で突っ込む、が解かもしれない。
てかこの問題、「ApiCompatibilityLevel が .NET Frameworkのときに、Microsoft.Bcl.AsyncInterfacesを導入した状態でIAsyncDisposableなどを触ろうとする」と発生するんだから、単に「.NET Framework設定の状態でR3を導入する」だけで発生しうるのでは…?
これよくよく考えるとTimeProvider.Testingが悪いんじゃなくて、「.NET Framework」の時にAsyncInterfacesを解決しようとすると起きますね。なのでR3単体でも発生しました。(NugetForUnityを経由せずに手動でdllを入れれば回避はできそう)
たぶんこの件をまとめた記事
2024/6/13 追記
NuGetForUnity v4.1.1でUnityのAPI Compatibility Levelの設定に依らず.NET Standard 2.x側のパッケージが優先されるオプション(デフォルトON)が追加されました。そのためこちらの問題は発生しづらくなりました。
たしかに、.NET Frameworkの設定なのにStandardのdllばかり導入されていた
Standardにすると導入されるパッケージが1つ増える
逆に2.1の方が依存が少ない?
Unity2022でAPIを.NET FrameworkからStandard 2.1に変えたらUniTask(unitypackage版)でエラーが出た
Assets\Plugins\UniTask\Runtime\Linq\Create.cs(131,22): error CS7069: Reference to type 'IValueTaskSource' claims it is defined in 'mscorlib', but it could not be found
スクリプトでもダメなことあるんだ…
VRCSDKのUnsafeが競合する
Processing assembly Library/Bee/artifacts/1900b0aEDbg.dag/jp.suzuryg.face-emo.ext.r3.unity.dll, with 120 defines and 226 references
processors: Unity.Jobs.CodeGen.JobsILPostProcessor, zzzUnity.Burst.CodeGen.BurstILPostProcessor
running Unity.Jobs.CodeGen.JobsILPostProcessor
Unity.Jobs.CodeGen.JobsILPostProcessor: ILPostProcessor has thrown an exception: Mono.Cecil.ResolutionException: Failed to resolve R3.Collections.FreeListCore1<R3.IFrameRunnerWorkItem>
RiderでR3.dllがVRCSDKのUnsafeを参照していることを確認
.net standardではなく、.net frameworkの実装になっている?
VRCSDKを削除すると、正常にビルドされることを確認
asmdefはOverride Referencesをtrueにしているが、それでもマネージドプラグインの参照には干渉するのか?
同じ階層のdllが優先されるのではないのか ?
この調子だと予期しない競合も頻繁に発生しそう
いまVRCSDKないプロジェクトにACaaCの開発環境移して知ったんだけど、System.Runtime.CompilerServices.Unsafe.dllってVRCSDKが連れてきてたのか。
エラーはいててなんでだってなってた
謎のコンパイルエラーに悩まされること3時間、ようやくアップロードできた……
結論を共有すると、UnityのPackegeManagerの中にあるBurstはVRCSDKと相性が悪いです
たまにburst前提のUnityアセットがいますが、同じプロジェクトにいると駄目みたいですね……気を付けてください
もう少し補足します
burstの中にunsafe.dllというファイルがあるのですが、VRCSDKのなかにもunsafe.dllがあり競合します
パッケージマネージャから消すのが、解決方法です。
エクスプローラーからやると、burstが依存している他のパッケージがあると、こっそり復元してくる仕様っぽいので注意です
Magica Clothの導入でJobsのインストールをしてるんだけど、CollectionsとVRCSDKのSystem.Runtime.CompilerServices.Unsafe.dllの依存関係が解決できない。
導入しているバージョンの問題なんかな。
ううーん?Magica Clothに必要なUnity.CollectionsとVRCSDKに重複する型Unsafeがあって利用できないっぽい……。やはりDynamicBoneなのか、でも夏時間が終わったらPhysicsBoneがくるって言うし揺れものは無しでやるか。
VRCSDKのUnsafeを消しても問題が解消しない
asmdefのOverride Referencesをfalseにして、NugetでR3を入れるとビルドが通る
名前を変更したdllは参照してくれない
dllのAuto Referenceをtrueにしてもダメ
trueにすると参照はされるけど、VRCSDKと競合する
VRCSDKのpackages.json以外をすべて削除しても問題が解消しない
VRCSDKのdependenciesからcom.unity.collectionsを削除すると問題が解消された
Mono Cecilを使用したコンパイルが有効になっているとエラーが発生する?
おそらくdllのファイル名と、dll内部の名前が一致してないとコケる
Zenject-usage.dllで発生していた同様の問題について、dllのファイル名を変更したところ解消されたのでほぼ確定
Unityはファイル名でしかdllを区別できないのにファイル名変更できないのは嫌だな…
なんのためのmetaファイル?
asmdefはguidで参照できるのに…
こんな仕様にしてるから競合が頻繁に発生するのでは…?
マネージドプラグインを同梱してるパッケージとか結構あるし…
dllのファイル名が同一である場合、NugetForUnity上ではインストール済みとみなされる
AutoReferenceをfalseにしていると、インストールできないのに使用できないという状況になる
asmdefでoverride referenceしてやればいいんだけど
Assembly-CSharpで使ってる人は詰む
勘違い。普通にNugetでインストールできた
nugetでインストール済みになる条件は?
ただし、nugetのdllと同梱dllを区別できない問題は相変わらず存在する
同梱dllが優先的に参照されてしまうとマズい
override referenceを使用しないなら、auto referenceがtrueのdllが優先されそうだが…
R3のソースそのまま突っ込む?
他の依存dllは名前を変更してもビルドが通ってる
たぶんMono.Cecilでコレクションクラスに対するなにかをやっていて、R3のコレクションクラスを参照できないためにコケている
つまりコレクションに関係しないアセンブリは名前を変更してもいい?
R3のコアってUnityでコンパイルできるのか…?
アセンブリ名を"r4.dll"に変更しても解消しない
名前の長さが原因ではない
r3.dllにすると解消される
Cecilは大文字と小文字を区別しない?
asmdefでoverride referenceするときは大文字と小文字が区別されるため、アリといえばアリ
r3.dllとR3.dllは別々に扱われる
ただし、参照の際も別々に扱われているかは不明
むしろcecilが区別しない以上、他にも区別しないケースがありそうで怖い
こちらのAnnotationsが含まれていないため、Unityではおそらく不要
Nugetで導入した場合はUnity以外の環境も考慮される
AnnotationsはDataAnnotationsを参照しており、DataAnnotationsの格納先にはAnnotationsも含まれていた
NugetでAnnotationsが導入されるとき、DataAnnotationsが導入されないのはなぜ?
念のためにAnnotationsとDataAnnotationsを同梱しておいてもいいか?
たぶんStandardのAPIには含まれていない
.NETのリポジトリにStandardのビルド構成が含まれてなかった…
Dead end System.ComponentModel.Annotations package (#51891)
System.ComponentModel.Annotationsの機能がランタイム内に含まれるようになり、パッケージが作られなくなった
.NET6の時点でNugetパッケージは追加されていない
上記のコミットは.NET6のリリース以前なので、この時点でStandardは対象になっていない
ひとまずR3.dllのみアセンブリ名を変更してビルド
R3.dllの依存ライブラリはアセンブリ名を変更していないが、今のところ不具合は出ていない
考えられるリスク
他のパッケージに同梱されているdllが参照されてしまう
バージョンをチェックしているなら大丈夫?
お勧めするアセンブリの参照方法は、アセンブリ名、バージョン、カルチャ、および公開キー トークン (存在する場合) を含む完全参照を使用することです。
他のパッケージに同梱されているdllとアセンブリ名が重複することにより不具合が発生する
Auto Referenceがfalseなら基本的に参照されないので大丈夫?
R3.dllと同様に、コンパイル時にファイル名とアセンブリ名の不整合により不具合が発生する
今後Cecil関連の不具合が発生したときは、ひとまずアセンブリの名前を変更したパッチバージョンを出してから根本的な修正に取り掛かる
dotnet/runtimeはGithubActionsでビルドできないっぽい?
ライブラリのビルド
課題
別のパッケージを作るときに、この作業を毎回やるのは面倒
自分のパッケージで競合を起こさないように管理できるなら名前を共通にしてもいい
同名のdllがプロジェクト内にある場合、Nugetでパッケージをインストールできなくなる
dllの名前を変えるとインストールできるようになる
アセンブリ名は見ていない
Packages以下に配置していない場合、Installed一覧に出てこなくなる