ikvmnet / ikvm

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

Encapsulating generated assemblies in nuget pkg fails in consuming service #523

Closed sanjeev-saxena-us closed 4 months ago

sanjeev-saxena-us commented 4 months ago

We have created a .net8 library (eg. lib.csproj) that encapsulates the IKVM generated dlls from the jar files. This library is a nuget package in our private DevOps. We have another .net8 app service (eg. app.csproj) that uses the nuget package above. When this app service runs, it throws an exception at start up because it cannot find any of the dlls in the nuget package. The documentation indicated that the generated dlls are added as a reference to the project (in our case, the lib.csproj nuget pkg) but we do not see them in the dependencies of the lib.csproj.

How can we resolve this?

wasabii commented 4 months ago

Not exactly sure I understand this..... but generally you should not generate IKVM assemblies and add them to NuGet packages. Use IkvmReference or MavenReference for proper management of Java libraries.

The documentation indicated that the generated dlls are added as a reference to the project (in our case, the lib.csproj nuget pkg)

IkvmReference does not do this. You should be adding IkvmReference in each project that depends upon the libraries. It operates like Reference, and is not transitive.

MavenReference though is transitive.

sanjeev-saxena-us commented 4 months ago

We are no longer using the nuget approach and have a single app service project. However when we deploy to kubernetes in Azure, we are getting failures such as:

 ---> System.TypeInitializationException: The type initializer for 'java.io.FileInputStream' threw an exception.
 ---> System.TypeInitializationException: The type initializer for 'IKVM.Runtime.LibJava' threw an exception.
 ---> System.TypeInitializationException: The type initializer for 'IKVM.Runtime.LibJvm' threw an exception.
 ---> IKVM.Runtime.InternalException: Could not load libjvm.
   at IKVM.Runtime.LibJvm..ctor()
   at IKVM.Runtime.LibJvm..cctor()
   --- End of inner exception stack trace ---
   at IKVM.Runtime.LibJava..ctor()
   at IKVM.Runtime.LibJava..cctor()
   --- End of inner exception stack trace ---
   at IKVM.Runtime.BootstrapClassLoader..ctor(RuntimeContext context)
   at IKVM.Runtime.RuntimeClassLoaderFactory.GetBootstrapClassLoader()
   at IKVM.Runtime.RuntimeClassLoaderFactory.GetClassLoaderWrapper(ClassLoader javaClassLoader)
   at IKVM.Runtime.RuntimeClassLoader.FromCallerID(CallerID callerID)
   at IKVM.Runtime.JNI.JNIFrame.GetFuncPtr(Object callerID, String clazz, String name, String sig)
   at java.io.FileInputStream.initIDs()
sanjeev-saxena-us commented 4 months ago

Btw, deploying and running in kind locally works just fine; it is an issue in Azure k8s

wasabii commented 4 months ago

Are you publishing all the proper content to the docker image, or doing something magic like naot or single file?

sanjeev-saxena-us commented 4 months ago

All are being included in the docker image.

What is interesting is that building the docker image locally works in both AKS and kind. The docker image built from an Azure pipeline fails in both AKS and kind. We noticed that when comparing the images, there is only 1 dll that is different ie. the app dll.

Our VS solution contains 2 VS projects the app and a lib; the app csproj has a project reference to the lib csproj; the lib csproj has all the IkvmReference items.

We tried dropping the lib project, brought in the code from the lib project into the app project and have all the IkvmReference items in the app's csproj but that resulted in the same issue.

Thoughts?

sanjeev-saxena-us commented 4 months ago

