How to resolve UnsatisfiedLinkError when using JNI with packages? - java

Firstly, my example has the following directory structure:
Sample.c
lib/
mypackage/
--Sample.java
Sample.java in mypackage looks like this:
package mypackage;
public class Sample {
public static native int sampleMethod(int x);
public static void main(String[] args) {
System.loadLibrary("Sample");
System.out.println("sampleMethod result: " + sampleMethod(5));
}
}
I run javac mypackage/Sample.java to compile the java file and javah mypackage.Sample to generate the JNI headers. Then I compile the library using the following command:
clang -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/darwin" -o lib/libSample.so -shared Sample.c
At this point the directory structure looks like this:
Sample.c
mypackage_Sample.h
lib/
--libSample.so
mypackage/
--Sample.java
--Sample.class
Now when I try to run the example using java -Djava.library.path=./lib/ mypackage.Sample I get the following error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no Sample in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at mypackage.Sample.main(Sample.java:7)
I tried specifying the full path to lib/, but I get the same error.
I am not sure if the code for the header and the implementation matter, but I will post them anyway.
mypackage_Sample.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class mypackage_Sample */
#ifndef _Included_mypackage_Sample
#define _Included_mypackage_Sample
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: mypackage_Sample
* Method: sampleMethod
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_mypackage_Sample_sampleMethod
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
Sample.c:
#include "mypackage_Sample.h"
#include <stdio.h>
JNIEXPORT jint JNICALL Java_mypackage_Sample_sampleMethod
(JNIEnv * env, jclass obj, jint num) {
return num * num;
}
I run this on OS X Yosemite 10.10.5 using clang 7.0.2 and java 1.8.0_101.

It looks like you have the wrong name from your library file (libSample.so).
If you use:
System.loadLibrary("Sample");
The JVM will map this name to a platform specific file name to try and load. On Linux that is libSample.so, on Windows that is Sample.dll, but on OS X it's something else.
You can find out which name your library file should have by looking at the output of:
System.mapLibraryName("Sample");
Called on the target platform.
After that, you can use that as the name of your library file.

Related

JVM exits without any error messages when loading compiled DLL

