ikvmnet / ikvm

A Java Virtual Machine and Bytecode-to-IL Converter for .NET
Other
1.15k stars 110 forks source link

Compiler cant find mscorlib.dll on .NET Framework 4.8 #440

Closed zznty closed 7 months ago

zznty commented 8 months ago

If i use any Ikvm or Maven reference and set target framework to net48, IkvmCompiler task throws with these messages

ERROR: Error: core library not found
ERROR: Error: unable to find 'mscorlib.dll'.

horever if target framework is net472 or net6,0+, everything works just fine. in my case i have dependencies that are only available for net48 so i cant use net472 as target for my project.

Using Ikvm 8.7.1

wasabii commented 8 months ago

Can you send me a complete example project file?

zznty commented 8 months ago

sure. ClassLibrary1.zip

wasabii commented 8 months ago

So this builds fine for me locally. With the exception that the LangVersion is set to 12, and my version of VS does not recognize that, so I change it to 11. Can you maybe explain more about your environment?

zznty commented 8 months ago

For this test ive used dotnet cli so dotnet build -f net48 fails but dotnet build -f net472 succeeds. Tested with both 8.0 and 7.0 sdk msbuilds.

wasabii commented 8 months ago

On Windows?

zznty commented 8 months ago

yes, windows 11 23h2

wasabii commented 8 months ago
c:\Users\jhaltom\Downloads\ClassLibrary1>dotnet build -f net48 ClassLibrary1.csproj
MSBuild version 17.8.0+6cdef4241 for .NET
  Determining projects to restore...
  All projects are up-to-date for restore.
C:\Program Files\dotnet\sdk\8.0.100-rc.2.23502.2\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.RuntimeIdentifierInference.targets(311,5): message NETSDK1057: You are using a preview versi
on of .NET. See: https://aka.ms/dotnet-support-policy [c:\Users\jhaltom\Downloads\ClassLibrary1\ClassLibrary1.csproj::TargetFramework=net48]
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
C:\Users\jhaltom\.nuget\packages\ikvm\8.7.1\buildTransitive\IKVM.Tasks.targets(31,9): warning : warning IKVMC0101: Unable to compile class "META-INF.versions.9.module-info" [c:\Users\jha
ltom\Downloads\ClassLibrary1\ClassLibrary1.csproj::TargetFramework=net48]
C:\Users\jhaltom\.nuget\packages\ikvm\8.7.1\buildTransitive\IKVM.Tasks.targets(31,9): warning :     (class format error "53.0") [c:\Users\jhaltom\Downloads\ClassLibrary1\ClassLibrary1.cs
proj::TargetFramework=net48]
c:\Users\jhaltom\Downloads\ClassLibrary1\Class1.cs(7,17): warning CS0612: 'JsonParser.JsonParser()' is obsolete [c:\Users\jhaltom\Downloads\ClassLibrary1\ClassLibrary1.csproj::TargetFram
ework=net48]
  ClassLibrary1 -> c:\Users\jhaltom\Downloads\ClassLibrary1\bin\Debug\net48\ClassLibrary1.dll

Build succeeded.

C:\Users\jhaltom\.nuget\packages\ikvm\8.7.1\buildTransitive\IKVM.Tasks.targets(31,9): warning : warning IKVMC0101: Unable to compile class "META-INF.versions.9.module-info" [c:\Users\jha
ltom\Downloads\ClassLibrary1\ClassLibrary1.csproj::TargetFramework=net48]
C:\Users\jhaltom\.nuget\packages\ikvm\8.7.1\buildTransitive\IKVM.Tasks.targets(31,9): warning :     (class format error "53.0") [c:\Users\jhaltom\Downloads\ClassLibrary1\ClassLibrary1.cs
proj::TargetFramework=net48]
c:\Users\jhaltom\Downloads\ClassLibrary1\Class1.cs(7,17): warning CS0612: 'JsonParser.JsonParser()' is obsolete [c:\Users\jhaltom\Downloads\ClassLibrary1\ClassLibrary1.csproj::TargetFram
ework=net48]
    3 Warning(s)
    0 Error(s)

Time Elapsed 00:00:04.27

So, works here.

We're going to probably need to dig into this deeper. Can you get me diagnostic level binary log from MSBuild?

>dotnet build -v:diag -bl -f net48 ClassLibrary1.csproj

zznty commented 8 months ago

build.log

wasabii commented 8 months ago

Need a binary log. Should be msbuild.binlog.

zznty commented 8 months ago

msbuild.zip okay, zipped it because github doesnt want to let me upload non standard format

wasabii commented 8 months ago

So the problem appears to be that mscorlib.dll isn't being passed to IKVM. And the diffrence between our two runs is that yours is adding the Microsoft.NETFramework.ReferenceAssemblies (which is for some reason missing mscorlib) NuGet package, while mine is using the installed facades in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.8\Facades\

Question for you. Do you have Visual Studio installed on your machine?

zznty commented 8 months ago

i do have it, but probably newer versions dont use framework devpack anymore. noticed the reference assemblies thing too, but this nuget package ships with full framework assembly list so mscorlib exists there

wasabii commented 8 months ago

Yeah. It does. But mscorlib is getting left off.