Unhandled exception. System.TypeInitializationException: The type initializer for '' threw an exception. ---> System.TypeInitializationException: The type initializer for 'java.io.FileInputStream' threw an exception. ---> System.TypeInitializationException: The type initializer for 'IKVM.Runtime.LibJava' threw an exception. ---> System.TypeInitializationException: The type initializer for 'IKVM.Runtime.LibJvm' threw an exception. ---> IKVM.Runtime.InternalException: Could not load libjvm. at IKVM.Runtime.LibJvm..ctor() at IKVM.Runtime.LibJvm..cctor() --- End of inner exception stack trace --- at IKVM.Runtime.LibJava..ctor() at IKVM.Runtime.LibJava..cctor() --- End of inner exception stack trace --- at IKVM.Runtime.BootstrapClassLoader..ctor(RuntimeContext context) at IKVM.Runtime.RuntimeClassLoaderFactory.GetBootstrapClassLoader() at IKVM.Runtime.RuntimeClassLoaderFactory.GetClassLoaderWrapper(ClassLoader javaClassLoader) at IKVM.Runtime.RuntimeClassLoader.FromCallerID(CallerID callerID) at IKVM.Runtime.JNI.JNIFrame.GetFuncPtr(Object callerID, String clazz, String name, String sig) at java.io.FileInputStream.initIDs() at java.io.FileInputStream..cctor() --- End of inner exception stack trace --- at java.io.FileInputStream.() at java.lang.System.initializeSystemClass() at SysteminitializeSystemClass() at IKVM.Runtime.Accessors.Java.Lang.SystemAccessor.InvokeInitializeSystemClass() at IKVM.Runtime.JVM.Init() at IKVM.Runtime.RuntimeInit.Init() at .cctor() --- End of inner exception stack trace --- at ikvm.runtime.Util.getClassFromObject(Object o) at java.lang.Object.instancehelper_getClass(Object this) at java.lang.Object.toStringImpl(Object) at java.lang.Object.toString()

tomfanara commented 4 months ago

@wasabii this seems to be a class loading issue as it (via IKVM) creates the class before running a method I assume in the java.io.FileInputStream then we get the above exception. Does this strike you as a build issue or in code with in a K8 cluster?

wasabii commented 4 months ago

In your product output, whether in the bin/ directory, or otherwise, is IKVM correctly copying the ikvm/{rid} folders?

There should at least be one ikvm/{rid} directory for the architecture you're targeting. In it, there should be a bin/ and lib/ folder, and the bin/ directory should contain various libraries. Specifically libjvm.so, and libiava.so, for Linux. And those should be ELF files of the appropriate platform.

tomfanara commented 4 months ago

is there an example docker build file that adds those libs to the container?

wasabii commented 4 months ago

Not from me.

The items are supposed to be emitted from dotnet publish. How you get that onto the Docker image is kinda up to you.

tomfanara commented 4 months ago

Ok but I assume those lib folders are the JRE that needs to be there for runtime class loading for IKVM?

wasabii commented 4 months ago

Not really. But they need to be there.

tomfanara commented 4 months ago

thanks so the JRE does not need to be present to run IKVM got it

wasabii commented 4 months ago

IKVM is a JRE. Kinda the point. It's Java classes converted to .NET classes. But it does need those native libraries for different backend implementations of classes sourced from OpenJDK.

tomfanara commented 4 months ago

good morning @wasabii we built it on a linux box in K8 and its on this folder structure.

We built the app on one of the linux pods that the agent uses (nothing particular about that, just ubuntu). It looks like it generates the so files but places them in a folder called ikvm//bin

e.g. ikvm/linux-x64/bin:

-rwxr--r-- 1 root root 17 Apr 16 14:52 ikvm.properties -rwxr--r-- 1 root root 1512 Apr 16 15:42 libawt.so -rwxr--r-- 1 root root 128944 Apr 16 15:41 libfdlibm.so -rwxr--r-- 1 root root 383328 Apr 16 15:42 libiava.so -rwxr--r-- 1 root root 33456 Apr 16 15:42 libjsound.so -rwxr--r-- 1 root root 278976 Apr 16 15:42 libjsoundalsa.so -rwxr--r-- 1 root root 142336 Apr 16 15:41 libjvm.so -rwxr--r-- 1 root root 3760 Apr 16 15:42 libmanagement.so -rwxr--r-- 1 root root 468088 Apr 16 15:42 libnet.so -rwxr--r-- 1 root root 262520 Apr 16 15:42 libnio.so -rwxr--r-- 1 root root 484464 Apr 16 15:42 libsunec.so -rwxr--r-- 1 root root 482448 Apr 16 15:42 libunpack.so -rwxr--r-- 1 root root 145960 Apr 16 15:42 libverify.so