I'm trying to call a c function from Java.
When loading the library (in Test.java) 2 things happen randomly:
"Load Lib" gets printed, and the jvm just exits without any errors
"Load Lib" gets printed, and the jvm gets stuck in a loop
The weird thing is that 'sometimes' "Lib loaded" gets printed too. Which means the library got loaded...
My question is that how can I fix this? The real problem is that I don't know what I'm doing wrong.
Dll compilation steps:
gcc -fpic -I "C:\Program Files\Java\jdk-15\include" -I "C:\Program Files\Java\jdk-15\include\win32" -c BindLib.c BindLib.h
gcc -fpic -s -shared -o BindLib.dll BindLib.o
System info:
Windows 10 64 bit, version 1909
Java 15
Main file:
package degubi;
public final class Main {
public static void main(String[] args) {
Test.enable();
}
}
Library file:
package degubi;
public class Test {
static {
System.out.println("Load lib");
System.loadLibrary("BindLib");
System.out.println("Lib loaded");
}
public static native void enable();
}
Source file:
#include "windows.h"
#include "BindLib.h"
JNIEXPORT void JNICALL Java_degubi_Test_enable(JNIEnv* env, jclass clazz) {
}
Header file:
#define __int64 long long
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class degubi_Test */
#ifndef _Included_degubi_Test
#define _Included_degubi_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: degubi_Test
* Method: enable
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_degubi_Test_enable(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
Which shell and C compiler were you using?
The problem might come from the incompatible between C compiler & the shell environment.
For example, if you use Cygwin compiler to compile the DLL, then execute the binary on Windows CMD, the program might not work (dependencies on cygwin.dll).
I ended up creating a project in Visual Studio and building it from there... worked perfectly. Still don't know what caused the issue.

Java not loading dependent libraries

I am trying to use JNI for the first time but when I run my java program I keep on getting an UnsatisfiedLinkError. The error says that it can't find my dependent libraries. I did see the question JNI Hello World Unsatisfied Link Error but their recommendations did not work. As a side-note I don't own microsoft visual studio and I'm running on windows 10.
I am using the following commands in order to compile and run my program:
javac HelloWorld.java
javah HelloWorld
gcc -Wl,--add-stdcall-alias -I"C:/Program Files/Java/jdk1.8.0_91/include" -I"C:/Program Files/Java/jdk1.8.0_91/include/win32" -shared -o HelloWorld.dll HelloWorld.c
java -Djava.library.path=. HelloWorld
Source Code:
Java Source (HelloWorld.java):
public class HelloWorld {
static {
System.loadLibrary("HelloWorld");
}
private static native void sayHello();
public static void main(String[] args) {
sayHello();
}
}
Generated header file (HelloWorld.h):
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */
#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloWorld
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloWorld_sayHello
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
C file (HelloWorld.c):
#include <jni.h>
#include <stdio.h>
#include "HelloWorld.h"
JNIEXPORT void JNICALL Java_HelloWorld_sayHello(JNIEnv *env, jclass cls) {
printf("C says hello!");
}
Take a look here for a simple HelloWorld sample:
https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo001
(Linux/OSX).
In case you want to use shared library, make sure JVM can see it. You can use: "-Djava.library.path=" or you should make sure library is on LD_LIBRARY_PATH.

JNI UnsatisfiedLinkError without wrong method names and with library path specified

I'm trying to work build my very first JNI application, following this tutorial: https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
Problem Summary: While running my application, I get an java.lang.UnsatisfiedLinkError error.
First I wrote the Class HelloJNI.java:
public class HelloJNI {
static {
System.loadLibrary("hello"); // Load native library at runtime
// hello.dll (Windows) or libhello.so (Unixes)
}
// Declare a native method sayHello() that receives nothing and returns void
private native void sayHello();
// Test Driver
public static void main(String[] args) {
new HelloJNI().sayHello(); // invoke the native method
}
}
This class I compiled with:
javac HelloJNI.java
Next I ran javah HelloJNI
This produced the following file HelloJNI.h:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */
#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: HelloJNI
* Method: sayHello
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_HelloJNI_sayHello
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
Next I implemented HelloJNI.c:
#include <jni.h>
#include <stdio.h>
#include "HelloJNI.h"
// Implementation of native method sayHello() of HelloJNI class
JNIEXPORT void JNICALL Java_HelloJNI_sayHello(JNIEnv *env, jobject thisObj) {
printf("Hello World!\n");
return;
}
Finally I compiled the c class:
gcc -I"/usr/lib/jvm/java-8-oracle/include" -I"/usr/lib/jvm/java-8-oracle/include/linux" -c -Wall -Werror -fpic HelloJNI.c
gcc -shared -o hello.so HelloJNI.o
This produces the files hello.so and HelloJNI.o. Next I try to run the code:
java -Djava.library.path=. HelloJNI
This produces the error:
Exception in thread "main" java.lang.UnsatisfiedLinkError: no hello in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1864)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at HelloJNI.(HelloJNI.java:3)
This seems to be the most common JNI error on the internet... My method names seem to be correct. I also ran:
nm hello.so | grep say
This gives me: 00000000000006b0 T Java_HelloJNI_sayHello which seems to be correct, i.e. the compiler didn't add additional characters. I simply ran out of ideas of things I could try. Any suggestions?
My OS: Linux Mint 13, GCC version 4.7.3, java version 1.8.0_60
==========UPDATE===============
When I replace System.loadLibrary("hello"); by System.load("/usr0/home/jkinable/workspace/javaIDEA/jnitest/hello.so"); my HelloWorld example works! However, I don't want to use an absolute path so I'm still looking for a way to use System.loadLibrary("hello"); instead? Any suggestions? I've also tried running on a different linux system, but I get the same issue.
It turns out that the problem is due to some naming convention on unix/linux platforms! When using:
System.loadLibrary("hello");
the file should not be named hello.so! Instead, the name should be libhello.so. On Windows, use hello.dll. I'm surprised that this issue is not mentioned in IBM's JNI tutorial: http://www.ibm.com/developerworks/java/tutorials/j-jni/j-jni.html
I'm not sure what the rationality behind this issue is. Why would you load a library "hello" which should be named libhello.so on your filesystem (instead of hello.so)?

vc++ JNI error LNK2019: unresolved external symbol

