UnsatisfiedLinkError: The library loads but I still get a link error
Asked Answered
I

2

1

I have two Eclipse plugins:

  • plugin-1: provides a package in .jar to other plugins. (a Java Wrapper for a C++ library) This plugin was created by clicking File->New->Other->Plug-in from Existing JAR Archives.

  • plugin-2: has the native library .so for plugin-1 (Bundle-NativeCode directive is in MANIFEST.MF) and instantiates a class from plugin-1

(I actually tried putting the .so in plugin-1, but I cannot seem to load the library, even with the Bundle-NativeCode directive in the plugin-1 MANIFEST.MF, outside of the plugin project that contains the .so, so I guess I have to bundle the .so with any plugin that uses plugin-1.)

I am running a JUnit tests from plugin-2 which instantiates MyClass from plugin-2 which, in turn, instantiates MyLibraryClass from plugin-1. MyClass successfully loads the native library and instantiates MyLibraryClass without an UnsatisfiedLinkError or other exception being thrown from either the loading of the native library or from instantiating MyLibraryClass. I am not running a plugin in this case -- just the JUnit tests.

When I run plugin-2 (using a product configuration) and instantiate MyClass, the native library loads fine but I get an UnsatisifiedLinkError when MyClass instantiates MyLibraryClass. In this case, I believe the library is being loaded based on the output I get from using the class described in the posting How do I get a list of JNI libraries which are loaded?

NOTE: I'm using Eclipse 3.6.1.

Here is a code sample that shows the essence of what I'm trying to do: package com.mylibrary;

import com.external_library.MyLibraryClass;


public class MyClass {


    public static void loadLibrary() {
      // Without Bundle-NativeCode in MANIFEST.MF I get 
      // "java.lang.UnsatisfiedLinkError: no mylibrary_java in java.library.path"
      System.loadLibrary("mylibrary_java"); // Loads libmylibrary_java.so. 

      // Works fine from JUnit Test
      // When I run the plugin, I get an UnsatisfiedLinkError:
      // "java.lang.UnsatisfiedLinkError: 
      // com.external_library.MyLibrary_javaJNI.new_MyLibraryClass__SWIG_3()J"
      MyLibraryClass instance = new MyLibraryClass(); 

    }
}
Imparadise answered 4/4, 2013 at 22:13 Comment(6)
I'm a bit confused. If I have understand you right, you have the following dependency chain [ 2 <- 1 <- 3 <- 4 ]. You also said that your setup works with JUnit tests. Did you mean normal JUnit tests or JUnit Plugin Tests?Licko
Maybe you could also post some code of your MyLibraryClass?Licko
1 doesn't depend on 2, but anyone who uses 1 most call the load library method in 1. I only have a .class file for the MyLibraryClass but let me think about what code I could give you that would be worthwhile. I did mean JUnit, not JUnit plugin.Imparadise
@Tobias Willig -- I reworked my submission, hopefully simplifying it and adding a little code snippet.Imparadise
NOTE: I tested this new configuration and I still see the same problem.Imparadise
Ok I will take a look at this problemLicko
L
1

I have replicated your setup and I get the same exception.

The problem could be solved by:

  • add the native library to plugin-1
  • add the Bundle-NativeCode directive to plugin-1's Manifest
  • load the library in the static constructor of plugins-1's Activator (you can write one and add it to the plugin)

Some other possible sources of errors: Be aware that the package path, the class name and the method signatures should never be changed for any class with native bindings. Otherwise JNI would not be able to find the native counterpart and you get an UnsatisfiedLinkError. In your import directive you specified the following classname com.external_library.MyLibraryClass, but your error message has a different classname com.external_library.MyLibrary_javaJNI. Check for these sources of errors.

Some additional explanations: A JUnit test in contrast to an JUnit plugin test starts no OSGi environment. Therefore you have a plain Java application with an ordinary JUnit test. If your native lib and your application are contained in the same folder (top level) the native lib will be automatically found on windows. If that is also true on UNIX systems, this would be an explanation why your JUnit test is successful. If it lies in a different folder, you have to specify the Java Library Path for an ordinary Java application.

EDIT by MrMas: Modify plugin-2 so it doesn't depend on plugin-1 by adding the .jar file to plugin-2.

  1. Copy the .jar file into plugin-2. I put it in the same directory as the .so.
  2. Add the jar to the project via: Project->Properties->Libraries->Add Jar
  3. Add the jar to the class path via plugin.xml->Runtime->ClassPath section->Add
  4. Export the packages from the Jar (if they're needed by downstream plugins)
  5. Remove the dependence of plugin-1 from the plugin.xml->dependencies tab

Now you can load the library with a System.loadLibrary and use the classes from within the plugin and from another plugin.

I chose not to modify plugin-1 because it was created as a plugin from an existing jar to which I couldn't discover how to add an Activator. I instead chose the path of adding the .jar to plugin-2. See Adding jars to a Eclipse PlugIn for additional discussion.

Licko answered 5/4, 2013 at 17:10 Comment(2)
I originally tried to do what you described, but I couldn't create a new src folder for the Activator.java file. I'm going to edit your response to fill in the holes, though what you described sent me the right direction. Thank you for taking time to look into this!Imparadise
Yes do that. I'm glad I could help.Licko
S
1

Bundle-NativeCode is an OSGI-tag. This means only OSGI classloaders are using it. In my case, I had an E4-RCP application. One plugin contained the Java class. The native code, however, I put into a fragment.

When loading and looking for a library, the OSGI classloader has a list of fragments (according to the naming of the structure involved) and examines their Bundle-NativeCode using the class NativeCodeFinder. If one has troubles, try to add breakpoints at the relevant functions. getNativePath() returns the entries as read by the OSGIpart.

Simplistic answered 27/5, 2016 at 10:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.