AssetCompiler error on multi-project configuration
Release Type: Official Release/GitHub (please choose appropriate option)
Version: Version number and/or git branch 4.2.0.2122
Platform(s): Does the problem occur on Windows, Android...? Windows/WPF
Describe the bug
I have created a pretty simple solution that contains 2 projects. The main game project and a WPF project. I based both of these off of the examples provided and
.
On a fresh repo pull when compiling the solution for x64 only I get the following error message
I then modify the csproj files to compile under AnyCPU everything works. After this I can then switch the projects back to x64 and compile/run with no issues including after full clears of the bin/obj folders.
There was some discussion of this on the Discord starting
To Reproduce Steps to reproduce the behavior:
- Open the repo in this zip file TowerNxt-master.zip
- Build the solution to see the error above
- Change the projects/solution to compile under AnyCPU. I did this by adding the AnyCPU config to the solution, modifying the csproj directly to be <Platforms>x64;AnyCPU</Platforms>, correcting the configs, then removing the <Platforms> tags all together so it only has AnyCPU
- Build and find no issues
- Switch projects/solution back to x64. I did this by manually adding <Platforms>x64</Platforms> to the csproj file
- Build
Expected behavior I would have expected the solution to compile under x64 configuration
Screenshots See above
Log and callstacks Not possible
Additional context Can discuss with Simba (@Doprez) and Vašo on discord for additional information.
Thank you.
Seems like if I add another intermediate project I get a different error.
My project I'm working on is pretty big and is actually used with several different front-end solutions. So I created another intermediate project to hold the WPF components to be consumed.
In this example the TowerNxt.WPF consumes the Aries3D.WPF project which intern consumes the Aries3D.Core project. In the provided solution attached to this message all projects are set to compile as AnyCPU.
The DifferentFolders is how I would want the solution to be organized. But I also attached it where the entire solution is in a single folder to simplify the problem
TowerNxt-DifferentFolders.zip TowerNxt-SingleFolderAnyCPU.zip
Thanks
When looking at the build output I actually saw this stack trace for the second issue
info 0.006s: [AssetCompiler] Starting builder.
3> EXEC : error 6.521s: [AssetCompiler] Unhandled exception. Exception: TypeInitializationException: The type initializer for 'Stride.Core.Assets.AssetCloner' threw an exception.
3> ---> TypeInitializationException: The type initializer for 'Stride.Core.Serialization.SerializerSelector' threw an exception.
3> ---> TypeInitializationException: The type initializer for '<Module>' threw an exception.
3> ---> FileNotFoundException: Could not load file or assembly 'PresentationFramework, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified.
3> at System.ModuleHandle.ResolveType(QCallModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
3> at System.ModuleHandle.ResolveTypeHandle(Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
3> at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
3> at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(MetadataToken caCtorToken, MetadataImport& scope, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder1& derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctorWithParameters, Boolean& isVarArg) 3> at System.Reflection.CustomAttribute.AddCustomAttributes(ListBuilder1& attributes, RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder1 derivedAttributes) 3> at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType) 3> at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType, Boolean inherit) 3> at System.Attribute.GetCustomAttribute(Assembly element, Type attributeType, Boolean inherit) 3> at System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T](Assembly element) 3> at System.Resources.ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(Assembly a, UltimateResourceFallbackLocation& fallbackLocation) 3> at System.Resources.ResourceManager.CommonAssemblyInit() 3> at GNU.Gettext.GettextResourceManager..ctor(String baseName, Assembly assembly) 3> at Stride.Core.Translation.Providers.GettextTranslationProvider..ctor(String baseName, Assembly assembly) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core.Translation\Providers\GettextTranslationProvider.cs:line 34 3> at Stride.Core.Translation.Providers.GettextTranslationProvider..ctor(Assembly assembly) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core.Translation\Providers\GettextTranslationProvider.cs:line 25 3> at Stride.Core.Translation.Providers.GettextTranslationProvider..ctor() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core.Translation\Providers\GettextTranslationProvider.cs:line 19 3> at Stride.Core.Presentation.Module.Initialize() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\presentation\Stride.Core.Presentation.Wpf\Module.cs:line 17 3> at .cctor() 3> at System.RuntimeTypeHandle.GetActivationInfo(ObjectHandleOnStack pRuntimeType, * ppfnAllocator, Void** pvAllocatorFirstArg, * ppfnCtor, BOOL* pfCtorIsPublic) 3> at System.RuntimeType.ActivatorCache..ctor(RuntimeType rt) 3> at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions) 3> at Stride.Core.Serialization.SerializerSelector.UpdateDataSerializers() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core\Serialization\SerializerSelector.cs:line 271 3> at Stride.Core.Serialization.SerializerSelector.Initialize() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core\Serialization\SerializerSelector.cs:line 101 3> at Stride.Core.Serialization.SerializerSelector..cctor() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core\Serialization\SerializerSelector.cs:line 45 3> at Stride.Core.Serialization.SerializerSelector..ctor(Boolean reuseReferences, Boolean externalIdentifiableAsGuid, String[] profiles) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core\Serialization\SerializerSelector.cs:line 17 3> at Stride.Core.Assets.AssetCloner..cctor() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\AssetCloner.cs:line 38 3> at Stride.Core.Assets.AssetItem.Clone(Boolean keepPackage, UFile newLocation, Asset newAsset, AssetClonerFlags flags) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\AssetItem.cs:line 139 3> at Stride.Core.Assets.AssetItem.Clone(UFile newLocation, Asset newAsset, AssetClonerFlags flags) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\AssetItem.cs:line 120 3> at Stride.Core.Assets.Analysis.AssetCollision.<>c__DisplayClass0_0.<Clean>b__1(AssetItem item) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\Analysis\AssetCollision.cs:line 48 3> at System.Linq.Enumerable.SelectListIterator2.Fill(ReadOnlySpan1 source, Span1 destination, Func2 func) 3> at System.Linq.Enumerable.SelectListIterator2.ToList()
3> at Stride.Core.Assets.Analysis.AssetCollision.Clean(Package package, ICollection1 inputItems, ICollection1 outputItems, AssetResolver assetResolver, Boolean cloneInput, Boolean removeUnloadableObjects) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\Analysis\AssetCollision.cs:line 48
3> at Stride.Core.Assets.Package.ValidateAssets(Boolean alwaysGenerateNewAssetId, Boolean removeUnloadableObjects, ILogger log) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\Package.cs:line 784
3> at Stride.Core.Assets.PackageSession.LoadAssets(PackageSession session, ILogger log, Package package, PackageLoadParameters loadParameters, List1 pendingPackageUpgrades, PackageLoadParameters newLoadParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 1519 3> at Stride.Core.Assets.PackageSession.LoadMissingAssets(ILogger log, IEnumerable1 packages, PackageLoadParameters loadParametersArg) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 974
3> at Stride.Core.Assets.PackageSession.LoadMissingReferences(ILogger log, PackageLoadParameters loadParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 917
3> at Stride.Core.Assets.PackageSession.Load(String filePath, PackageSessionResult sessionResult, PackageLoadParameters loadParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 855
3> at Stride.Core.Assets.PackageSession.Load(String filePath, PackageLoadParameters loadParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 905
3> at Stride.Core.Assets.CompilerApp.PackageBuilder.BuildMaster() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets.CompilerApp\PackageBuilder.cs:line 91
3> at Stride.Core.Assets.CompilerApp.PackageBuilder.Build() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets.CompilerApp\PackageBuilder.cs:line 57
3> at Stride.Core.Assets.CompilerApp.PackageBuilderApp.Run(String[] args) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets.CompilerApp\PackageBuilderApp.cs:line 288
3> System.TypeInitializationException: The type initializer for 'Stride.Core.Assets.AssetCloner' threw an exception.
3> ---> System.TypeInitializationException: The type initializer for 'Stride.Core.Serialization.SerializerSelector' threw an exception.
3> ---> System.TypeInitializationException: The type initializer for '<Module>' threw an exception.
3> ---> System.IO.FileNotFoundException: Could not load file or assembly 'PresentationFramework, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified.
3> File name: 'PresentationFramework, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'
3> at System.ModuleHandle.ResolveType(QCallModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type)
3> at System.ModuleHandle.ResolveTypeHandle(Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext)
3> at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments)
3> at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(MetadataToken caCtorToken, MetadataImport& scope, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder1& derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctorWithParameters, Boolean& isVarArg) 3> at System.Reflection.CustomAttribute.AddCustomAttributes(ListBuilder1& attributes, RuntimeModule decoratedModule, Int32 decoratedMetadataToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, ListBuilder1 derivedAttributes) 3> at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType) 3> at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType, Boolean inherit) 3> at System.Attribute.GetCustomAttribute(Assembly element, Type attributeType, Boolean inherit) 3> at System.Reflection.CustomAttributeExtensions.GetCustomAttribute[T](Assembly element) 3> at System.Resources.ManifestBasedResourceGroveler.GetNeutralResourcesLanguage(Assembly a, UltimateResourceFallbackLocation& fallbackLocation) 3> at System.Resources.ResourceManager.CommonAssemblyInit() 3> at GNU.Gettext.GettextResourceManager..ctor(String baseName, Assembly assembly) 3> at Stride.Core.Translation.Providers.GettextTranslationProvider..ctor(String baseName, Assembly assembly) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core.Translation\Providers\GettextTranslationProvider.cs:line 34 3> at Stride.Core.Translation.Providers.GettextTranslationProvider..ctor(Assembly assembly) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core.Translation\Providers\GettextTranslationProvider.cs:line 25 3> at Stride.Core.Translation.Providers.GettextTranslationProvider..ctor() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core.Translation\Providers\GettextTranslationProvider.cs:line 19 3> at Stride.Core.Presentation.Module.Initialize() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\presentation\Stride.Core.Presentation.Wpf\Module.cs:line 17 3> at .cctor() 3> --- End of inner exception stack trace --- 3> at System.RuntimeTypeHandle.GetActivationInfo(ObjectHandleOnStack pRuntimeType, * ppfnAllocator, Void** pvAllocatorFirstArg, * ppfnCtor, BOOL* pfCtorIsPublic) 3> at System.RuntimeType.ActivatorCache..ctor(RuntimeType rt) 3> at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean wrapExceptions) 3> at Stride.Core.Serialization.SerializerSelector.UpdateDataSerializers() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core\Serialization\SerializerSelector.cs:line 271 3> at Stride.Core.Serialization.SerializerSelector.Initialize() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core\Serialization\SerializerSelector.cs:line 101 3> at Stride.Core.Serialization.SerializerSelector..cctor() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core\Serialization\SerializerSelector.cs:line 45 3> --- End of inner exception stack trace --- 3> at Stride.Core.Serialization.SerializerSelector..ctor(Boolean reuseReferences, Boolean externalIdentifiableAsGuid, String[] profiles) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\core\Stride.Core\Serialization\SerializerSelector.cs:line 17 3> at Stride.Core.Assets.AssetCloner..cctor() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\AssetCloner.cs:line 38 3> --- End of inner exception stack trace --- 3> at Stride.Core.Assets.AssetItem.Clone(Boolean keepPackage, UFile newLocation, Asset newAsset, AssetClonerFlags flags) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\AssetItem.cs:line 139 3> at Stride.Core.Assets.AssetItem.Clone(UFile newLocation, Asset newAsset, AssetClonerFlags flags) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\AssetItem.cs:line 120 3> at Stride.Core.Assets.Analysis.AssetCollision.<>c__DisplayClass0_0.<Clean>b__1(AssetItem item) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\Analysis\AssetCollision.cs:line 48 3> at System.Linq.Enumerable.SelectListIterator2.Fill(ReadOnlySpan1 source, Span1 destination, Func2 func) 3> at System.Linq.Enumerable.SelectListIterator2.ToList()
3> at Stride.Core.Assets.Analysis.AssetCollision.Clean(Package package, ICollection1 inputItems, ICollection1 outputItems, AssetResolver assetResolver, Boolean cloneInput, Boolean removeUnloadableObjects) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\Analysis\AssetCollision.cs:line 48
3> at Stride.Core.Assets.Package.ValidateAssets(Boolean alwaysGenerateNewAssetId, Boolean removeUnloadableObjects, ILogger log) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\Package.cs:line 784
3> at Stride.Core.Assets.PackageSession.LoadAssets(PackageSession session, ILogger log, Package package, PackageLoadParameters loadParameters, List1 pendingPackageUpgrades, PackageLoadParameters newLoadParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 1519 3> at Stride.Core.Assets.PackageSession.LoadMissingAssets(ILogger log, IEnumerable1 packages, PackageLoadParameters loadParametersArg) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 974
3> at Stride.Core.Assets.PackageSession.LoadMissingReferences(ILogger log, PackageLoadParameters loadParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 917
3> at Stride.Core.Assets.PackageSession.Load(String filePath, PackageSessionResult sessionResult, PackageLoadParameters loadParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 855
3> at Stride.Core.Assets.PackageSession.Load(String filePath, PackageLoadParameters loadParameters) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets\PackageSession.cs:line 905
3> at Stride.Core.Assets.CompilerApp.PackageBuilder.BuildMaster() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets.CompilerApp\PackageBuilder.cs:line 91
3> at Stride.Core.Assets.CompilerApp.PackageBuilder.Build() in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets.CompilerApp\PackageBuilder.cs:line 57
3> at Stride.Core.Assets.CompilerApp.PackageBuilderApp.Run(String[] args) in C:\BuildAgent\work\b5f46e3c4829a09e\sources\assets\Stride.Core.Assets.CompilerApp\PackageBuilderApp.cs:line 288
I tried running the source to debug this and its a bit weird. I noticed that if I run the build from the Stride Gamestudio I dont have any errors..
Its important to note that the folders in the solution "shouldnt" matter, my project is the below mess of what I try to organize and I havent had this error before.
This specific error seems to be narrowed down to happening when only using VS2022 to build the project with the AssetCompiler. so either Gamestudio is using the compiler differently or it could be msbuild(I believe the Gamestudio still uses this for builds) vs dotnet as well.
huh, it does seem like VS AssetCompiler is different than the Gamestudio.
Top is VS and bottom is Gamestudio.
Thanks for looking into this. I think folder structure was a bit of a mislead. The problem seems to be caused by me introducing a third intermediary project (Aries3D.WPF) and having TowerNxt.WPF reference that project.
As a test I forced my output path to match yours like this
However I got the same error but now our Output Paths match
If there's anything else I can do to help you or anyone else out let me know.
Debugging this is brutal but I did find out one more thing.
Removing the AssetCompiler completely seems to build and then removing the base.Draw() in teapotDemo seems to let it run. I have no clue what this breaks lol but your Teapot demo seems to work as expected.
Make sure to clean the poroject after removing.
@xen2 would you have an easy way of seeing why the error is being thrown? I think I narrowed it down to AssetCloner.Clone() on line 225 but I cant see what is throwing an error, Im guessing due to threading?
In my case it looks like problem is related to msbuild and version of it, when I Installed ms build and vs 2019 along with 2022 then the command is working, but yes it does need to work with vs 2022 alone. On windows 10, latest version of stride cannot even create a new project on vs2022 latest community edition because of this.
The problem is referencing any Stride libraries that involve WPF and a problematic ModuleInitializer code, eg. this reference will cause an issue:
<PackageReference Include="Stride.Core.Presentation.Wpf" Version="4.2.0.2122" />
The problem is caused by translation provider GettextTranslationProvider in the ModuleInitializer, eg.
https://github.com/stride3d/stride/blob/3797e5d2be7e44fac4b823861e8fcba665e92e15/sources/presentation/Stride.Core.Presentation.Wpf/Module.cs#L17
which traces all the way back to this class
https://github.com/stride3d/gettextnet/blob/f5f61820ea00b9a2e42570014b73e68b727a23d5/GNU.Gettext/GNU.Gettext/GettextResourceManager.cs#L70
What's happening is the base ResourceManager is doing some reflection/assembly loading (or something like that) which is making it try to load the WPF libraries (eg. PresentationFramework.dll) when the WPF library isn't loaded.
Here's where things fall apart, in .NET 8 (maybe .NET 6, as well?), the WPF library is treated as a "FrameworkReference" instead of some standard library you could reference.
This means things like PresentationFramework.dll are no longer included in build folder, as they are part of the runtime (eg. C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\8.0.6).
The Game Studio editor works because it is a WPF app, so all the WPF libraries are already loaded at the start so ResourceManager doesn't need to load any WPF library.
CompilerApp is not a WPF app, so none of the WPF libraries are loaded, and the problem is I'm not sure you can Assembly.Load the WPF libraries since the "framework" libraries aren't expected to load this way.
A lot of the above came from me debugging through CompilerApp and this thread https://github.com/dotnet/runtime/issues/13226
The only solution(s) I can think of:
- Change GettextTranslationProvider or TranslationManager so it lazy loads
GettextResourceManagerinstead of trying to create it immediately. I assume since CompilerApp won't try to touch this stuff, it won't get called, so it won't try to trigger the loading any WPF stuff. - Wrap try/catch around these GettextTranslationProvider and just ignore the error
- Wait until cross-platform editor is made which will naturally remove dependency on WPF libraries.
I think (1.) would provide the fastest solution, though would need testing to prove CompilerApp won't touch the TranslationManager
EDIT: 1 & 2 doesn't work. There's additional code that touch WPF related objects.