Good day.
I'm trying to compile a library for use it in Java. But getting the error "error LNK2019: unresolved external symbol". In c ++ I do not much understand, ask for help.
Begin cpp file
//ftrJavaScanAPI.cpp : Defines the entry point for the DLL application.
//
#ifdef _WINDOWS
#pragma warning (disable:4996)
#endif
#include "C:\ftrJavaScanAPI\ftrScanAPI.h"
#include "ftrJavaScanAPI.h"
#ifdef FTR_OS_UNIX
#include <string.h>
#endif
FTRHANDLE hDevice = NULL;
FTRSCAN_IMAGE_SIZE m_ImageSize;
FTR_DWORD m_dwErrCode = 0;
#ifdef _WINDOWS
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
#endif
JNIEXPORT jboolean JNICALL Java_com_Futronic_ScanApiHelper_Scanner_OpenDevice(JNIEnv *env, jobject obj)
{
hDevice = ftrScanOpenDevice();
if( hDevice == NULL )
return JNI_FALSE;
return JNI_TRUE;
}
Begin .h file:
#include <C:\Program Files\Java\jdk1.7.0_05\include\jni.h>
/* Header for class com_Futronic_ScanApiHelper_Scanner */
#ifndef _Included_com_Futronic_ScanApiHelper_Scanner
#define _Included_com_Futronic_ScanApiHelper_Scanner
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_Futronic_ScanApiHelper_Scanner
* Method: OpenDevice
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_Futronic_ScanApiHelper_Scanner_OpenDevice
(JNIEnv *, jobject);
Error on Debug
1>ftrJavaScanAPI.obj : error LNK2019: unresolved external symbol ftrScanOpenDevice referenced in function Java_com_Futronic_ScanApiHelper_Scanner_OpenDevice
I understand that it is necessary add code to export some symbols from the DLL so that an export library, but do not know how to do it
What are you linking into your DLL. Your source files don't contain function 'ftrScanOpenDevice' make sure you add appropriate .LIB file to your build.
Before you introduce the complexities of DLL. Make you can compile and run this simple program:
#include "C:\ftrJavaScanAPI\ftrScanAPI.h"
int main ()
{
FTRHANDLE hDevice = ftrScanOpenDevice();
}
Make sure you can compile this and produce EXE file. Also, your executable should run without an error. It should not produce any output. If get you errors regarding DLL files not found, make sure you have appropriate DLL files available in your path or in the same directory that contains your EXE file. Also, make sure you have the same DLLs available for your final JNI program.
One more thing, you shouldn't hard code the absolute names for your include files. Use Visual Studio settings to add 'FTRScanAPI' to your include and library paths. So your include directive should be just
#include "ftrScanAPI.h"

Call C from Android using JNI with only a C shared library and header file

Android Studio 0.3.1
Hello,
I have the following library written in C but don't have the source code for it only the libapp_module.so
libapp_module.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
I have the header file for this library:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _WIN32
#define LIB_API(type) __declspec(dllexport) type
#else
#define LIB_API(type) type
#endif
LIB_API(int) module_init();
#ifdef __cplusplus
}
#endif
The problem is the exception when I try and call the function from my Android App:
D/dalvikvm﹕ Added shared lib /data/app-lib/com.sunsystems.snaptest-1/libapp_module.so 0x416f3d88
D/dalvikvm﹕ No JNI_OnLoad found in /data/app-lib/com.sunsystems.snaptest-1/libapp_module.so 0x416f3d88, skipping init
W/dalvikvm﹕ No implementation found for native Lcom/sunsystems/snaptest/App_Module;.module_init:()I
UnsatisfiedLinkError: Native method not found: com.sunsystems.snaptest.App_Module.module_init:()I
This is what I am doing
I have created a Android App and I want to call that module_init() from my App so I have created a class called App_Module.java
public class App_Module {
/* Load native C libraries */
static {
System.loadLibrary("app_module");
}
public native static int module_init();
}
And I used JNI like this in my root of the project:
javah -jni -classpath build/classes/debug -d jni/ com.sunsystems.snaptest.App_Module
Which generated the following header interface:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_sunsystems_snaptest_App_Module */
#ifndef _Included_com_sunsystems_snaptest_App_Module
#define _Included_com_sunsystems_snaptest_App_Module
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_sunsystems_snaptest_App_Module
* Method: module_init
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_com_sunsystems_snaptest_App_Module_module_1init
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
Then in my Android App I load the library in the above App_Module class and call it like this:
App_Module.module_init()
So I guess it cannot find symbol inside the libapp_module.so library.
Many thanks for any suggestions,
You have to implement the native method and make it call the function in your library. For example:
#include "header_file_for_your_library.h"
#include "com_sunsystems_snaptest_App_Module.h"
JNIEXPORT jint JNICALL Java_com_sunsystems_snaptest_App_Module_module_1init(JNIEnv *env, jclass klass) {
return module_init();
}
Just about any tutorial on JNI or Android NDK will have further details.

Categories