Home > Blockchain >  JNI Unsatisfied Link Error in Eclipse Can't find dependent Libraries
JNI Unsatisfied Link Error in Eclipse Can't find dependent Libraries

Time:09-24

I'm trying to invoke a C function from java that uses C -style strings. The program executes just fine when I'm using C-style strings but just as I declare std::string somehow it can't find dependent libraries anymore. I checked my includes folder in eclipse environment and it does contain <string> library and all its dependencies.

package test_strings;

public class TestString {
    
    static {
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libnative_cpp.dll");
    }
    
    public native String sayHelloC();
    public native String sayHelloCpp();

    public static void main(String[] args) {
        
        TestString test = new TestString();
        
        System.out.println(test.sayHelloC());
        System.out.println(test.sayHelloCpp());

    }

}

And this is my native file:

#include "test_strings_TestString.h"
#include<string>
using namespace std;

JNIEXPORT jstring JNICALL Java_test_1strings_TestString_sayHelloC
  (JNIEnv *env, jobject thisObj){

    jstring str = env->NewStringUTF("Hello World C-style !!");
    return str;
}

JNIEXPORT jstring JNICALL Java_test_1strings_TestString_sayHelloCpp
  (JNIEnv *env, jobject thisObj){
    //std::string str = "Hello World C   style !!";
    //return env->NewStringUTF(str.c_str());
    return env->NewStringUTF("Hello World C   style !!");
}

This code compiles fine and runs well from java but as soon as I try to use the std::string version(commented) the code compiles and the dynamic library is created but on running the java code I get the following error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\Users\aurok\eclipse-workspace\native_cpp\Debug\libnative_cpp.dll: Can't find dependent libraries
    at java.base/jdk.internal.loader.NativeLibraries.load(Native Method)
    at java.base/jdk.internal.loader.NativeLibraries$NativeLibraryImpl.open(NativeLibraries.java:383)
    at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:227)
    at java.base/jdk.internal.loader.NativeLibraries.loadLibrary(NativeLibraries.java:169)
    at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2383)
    at java.base/java.lang.Runtime.load0(Runtime.java:746)
    at java.base/java.lang.System.load(System.java:1857)
    at test_strings.TestString.<clinit>(TestString.java:6)

I have searched various sources for a possible explanation but couldn't find one. Guys, help me!

CodePudding user response:

<string> is a header file, and if your C code containing #include <string> directive compiles this means that paths of standard include folders are configured correctly.

However, depending on how your project is configured to be linked to the C and C runtime libraries (statically or dynamically), the resulting executable may or may not depend on additional DLLs. (For example, in case of Microsoft Visual Studio 2019 C compiler, the C runtime library DLL is vcruntime140.dll and C runtime library DLL is msvcp140.dll.)

Using std::string probably causes your executable to depend on the C runtime library DLL (in addition to the C runtime DLL), and perhaps it is not found in the same folder as the executable (and not in the DLL search path).

On Windows, C runtime DLL is often already available system-wide, but C runtime DLL needs to be either installed (using the Microsoft Visual C Redistributable package) or placed into the same folder along the executable itself.

Another option is to link runtime libraries statically, so the resulting executable won't have those DLL dependencies. But usually, dynamic linking is preferred.

Note that depending on which C compiler you are using with your Eclipse IDE — either GCC (G ), Clang, MSVC or some another — the required C runtime DLL will have a different filename.

CodePudding user response:

Thanks a lot heap underrun for your answer. I finally figured out a way to make it work. I used the Dependencies tool by lucasg and found that libgcc_s_seh-1.dll and libstdc -6.dll were missing even though they are present in MinGW bin.

So I explicitly added them in the same folder as my dynamic library and loaded them in the java virtual environment. This is how the java side looks now:

package test_strings;

import java.io.IOException;

public class TestString {
    
    static {
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libwinpthread-1.dll");
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libgcc_s_seh-1.dll");
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libstdc  -6.dll.dll");
        System.load("C:\\Users\\aurok\\eclipse-workspace\\native_cpp\\Debug\\libnative_cpp.dll");
    }
    
    public native String sayHelloC();
    public native String sayHelloCpp();

    public static void main(String[] args) {
        
        TestString test = new TestString();
        
        System.out.println(test.sayHelloC());
        System.out.println(test.sayHelloCpp());

    }

}

NOTE: The order in which the dlls are loaded is important. It won't work in any another order.

  • Related