ikvmnet / ikvm

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

Oracle Linux Server support #430

Closed vokounjan closed 8 months ago

vokounjan commented 9 months ago

I have an application (targeting .NET 7, built with .NET 8 SDK) using IKVM that I run successfully on Windows and Debian. However, if I try to run it on Oracle Linux Server, I get the following error message:

Unhandled exception. System.TypeInitializationException: The type initializer for 'com.somecompany.utils.demo' threw an exception.
---> System.TypeInitializationException: The type initializer for 'java.lang.Object' threw an exception.
---> System.ArgumentNullException: Value cannot be null. (Parameter 'propertyName')
   at System.Text.Json.ThrowHelper.ThrowArgumentNullException(String parameterName)
   at System.Text.Json.JsonElement.TryGetProperty(String propertyName, JsonElement& value)
   at IKVM.Runtime.RuntimeUtil.GetRuntimeIdentifierIterator(String rid)+MoveNext()
   at System.Linq.Enumerable.DistinctIterator``1.MoveNext()
   at IKVM.Runtime.JVM.Properties.ResolveHomePathFromRoot(String homePathRoot)
   at IKVM.Runtime.JVM.Properties.GetHomePath()
   at System.Lazy``1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy``1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy``1.CreateValue()
   at IKVM.Runtime.JVM.Properties.get_HomePath()
   at IKVM.Runtime.JVM.Properties.GetInitProperties()
   at System.Lazy``1.ViaFactory(LazyThreadSafetyMode mode)
   at System.Lazy``1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
   at System.Lazy``1.CreateValue()
   at IKVM.Runtime.JVM.Properties.get_Init()
   at IKVM.Java.Externs.java.lang.System.initProperties(Object props)
   at java.lang.System.initProperties(Properties props)
   at java.lang.System.initializeSystemClass()
   at __<MethodAccessor>__System__initializeSystemClass()
   at IKVM.Runtime.Accessors.Java.Lang.SystemAccessor.InvokeInitializeSystemClass()
   at IKVM.Runtime.JVM.EnsureInitialized()
   at java.lang.Object..cctor()
   --- End of inner exception stack trace ---
   at java.lang.Object..ctor()
   at com.somecompany.utils.demo.Test_s..ctor()
   at com.somecompany.utils.demo.Test_s..ctor(1)
   at com.somecompany.utils.demo..cctor()
   --- End of inner exception stack trace ---
   at com.somecompany.utils.demo.SetDebugLevel(Int32 i)
   at MyApplication.Program.<>c.<Main>b__0_0(HostBuilderContext context, ILoggingBuilder logging) in E:\src\MyApplication\Program.cs:line 26
   at Microsoft.Extensions.Hosting.HostingHostBuilderExtensions.<>c__DisplayClass4_1.<ConfigureLogging>b__1(ILoggingBuilder builder)
   at Microsoft.Extensions.DependencyInjection.LoggingServiceCollectionExtensions.AddLogging(IServiceCollection services, Action``1 configure)
   at Microsoft.Extensions.Hosting.HostingHostBuilderExtensions.<>c__DisplayClass4_0.<ConfigureLogging>b__0(HostBuilderContext context, IServiceCollection collection)
   at Microsoft.Extensions.Hosting.HostBuilder.InitializeServiceProvider()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at MyApplication.Program.Main(String[] args) in E:\src\MyApplication\Program.cs:line 16

I am building the application as self-contained on Windows machine as follows:

dotnet restore --runtime linux-x64
dotnet publish --configuration Release --no-restore --self-contained --runtime linux-x64

And contents of /etc/os-release and and /etc/redhat-release on OLS machine are following

NAME="Oracle Linux Server"
VERSION="7.9"
ID="ol"
ID_LIKE="fedora"
VARIANT="Server"
VARIANT_ID="server"
VERSION_ID="7.9"
PRETTY_NAME="Oracle Linux Server 7.9"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:oracle:linux:7:9:server"
HOME_URL="[https://linux.oracle.com/"](https://linux.oracle.com/%22)
BUG_REPORT_URL="[https://bugzilla.oracle.com/"](https://bugzilla.oracle.com/%22)

ORACLE_BUGZILLA_PRODUCT="Oracle Linux 7"
ORACLE_BUGZILLA_PRODUCT_VERSION=7.9
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=7.9
Red Hat Enterprise Linux Server release 7.9 (Maipo)

Is Oracle Linux Server supported? If so, what am I doing wrong? Thanks in advance for your help.

wasabii commented 9 months ago

Which version of IKVM is this with?

wasabii commented 9 months ago

And can you run dotnet --info and show the output here?

vokounjan commented 9 months ago

Sorry, should have mentioned it - I'm using the currently latest version 8.6.4.

Unfortunately I don't have access to the machine right now (will have on Monday) but there is no .NET installed on it therefore I'm using the self-contained version. I'll paste the output here once I'm able to.

wasabii commented 9 months ago

Ahh. What I think is going on is the RuntimeIdentifier that .NET is returning to IKVM isn't actually present in .NET's RID graph file at: https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.NETCore.Platforms/src/runtime.json

The idea here is IKVM uses .NET's runtime identifier to figure out which native Java library versions it should load. I've seen this come up a few other times, with OS X. For instance, .NET might report RID 'ol.9.0-x64'.... because it's running on Oracle Linux 9, but Microsoft left off on 'ol.8.0-x64' or something in their RID document, and never added 9. This IKVM gets version 9, and cant find it in the runtime.json file.

This will change quite a bit in .NET 8, as MS is dropping the distribition specific RID values in favor of ONLY win-arch, linux-arch, osx-arch, etc. But, we're not there yet.

So, yeah, looks like 8.6.4 is broken on your specific version of Oracle Linux.

I'm preparing a patch to generate a 'fallback rid' if the version returned by .NET itself isn't known.

wasabii commented 9 months ago

One workaround you can use is to set the environment variable DOTNET_RUNTIME_ID to something specific. Which should skip consulting .NET. For instance, set it to linux-x64.

vokounjan commented 9 months ago

Thank you for confirming my assumption (RID problem). Publishing the application in .NET 8 was actually my next step.

Also thanks for the DOTNET_RUNTIME_ID hint, I'll try that first.