zznty commented 8 months ago

most likely because ikvm is searching for Facades directory but mscorlib is present only in root directory

wasabii commented 8 months ago

Same in Program Files though. Same layout.

wasabii commented 8 months ago

I need more verbosity on your log file. That's why I asked for -v:diag. Looks like you had it set to minimal.

wasabii commented 8 months ago

So my understanding is that the reference nuget is used of you don't have the devoack installed. So you probably don't. I probably do.

But please don't install it yet. I want to track this down.

zznty commented 8 months ago

even devpack install didnt help with that, cli and rider are still using sdk msbuild which has no idea about framework devpacks nor its references

zznty commented 8 months ago

I need more verbosity on your log file.

ive copypasted your command and console output looks like diag too

wasabii commented 8 months ago

Core SDK MSBuild DOES have ideas about devpacks though. It's intended to.

C:\Program Files\dotnet\sdk\8.0.100-rc.2.23502.2\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.FrameworkReferenceResolution.targets

wasabii commented 8 months ago

Yes, the verbosity effects both outputs.

wasabii commented 8 months ago

Maybe try dotnet msbuild -v:diag instead.

wasabii commented 8 months ago

Yeah. The problem is in your MSBuild output I'm not able to find the first builtin call to ResolveAssemblyReferences, which I would be expecting to see. Nor can I see the targets that detect the existence of the devpacks, etc.

zznty commented 8 months ago

even dotnet msbuild is producing the exact same log and looks like it exits before all dependencies of ResolveAssemblyReferences have ran

wasabii commented 8 months ago

Another thing I've noticed is that the decision to include the NuGet happens in Restore. Can you rerun restore with the devpack installed?

wasabii commented 8 months ago

The IncludeTargetingPackReference seems to be where the core decision is made. In my builds, RootPath is not passed. In yours it is. That variable is set by the .targets file packed with the NuGet package. So, restore decides whether to implicitely reference that NuGet. And then the variable is set.

zznty commented 8 months ago

restore.zip

wasabii commented 8 months ago

Can you try again after clearing obj/?

zznty commented 8 months ago

restore.zip

wasabii commented 8 months ago

Geeze. Yeah. I don't undestand it. So.... let's focus on somehow to patch it up. Because I don't have anyway to reproduce it here, I'm going to have you make some changes to the IKVM targets files, directly in your NuGet cache.

In C:\Users\User.nuget\packages\ikvm\8.7.1\buildTransitive\IKVM.targets

ResolveIkvmFrameworkReferences target.

There's this group:


            <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.NuGetIsFrameworkReference)' == 'true' Or '%(Reference.FrameworkFile)' == 'true' Or '%(Reference.ResolvedFrom)' == '{TargetFrameworkDirectory}' Or '%(Reference.IsImplicitlyDefined)' == 'true' Or '%(Reference.FrameworkReferenceName)' != '' Or '%(Reference.FrameworkReferenceVersion)' != '' "/>
            <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.Filename)%(Reference.Extension)' == 'IKVM.Runtime.dll' " />
            <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.Filename)%(Reference.Extension)' == 'IKVM.Java.dll' " />

The goal here is to yank some framework-related assemblies out of the set of all currently known references, but to exclude assemblies in References up to this point which are based on user-included NuGet packages. For instance, when building IkvmReference, we don't want to link against some random NuGet package the user included.

So, there's a bunch of different ways this is indicated in metadata.

Reference.NuGetIsFrameworkReference, etc.

Much as we hardcode the search for IKVM.Java.dll, let's hardcode teh search for mscorlib.dll. So copy the IKVM.Java line, and just replace the nam

If I had access to your machine, though, what I would be doing is looking through the input References collection, and seeing if there are any metadata item tests that I'm missing, that would include mscorlib. IsNuGetMagicFrameworkThing? Stuff like that. If you have the ability to do that.....

One way to do it would be to add a new ItemGroup, called, <_LetMeSee Include=@(Reference)" /> and then run the binary logger, so you can see EVERYTHING in References at that point, including it's metadata.

zznty commented 8 months ago

okay looks like its also reproduceable under windows sandbox environment so you can launch it, install latest sdk package and try to build the project (also had to use jar directly because ssl java lib doesnt work in sandbox for some reason)

wasabii commented 8 months ago

Awesome. I always forget about sandbox.

image

So, no metadata at all. How obnoxious. When provided by the NuGet framework reference package, mscorlib is listed in Reference, but gets no metadata assigned to it to indicate it's an actual framework level reference, or SDK level reference.

So, gotta hard code it.

            <_IkvmFrameworkAssemblyReference Include="@(Reference)" Condition=" '%(Reference.NuGetIsFrameworkReference)' == 'true' Or '%(Reference.FrameworkFile)' == 'true' Or '%(Reference.ResolvedFrom)' == '{TargetFrameworkDirectory}' Or '%(Reference.IsImplicitlyDefined)' == 'true' Or '%(Reference.FrameworkReferenceName)' != '' Or '%(Reference.FrameworkReferenceVersion)' != '' Or '%(Reference.Identity)' == 'mscorlib' "/>
zznty commented 8 months ago

Can confirm, pr has fixed the issue for me.