Error merging VB app in 2.0.27
pricerc opened this issue · 20 comments
I'm using 2.0.18 ok, but nuget advised me that there was an update, so I decided to try it.
I run the repack in a post-build CMD file, with this snippet:
SET ILMERGE_VERSION=2.0.27
SET ILMERGE_PATH=%USERPROFILE%.nuget\packages\ilrepack%ILMERGE_VERSION%\tools\
Without doing anything else besides changing the minor version from 18 to 27, I get this error:
Failed to resolve assembly: 'Microsoft.VisualBasic.Core, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
can you add a /lib:dir option where dir is the directory containing Microsoft.VisualBasic.Core.dll?
I can give it a go.
I just have to figure out which of the 78 copies of Microsoft.VisualBasic.Core.DLL on my C: drive is the right one...
I went with this one:
/lib:C:\VisualStudio\2022\Professional\dotnet\net8.0\runtime\shared\Microsoft.NETCore.App\8.0.1
Which got rid of the error during repacking. I'll have to test the resulting assembly later - I need to copy it to a test platform to confirm that it works.
But while going through this exercise, I clicked that I'm still using VS 2017 for this particular library which is a .NET Framework 4.8 assembly, but Microsoft.VisualBasic.Core.DLL is a .NET 8.0 assembly.
So I'm not sure why my library would be interested in it, or why ILRepack would want to look for it.
Looking at the merged DLL using ILSpy, there is no reference to Microsoft.VisualBasic.Core.DLL.
Cecil needs that dll to resolve some type references (understand signatures, metadata etc) of the input assemblies, even if the actual dll is not used.
I’m guessing 2.0.18 was accidentally picking it up from some random location like the GAC or something. We did change the resolve algorithm to rely on the /lib: arguments to make it explicit which ones you need exactly, because people have been picking up wrong dlls from wrong locations accidentally.
I’m guessing 2.0.18 was accidentally picking it up from some random location like the GAC or something. We did change the resolve algorithm to rely on the /lib: arguments to make it explicit which ones you need exactly, because people have been picking up wrong dlls from wrong locations accidentally.
I still don't understand why it needs the location of a library that none of my assemblies are using, and that is for a different generation of framework.
I've changed it to /lib:"%ProgramFiles(x86)%\dotnet\shared\Microsoft.NETCore.App\6.0.26", which is at least not as hard-coded, and in a "well-known" folder.
You can install dotnet tool install -g refdump
and then in the directory with all your assemblies, run refdump *.dll -s -a:Microsoft.VisualBasic.Core -t
and it will show you which of the assemblies are referencing Microsoft.VisualBasic.Core.dll and why.
And if I do refdump *.dll -s -t | findstr /i /r Microsoft.*Core
then all I get is WebView2.Core
and .Basic.:
C:\Projects\CBS\CBS-Vault\CBS.Vault\bin\Debug>refdump *.dll -s -t | findstr /i /r .*Basic.*
Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a:
Microsoft.VisualBasic.ApplicationServices.ApplicationBase
Microsoft.VisualBasic.ApplicationServices.AssemblyInfo
Microsoft.VisualBasic.ApplicationServices.User
Microsoft.VisualBasic.CompareMethod
Microsoft.VisualBasic.CompilerServices.Conversions
Microsoft.VisualBasic.CompilerServices.DesignerGeneratedAttribute
Microsoft.VisualBasic.CompilerServices.LikeOperator
Microsoft.VisualBasic.CompilerServices.NewLateBinding
Microsoft.VisualBasic.CompilerServices.Operators
Microsoft.VisualBasic.CompilerServices.ProjectData
Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute
Microsoft.VisualBasic.CompilerServices.Utils
Microsoft.VisualBasic.Conversion
Microsoft.VisualBasic.DateAndTime
Microsoft.VisualBasic.DateInterval
Microsoft.VisualBasic.Devices.Computer
Microsoft.VisualBasic.Devices.ComputerInfo
Microsoft.VisualBasic.Devices.Keyboard
Microsoft.VisualBasic.Devices.ServerComputer
Microsoft.VisualBasic.FileIO.DeleteDirectoryOption
Microsoft.VisualBasic.FirstDayOfWeek
Microsoft.VisualBasic.FirstWeekOfYear
Microsoft.VisualBasic.HideModuleNameAttribute
Microsoft.VisualBasic.Interaction
Microsoft.VisualBasic.MyGroupCollectionAttribute
Microsoft.VisualBasic.MyServices.ClipboardProxy
Microsoft.VisualBasic.MyServices.FileSystemProxy
Microsoft.VisualBasic.MyServices.Internal.ContextValue`1
Microsoft.VisualBasic.MyServices.RegistryProxy
Microsoft.VisualBasic.MyServices.SpecialDirectoriesProxy
Microsoft.VisualBasic.Strings
Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a:
Microsoft.VisualBasic.Devices.ComputerInfo
System.ServiceModel.BasicHttpBinding
System.ServiceModel.BasicHttpSecurityMode
DevExpress.Data.Filtering.Helpers.CriteriaToBasicStyleParameterlessProcessor
System.ServiceModel.BasicHttpBinding
System.ServiceModel.BasicHttpSecurity
System.ServiceModel.BasicHttpSecurityMode
DevExpress.Data.Filtering.Helpers.CriteriaToBasicStyleParameterlessProcessor
System.ServiceModel.BasicHttpBinding
System.ServiceModel.BasicHttpSecurity
System.ServiceModel.BasicHttpSecurityMode
DevExpress.Diagram.Core.BasicShapes
Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a:
Microsoft.VisualBasic.ApplicationServices.ApplicationBase
Microsoft.VisualBasic.ApplicationServices.AssemblyInfo
Microsoft.VisualBasic.ApplicationServices.User
Microsoft.VisualBasic.CompareMethod
Microsoft.VisualBasic.CompilerServices.Conversions
Microsoft.VisualBasic.CompilerServices.DesignerGeneratedAttribute
Microsoft.VisualBasic.CompilerServices.LikeOperator
Microsoft.VisualBasic.CompilerServices.NewLateBinding
Microsoft.VisualBasic.CompilerServices.Operators
Microsoft.VisualBasic.CompilerServices.ProjectData
Microsoft.VisualBasic.CompilerServices.StandardModuleAttribute
Microsoft.VisualBasic.CompilerServices.Utils
Microsoft.VisualBasic.Conversion
Microsoft.VisualBasic.DateAndTime
Microsoft.VisualBasic.DateInterval
Microsoft.VisualBasic.Devices.Computer
Microsoft.VisualBasic.Devices.ComputerInfo
Microsoft.VisualBasic.Devices.Keyboard
Microsoft.VisualBasic.Devices.ServerComputer
Microsoft.VisualBasic.FileIO.DeleteDirectoryOption
Microsoft.VisualBasic.FirstDayOfWeek
Microsoft.VisualBasic.FirstWeekOfYear
Microsoft.VisualBasic.HideModuleNameAttribute
Microsoft.VisualBasic.Interaction
Microsoft.VisualBasic.MyGroupCollectionAttribute
Microsoft.VisualBasic.MyServices.ClipboardProxy
Microsoft.VisualBasic.MyServices.FileSystemProxy
Microsoft.VisualBasic.MyServices.Internal.ContextValue`1
Microsoft.VisualBasic.MyServices.RegistryProxy
Microsoft.VisualBasic.MyServices.SpecialDirectoriesProxy
Microsoft.VisualBasic.Strings
C:\Projects\CBS\CBS-Vault\CBS.Vault\bin\Debug>
Because this is a fairly common "issue" for which we cannot do anything on development side. My suggestion is to catch the Mono.Cecil.AssemblyResolutionException
by wrapping its message in something like “[ILREPACK-001] Failed to resolve assembly” and throwing it again. Here, rename one of the related issues
with /lib:
suggestion to this error message. This will make searching and self-diagnosis of such errors easier. People will find this problem by the error ID and help themselves.
If you want to figure out why MS.VB.Core is needed, you need to debug, break in the debugger when it happens and examine the callstack. It will tell you what Cecil was looking at that required that dll.
So its failing when trying to resolve Microsoft.VisualBasic.MyGroupCollectionAttribute, which in .NET 'core' lives in Microsoft.VisualBasic.Core, but in .NET 'Framework' lives in Microsoft.VisualBasic.
Putting a break point in ReferenceFixator.FixReferences, I can see that the scope at this point is "{Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a}"
It is still correct in Cecil.MetadataResolver public virtual TypeDefinition Resolve (TypeReference type)
.
Then, in TryResolve, it gets broken, after this, the version number has changed to 0.0.0.0:
private AssemblyDefinition TryResolve(AssemblyNameReference name, ReaderParameters parameters)
{
if (name.Name == "System.Runtime" && name.Version.Major != 0 && systemRuntimeVersion is null)
{
systemRuntimeVersion = name.Version;
}
// heuristic: assembly more likely to be Core after that version.
// Try to resolve from Core first to prevent the base resolver
// from resolving Core assemblies from the GAC
if (IsFrameworkName(name.Name) && name.Version > netcoreVersionBoundary)
{
var fromCore = TryResolveFromCoreFixVersion(name);
if (fromCore != null)
{
return fromCore;
}
}
var result = base.Resolve(name, parameters);
return result;
}
The heuristic is not valid for Microsoft.VisualBasic, since the version number for the .NET Framework version of Microsoft.VisualBasic.dll is 10.0.0.0, and the .NET 8.0 version of Microsoft.VisualBasic.Core 8 is 13.0.x.y...
If I skip that logic and go straight to var result = base.Resolve(name, parameters);
, I get the correct resolution.
Thanks for investigating! It does seem to be a problem, and a regression too, and my fault on top of it. I’ll take a look.
I'm trying to reproduce this and I can't find a good repro. Any chance you would be able to create a minimal project that exhibits this problem? I'm guessing it should be relatively simple now knowing that a VB attribute is involved. Once I have a repro (without your added /lib argument) I'll be able to fix the heuristic in the resolver as well as emit a better error message for this situation.
This is what I tried: I created a tiny app that uses Newtonsoft and VB and tried to merge it, and it seems to work fine for me:
There must be some step that is relevant and I'm missing it.
I had the same problem, so I did the same experiment as you and the problem happened to me as well
The solution is very simple: ignore the problem
I made a copy of "Microsoft.VisualBasic.Core.dll" and put it in the same folder and from here there is no longer a problem.
But ignoring is the solution to the problem. For example, if you make a copy of 'Newtonsoft.Json.dll' and change its name to 'Microsoft.VisualBasic.Core.dll', this will solve the problem as well.
@pricerc
Try it and share with us if the solution is to ignore.
@Dark-Shadow-EGY You're saying that the problem happened to you. It didn't happen to me. I'd love to be able to reproduce the problem so I can fix it. If I can fix it, there's no need to ignore.
Could you please describe your set up and repro steps exactly? What did you do? Where is Newtonsoft.Json.dll? Where is MS.VB.Core.dll? what is the arguments passed to ILRepack.exe? what is the current directory?
Thanks.
2024-05-28.09-01-28.mp4
Thanks all! @pricerc your insight was very helpful, and @Dark-Shadow-EGY with your video I was able to reproduce and fix.