question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Try System.loadLibrary before trying to extract native libraries from a JAR

See original GitHub issue

We use Realm in a multi-platform compose app, one that includes a compose desktop build. Some JVM installers move native shared/JNI libraries are out of the JAR, for a number of reasons, including Windows and macOS security systems’ requirement to verify all native code is signed. Conveyor specifically recommends:

Therefore your software should always attempt to load shared libraries by using System.loadLibrary first, before trying to extract native libraries from a JAR. Alternatively you can use System.load in combination with the java.home system property but remember to add either lib on UNIX or bin on Windows.

From what i can see here, it seems Realm will only use System.loadLibrary on Android, which results in exception when trying to initialize our app on desktop JVM apps:

Caused by: java.lang.RuntimeException: Couldn't load Realm native libraries
        at io.realm.kotlin.internal.interop.realmc.<clinit>(realmc.java:28)
        ... 85 more
Caused by: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at io.realm.kotlin.internal.interop.realmc.<clinit>(realmc.java:26)
        ... 85 more
Caused by: java.lang.NullPointerException: lib must not be null
        at io.realm.kotlin.jvm.SoLoader.unpackAndInstall(SoLoader.kt:98)
        at io.realm.kotlin.jvm.SoLoader.load(SoLoader.kt:62)
        at io.realm.kotlin.jvm.SoLoader.load(SoLoader.kt:47)
        ... 90 more

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:9

github_iconTop GitHub Comments

2reactions
mikehearncommented, Nov 4, 2022

I think if you try loadLibrary first users won’t even need to know, right? If it doesn’t work you’ll do what you’re doing now with extraction from the JAR and everything will be just as it was. It only makes a difference if the user or a tool has done the extraction and placement.

2reactions
mikehearncommented, Nov 3, 2022

Hiya,

The issue here isn’t really Conveyor specific. Rather, anyone who wants to package Realm with their (desktop) app and use jlink to create a bundled JVM setup will hit the issue.

In a completely normal, old-school JVM bundling setup all shared libraries are placed in the library search path by default, so when the JVM executes System.loadLibrary("foo") will work without the app needing to care about file locations, caches, extraction from jars etc. That’s why the JDK’s own libraries don’t need to be extracted to your home directory: they’re already next to libjvm and so get found correctly. On Windows this means in the same bin directory, on macOS in the Contents/runtime/Contents/Home/lib directory and so on. Doing things the standard way has many advantages for end users, like not cluttering their home directory, better startup time, better compatibility with code signing and so on.

Therefore, Realm should really be compatible with this setup and the good news is how easy it is: just run System.loadLibrary always, and continue along the existing codepaths from a catch block. If the library can’t be loaded then you conclude you’re in a developer environment and it’s OK to go unpack to the user’s home dir. If it can be loaded, happy days, you’re running in an end-user package where everything is already laid out properly ahead of time.

Does that make sense?

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to bundle a native library and a JNI library inside a JAR?
I want is to have the native library, JNI library, and all Java API classes in one JAR file to avoid redistribution headaches....
Read more >
How to Load Native JNI Library from JAR - Adam Heinrich
The problem is that for loading such a dynamic library you have to call method System.load(String filename) which requires an absolute filename.
Read more >
Bundling a native library in a jar file - Oracle Communities
This certianly is possible. I have done it. You have to extract the dll from the jar file and write it to a...
Read more >
Java Native Interface (JNI) in depth - exporting to JAR files
In this java tutorial, I discuss how to properly export a java project into a JAR file so that it contains the dynamic...
Read more >
Configuring native libraries in shared libraries - IBM
Implement a static method in the class that loads the native library. In the class that loads the native library, call System.loadLibrary( ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found