Is this in accordance with how it should operate?

wasabii commented 4 months ago

Yup that seems fine. So my guess is we link to something on Linux that isn't present on your container.

You can probably get into the container and run ldd on each library to see if it is missing anything.

tomfanara commented 4 months ago

@wasabii Progress but different errors now

I added an option in the template (in a feature branch), ivkmMigration +  ivkmArchitecture that allows specifying to migrate the ivkm files for the specified architecture to the publish folder.   Ran this, works, however, now that the .so files are there, getting a little different errors:   Unhandled exception. System.TypeInitializationException: The type initializer for '' threw an exception. ---> System.TypeInitializationException: The type initializer for 'java.io.FileInputStream' threw an exception. ---> System.TypeInitializationException: The type initializer for 'IKVM.Runtime.LibJava' threw an exception. ---> System.TypeInitializationException: The type initializer for 'IKVM.Runtime.LibJvm' threw an exception. ---> IKVM.Runtime.InternalException: Could not load libjvm.    at IKVM.Runtime.LibJvm..ctor()    at IKVM.Runtime.LibJvm..cctor()    --- End of inner exception stack trace ---    at IKVM.Runtime.LibJava..ctor()    at IKVM.Runtime.LibJava..cctor()    --- End of inner exception stack trace ---    at IKVM.Runtime.BootstrapClassLoader..ctor(RuntimeContext context)    at IKVM.Runtime.RuntimeClassLoaderFactory.GetBootstrapClassLoader()    at IKVM.Runtime.RuntimeClassLoaderFactory.GetClassLoaderWrapper(ClassLoader javaClassLoader)    at IKVM.Runtime.RuntimeClassLoader.FromCallerID(CallerID callerID)    at IKVM.Runtime.JNI.JNIFrame.GetFuncPtr(Object callerID, String clazz, String name, String sig)    at java.io.FileInputStream.initIDs()    at java.io.FileInputStream..cctor()    --- End of inner exception stack trace ---    at java.io.FileInputStream.()    at java.lang.System.initializeSystemClass()    at SysteminitializeSystemClass()    at IKVM.Runtime.Accessors.Java.Lang.SystemAccessor.InvokeInitializeSystemClass()    at IKVM.Runtime.JVM.Init()    at IKVM.Runtime.RuntimeInit.Init()    at .cctor()    --- End of inner exception stack trace ---    at ikvm.runtime.Util.getClassFromObject(Object o)    at java.lang.Object.instancehelper_getClass(Object this)    at java.lang.Object.toStringImpl(Object)    at java.lang.Object.toString()    at com.ibm.connector.imstoc.IMSConnectionSpec..ctor() in IMSConnectionSpec.java:line 78    at Alegeus.CDH.ILA.DelegatedAuth.Lib.IMS.Communication.IMSConnector..ctor(IMSConnectConfig imsConnectConfig) in /azp/_work/77/s/Alegeus.ILA.DelegatedAuth/IMS/IMS/Communication/IMSConnector.cs:line 40    at Alegeus.ILA.DelegatedAuth.ServiceCollectionExtensions.AddLocal(IServiceCollection services, IConfiguration configuration) in /azp/_work/77/s/Alegeus.ILA.DelegatedAuth/ServiceCollectionExtensions.cs:line 43    at Program.

$(String[] args) in /azp/_work/77/s/Alegeus.ILA.DelegatedAuth/Program.cs:line 11

wasabii commented 4 months ago

Did you make any progrss on this?

wasabii commented 4 months ago

I just threw together a test project out of the box using the VS run in container template. Creates a linux container using mcr.microsoft.com/dotnet/aspnet:8.0. It runs IKVM fine. I made zero changes to the Dockerfile.

sanjeev-saxena-us commented 4 months ago

Thanks for the update. We discovered the root cause => we have .dockerignore file that has "bin" bindings which resulted in the exclusion of the bin folder. We have removed said binding and CI/CD pipeline is now successfully creating the correct docker image and deploying to the pod; the pod is fully functional. Am closing this issue.

wasabii commented 4 months ago

Ahhh. Cool. Yeah. Makes sense.