I am trying to use a package in my final year project called libfprint. This is an opensource fingerprint reader SDK. I am doing my project in Java so I need to port over the libfprint functionality.
A stroke of good luck hit me and turned out somebody already did this. A package called jlibfprint is a JNI wrapper for libfprint.
So I followed the instructions in both jlibfprint and libfprint for setup. libfprint more or less works fine. As for jlibfprint, when I tried to run the sample program I got,
Exception in thread "main" java.lang.UnsatisfiedLinkError: no JlibFprint_jni in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1681)
at java.lang.Runtime.loadLibrary0(Runtime.java:840)
at java.lang.System.loadLibrary(System.java:1047)
at JlibFprint.<clinit>(JlibFprint.java:28)
at SampleRun.main(SampleRun.java:30)
JlibFprint.(JlibFprint.java:28)
is referring to
static {
System.loadLibrary("JlibFprint_jni");
}
So now I'm looking through the project properties and get to the field "Native library location", and I point it to the directory containing a single file called libJlibFprint_jni.so.
Now when I run the program, the error I get is,
Exception in thread "main" java.lang.UnsatisfiedLinkError: JlibFprint.enroll_finger()LJlibFprint$fp_print_data;
at JlibFprint.enroll_finger(Native Method)
at SampleRun.main(SampleRun.java:36)
Enroll the first finger...
Here are the sample Java file
SampleRun.java
public class SampleRun {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
JlibFprint jlibfprint = new JlibFprint();
JlibFprint.fp_print_data pd1, pd2;
int matchValue;
try
{
System.out.println("Enroll the first finger...");
pd1 = jlibfprint.enroll_finger();
System.out.println("Compare the previous acquisition with the next one...");
pd2 = jlibfprint.enroll_finger();
matchValue = JlibFprint.img_compare_print_data(pd1, pd2);
System.out.println(matchValue);
if (matchValue > JlibFprint.BOZORTH_THRESHOLD)
{
System.out.println("[OK] The two fingerprints are compatible!");
}
else
{
System.out.println("[FAIL] The two fingerprints are not compatible!");
}
}
catch (JlibFprint.EnrollException e)
{
System.err.format("Enroll Exception [%d]\n", e.enroll_exception);
e.printStackTrace();
}
}
}
I am using Ubuntu 11.10 with Eclipse Juno.
Anybody with a breeze of knowledge in this area would be a great help !
I know this is a bit late. But if you are using the eclipse for your java project then go to the Run Configurations and then go to the Arguments tab.
In the VM arguments add following line:
-Djava.library.path="${workspace_loc}/PROJECT_NAME/DIRECTORY_NAME_CONTAINIG_LIBRARY:${env_var:PATH}"
Just found the solution here. I'm sure it was obvious to some but JNI is totally new to me. The solution was:
"Create a new file in /etc/ld.so.conf.d/ called .conf
Edit the file and add a line per directory of shared libraries (*.so
files), it will look something like:
/usr/lib/APPLICATION/lib Reload the list of system-wide library paths:
sudo ldconfig"
I'm just gonna throw a few JNI related answers, feel free to downvote.
Android Java JNI and C Char array Can't recognize the value
The call needs to look like
JNIEXPORT <return type> JNICALL Java_<your_package_name>_<classname>_<methodname>(JNIEnv *env, jobject obj, ...)
so lets try it out for an example that is
package com.rtrk.demo;
public class PELib
{
public native int play(String file, String file2, blahblah);
/* ... */
}
which should look like
JNIEXPORT jint JNICALL Java_com_rtrk_demo_PELib_play(JNIEnv *env, jobject obj, jstring main_video, jstring prev_video, jint main_x, jint main_y, jint main_width, jint main_height, jint prev_x, jint prev_y, jint prev_width, jint prev_height)
This is the main root cause for UnsatisfiedLinkErrors :)
Related
I want to call this minimal dummy C program (named "TEST.c"):
extern "C"
void Java_TEST_run() {}
from this Java code (named "Example.java"):
public class Example
{
public static void main(String args[])
{
System.out.println("START");
TEST test = new TEST();
test.dll_call();
System.out.println("ALL DONE!");
}
}
class TEST
{
public void dll_call()
{
run();
}
static {
try {
System.out.println("Load DLL = start ");
System.load("/home/user/Desktop/TEST.dll");
System.out.println("Load DLL = finish ");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load.\n");
System.exit(1);
}
}
public native void run();
}
I create the C dll file by the following commands:
g++ -c TEST.c
g++ -shared -o TEST.dll TEST.o
This works all fine within the console environment, esp. I got the successful Java program execution output:
START
Load DLL = start
Load DLL = finish
ALL DONE!
Now, if I try to run the Java program from the Eclipse IDE, I got the following error:
START
Load DLL = start
Load DLL = finish
Exception in thread "main" java.lang.UnsatisfiedLinkError: 'void Example.TEST.run()'
at test1/Example.TEST.run(Native Method)
at test1/Example.TEST.dll_call(Example.java:21)
at test1/Example.Example.main(Example.java:11)
To my understanding, this means the Java program running from Eclipse does successfully find the c dll file, but when trying to enter the dll file, it fails by finding the dummy function Java_TEST_run().
As the c code "TEST.c" is already as minimal as possible, and as the execution works fine from the console, I do not understand, why it fails from Eclipse.
Can someone please advice me, how to make this minimal c code working from Java in Eclipse?
Operating system is Ubuntu 18.04 with openjdk 11.0.6 and Eclipse 4.14.0.
This is a follow up question from this question.
Any help much appreciated, thank you!
I was able to resolve the issue with Eclipse.
The C/C++ code needs to include the name of the Eclipse project, e.g. "Example", in the function name. In above code, this means:
extern "C"
void Java_TEST_run() {}
needs to be changed to:
extern "C"
void Java_Example_TEST_run() {}
I'll give you quick answer
First of all you will need JNI for c/c++ and it will generate header for your .java file.
For example, if we have class from your example we will have header output like this
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class TEST */
#ifndef _Included_TEST
#define _Included_TEST
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: TEST
* Method: run
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_TEST_run
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
You can generate this type of header by typing
javac -h . TEST.java for your given class
Last thing we have to do is create our .cpp file to add function body, you can just copy decleration from JNI generated header file
#include "TEST.h"
JNIEXPORT void JNICALL Java_TEST_run(JNIEnv * env, jobject obj){
//my very special code
}
And that would be it.
In order to add JNI to your Visual Studio (if you are using one) you will have to go to project properties and add additional include and additional library from jdk folder.
If you are using g++, add include directory of JDK and library.
I have some code written in c++ by android JNI.
in one export function
"extern "C" JNIEXPORT int JNICALL Java_com_android_mymapsforge_create(JNIEnv *env, jobject obj)
{
...
ifstream infile("C:\\Users\\li\\Documents\\Visual Studio 2010\\Projects\\importANN\\Debug\\nodes.csv");
string line;
int index = 0;
while( getline( infile, line ))
{
....
}
}
when i using those original c++ code, i test under vs2010. Either i assign the infile() parameters with a fixed file path, or using some c++ get_file_path function, it's a thing related windows system, there is no problem. both work.
But now I want to using these code under JNI using by android. So the file path system change to android and some function need be adjusted.
My problem arise: because the code is using at last by my android java code under a android app, so the "C:\Users\li\Documents\Visual Studio 2010\Projects\importANN\Debug\nodes.csv", no longer take effect, it may be change to "/mnt/sdcard/somefolder/nodes.csv"
but i have experience when i in android app give a fixed file path it tell my some error, so under android jave envi, i using below code to get file path, similar code here:
String mpath ;
mpath = Environment.getExternalStorageDirectory().getPath();
mapView.setMapFile(new File(mpath+"/"+"berlin.map"));
(omit the filename , i just want to tell the method i use)
But these android code must can not use in my c++ wrapping function Java_com_android_mymapsforge_create,
So my question is :
how to cope with the file(android system) path things under the c++ export function? For example, i put the "nodes.csv" under my sdcard root folder, and want to do some processing under the JNI exported c++ function?
The easiest way is to pass the path as an argument of the function.
extern "C" JNIEXPORT int
JNICALL Java_com_android_mymapsforge_create(JNIEnv *env, jobject, jstring path)
Then you can turn jstring path to char* using JNI converting jstring to char *.
The second way is to call Android Environment.getExternalStorageDirectory().getPath() from JNI function like described here - Call a static java method of another package from native code.
I am building a small app on a raspberry pi.
I have a JVM which tries to access a C++ Library called "RCSwitch"
I created a JavaClass
public class NativeRCSwitchAdapter {
private static final NativeRCSwitchAdapter instance = new NativeRCSwitchAdapter();
public static NativeRCSwitchAdapter getInstance(){
return instance;
}
private NativeRCSwitchAdapter(){};
static{
String path = NativeRCSwitchAdapter.class.getProtectionDomain().getCodeSource().getLocation().getPath();
System.load(path + "NativeRCSwitchAdapter.so");
}
// methods to redirect to native layer (C++)
public native void switchOn(String group, String channel);
public native void switchOff(String group, String channel);
}
I then ran javac & javah to have java generate my header file for me.
I created a c++ file:
#include "NativeRCSwitchAdapter.h"
#include "RCSwitch.h"
#include <stdio.h>
#include <iostream>
using namespace std;
JNIEXPORT void JNICALL Java_NativeRCSwitchAdapter_switchOn(JNIEnv * env, jobject obj, jstring jsGroup, jstring jsChannel ){
cout<<"teststring output"<<endl;
const char *csGroup = env->GetStringUTFChars(jsGroup, 0);
const char *csChannel = env->GetStringUTFChars(jsChannel, 0);
char sGroup[6];
char sChannel[6];
for (int i = 0; i<5; i++) {
sGroup[i] = csGroup[i];
sChannel[i] = csChannel[i];
}
sGroup[5] = '\0';
sChannel[5] = '\0';
cout<<"ONON"<<endl;
cout<<sGroup<<endl;
cout<<sChannel<<endl;
RCSwitch mySwitch = RCSwitch();
//for testing purposes set to the ELRO Power Plugs
mySwitch.setPulseLength(300);
mySwitch.enableTransmit(0);
mySwitch.setRepeatTransmit(3);
mySwitch.switchOn(sGroup, sChannel);
}
Now this file uses the RCSwitch library which in turn uses the wiringPi library.
Now if i compile i run this:
g++ -shared -I/usr/jdk1.8.0/include -I/usr/jdk1.8.0/include/linux NativeRCSwitchAdapter.cpp -o NativeRCSwitchAdapter.so
Yet I get this error if start everything from java: (simple main, create an instance of my object and run the switchOn()
java: symbol lookup error: /home/pi/applications/Pi-jAutomation433/RCSwitchJNIWrapper/src/NativeRCSwitchAdapter.so: undefined symbol: _ZN8RCSwitchC1Ev
It has been time, since i last coded in C, so please forgive me but I believe it has something to do with the the linking phase of the compiler? Or does the compiler automatically check all dependencies and then their deps until no further dependencies are found and it then links it all nicely together and wraps it in an app?
Oh here is the repo to have an in depth look if anybody cares:
Github repo
Thanks for any help coming my way!
UPDATE
Okay so I managed to get this error away. Turns out (well I kinda knew that already but yeah) I am quiet a duphus when it comes to C++ compiler knowledge. Anyways I managed to get the error changed. I didn't know I had to explicitly tell g++ to include RCSwitch.cpp as well. Okay so now I did. Next error ;-)
I guess this time it should be fairly easy to tackle. I get an undefined symbol "pinMode".
This symbol is part of the wiringPi library. Do I have to include ALL c librarys that are executed in my java file? Or only the one I access and anything after that doesnt matter to java?
Your native function declaration is getting mangled by the c++ compiler. Add extern "C" around your declarations to clear up the issue.
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
JNIEXPORT void JNICALL Java_NativeRCSwitchAdapter_switchOn(JNIEnv * env, jobject obj, jstring jsGroup, jstring jsChannel ){
#ifdef __cplusplus
}
#endif /* __cplusplus */
Edit:
You need to include all other objects/libraries into your creation of the shared library.
See this Dynamic Link Library Q/A.
I'm trying to use JNI and getting java.lang.UnsatisfiedLinkError. Unlike the other million questions asked about this, I have the lib on my path, and have even seen the exception change when I remove it. I'm sure that something is wrong with the dll I have created, but I'm not sure what.
Here is my java class code:
package com;
public class Tune {
static {
System.loadLibrary("lala");
}
public static void main(String[] args) {
Tune j = new Tune();
System.out.println("2+6="+j.add(2, 6));
}
native public int add(int x,int y);
}
Here is the abridged portion of my javah produced header file:
/*
* Class: com_Tune
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_Tune_add
(JNIEnv *, jobject, jint, jint);
Here is my c++ code:
#include <jni.h>
#include <com_Tune.h>
JNIEXPORT jint JNICALL Java_com_Tune_add
(JNIEnv * env, jobject obj, jint x, jint y) {
return x+y;
}
Here is the runtime exception I get from eclipse:
Exception in thread "main" java.lang.UnsatisfiedLinkError: com.Tune.add(II)I
at com.Tune.add(Native Method)
at com.Tune.main(Tune.java:9)
I read that the above exception means it DID find the library "lala", but that the method "add" is still not defined. The only things I see different between my project and the tutorial are:
Mine uses a package, instead of the default package (shouldn't tutorials really do this?!?! come on let's get professional)
Mine has a return value.
I moved my dll after it was created (I don't think this will break it since my path is configured.)
How is this possible?
Other Info:
OS: Windows 7
JDK: 1.6.0_31 (for x86, 32 bit jvm)
C++ IDE: Code::Blocks (the dll was compiled automatically by the Code::Blocks IDE)
C++ compiler: MinGW32-g++ (the GNU C++ compiler)
I have jni.h and com_Tune.h in C:\_\include
I have lala.dll in C:\_\lib
Environment Variables:
PATH: C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;%CommonProgramFiles%\Microsoft Shared\Windows Live;C:\Program Files (x86)\AMD APP\bin\x86_64;C:\Program Files (x86)\AMD APP\bin\x86;%SystemRoot%\system32;%SystemRoot%;%SystemRoot%\System32\Wbem;%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\ATI Technologies\ATI.ACE\Core-Static;C:\Apps;%JAVA_HOME%\bin;C:\Program Files\MySQL\MySQL Server 5.5\bin;%MAVEN_HOME%\bin;%HADOOP_INSTALL%\bin;c:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\MinGW\bin;C:\Program Files (x86)\GnuWin32\bin;C:_\path;C:\_\lib;C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin;C:\_\include
The problem is with the name compiler has generated: Java_com_Tune_add#16
Use either of two
gcc -Wl,-kill-at
Or
gcc -Wl,--add-stdcall-alias
This will ensure generation of Java_com_Tune_add
And then your method call will be successful.
One possible source of the problem might be that you compiled the code using a C++ compiler, which uses a different [calling convention] than plain C. If thats the case then the solution would be to wrap the code for the method in a extern "C" block like this:
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jint JNICALL Java_com_Tune_add
...
#ifdef __cplusplus
}
#endif
Just guessing... Is your dll depends on another dll that is not on the path? MinGW modules usually depend on specific C runtime library.
I had the same issue and the flag -Wl,-kill-at worked for me.
Try with following example for Windows:
(remember that the Java class name must be the same that corresponding file name)
Step 1. Create the following Java file (P.java):
class P
{
static
{
// "P" is the name of DLL without ".dll"
System.loadLibrary ("P");
}
public static native void f(int i);
public static void main(String[] args)
{
f(1);
}
}
Step 2. javac P.java
Step 3. javah P
Then, "javah" generates the header file "P.h"
Step 4. Create the file "P.def" including the following two lines (this file defines the exported symbols, in this case the name of C function):
EXPORTS
Java_P_f
Step 5. Create your C file (P.c):
#include "P.h"
JNIEXPORT void JNICALL Java_P_f(JNIEnv *env, jclass c, jint i)
{
printf("%i\n",i);
}
Step 6. Within Visual Studio command promt, define the following variables:
set JAVA_HOME= the path of JDK
set include=%include%;%JAVA_HOME%\include;%JAVA_HOME%\include\win32
Step 7. Generate DLL:
cl /LD P.c P.def
Step 8. Run the Java program:
java P
(Note: P.dll and P.class are located in the same directory)
How to change and update the title of the command prompt window from the java command line application? Every time I run my application, the command prompt window title shows:
C:\WINDOWS\system32\cmd.exe - java MyApp.
I'd like to change and update the window title as the java program runs, for example as wget(win32) updates downloading status in the title: Wget [12%].
Although I haven't tried it myself, in Windows, one can use the Win32 API call to SetConsoleTitle in order to change the title of the console.
However, since this is a call to a native library, it will require the use of something like Java Native Interface (JNI) in order to make the call, and this will only work on Windows 2000 and later.
Edit - A solution using JNI
The following is an example of using JNI in order to change the title of the console window from Java in Windows. To implement this, the prerequiste is some knowledge in C and using the compiler/linker.
First, here's result:
(source: coobird.net)
Disclaimer: This is my first Java application using JNI, so it's probably not going to be a good example of how to use it -- I don't perform any error-checking at all, and I may be missing some details.
The Java program was the following:
class ChangeTitle {
private static native void setTitle(String s);
static {
System.loadLibrary("ChangeTitle");
}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 5; i++) {
String title = "Hello! " + i;
System.out.println("Setting title to: " + title);
setTitle(title);
Thread.sleep(1000);
}
}
}
Basically, the title is changed every 5 seconds by calling the setTitle native method in an external native library called ChangeTitle.
Once the above code is compiled to make a ChangeTitle.class file, the javah command is used to create a C header that is used when creating the C library.
Writing the native library
Writing the library will involve writing the C source code against the C header file generated by javah.
The ChangeTitle.h header was the following:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class ChangeTitle */
#ifndef _Included_ChangeTitle
#define _Included_ChangeTitle
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: ChangeTitle
* Method: setTitle
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_ChangeTitle_setTitle
(JNIEnv *, jclass, jstring);
#ifdef __cplusplus
}
#endif
#endif
Now, the implementation, ChangeTitle.c:
#include <windows.h>
#include <stdio.h>
#include <conio.h>
#include <jni.h>
#include "ChangeTitle.h"
JNIEXPORT void JNICALL
Java_ChangeTitle_setTitle(JNIEnv* env, jclass c, jstring s) {
const jbyte *str;
str = (*env)->GetStringUTFChars(env, s, NULL);
SetConsoleTitle(str);
(*env)->ReleaseStringUTFChars(env, s, str);
};
A String that is passed into the native function is changed into an UTF-8 encoded C string, which is sent to the SetConsoleTitle function, which, as the function name suggests, changes the title of the console.
(Note: There may be some issues with just passing in the string into the SetConsoleTitle function, but according to the documentation, it does accept Unicode as well. I'm not too sure how well the code above will work when sending in various strings.)
The above is basically a combination of sample code obtained from Section 3.2: Accessing Strings of The Java Native Interface Programmer's Guide and Specification, and the SetConsoleTitle Function page from MSDN.
For a more involved sample code with error-checking, please see the Section 3.2: Accessing Strings and SetConsoleTitle Function pages.
Building the DLL
The part that turned out to take the most amount of time for me to figure out was getting the C files to compile into an DLL that actually could be read without causing an UnsatisfiedLinkError.
After a lot of searching and trying things out, I was able to get the C source to compile to a DLL that could be called from Java. Since I am using MinGW, I found a page form mingw.org which described exactly how to build a DLL for JNI.
Sources:
The Java Native Interface Programmer's Guide and Specification
Chapter 2: Getting Started - Details the process using JNI.
JNI-MinGW-DLL - Building a JNI DLL on MinGW with gcc.
This depends on your terminal emulator, but essentially it's just printing out control sequences to the console.
Now I'm not clear on what control sequences CMD.EXE responds to (I haven't one available to try this on) but I hear there's a command called TITLE which sets the title of the window. I tried piping TITLE's output to a file, but apparently, it doesn't actually set the title by outputting control characters. The START command can take a parameter which is title of the window followed by the command to run in the window. So something like
cmd TITLE "lovely Application that is in a command window." && "java" MyApp
REM or
start "lovely Application that is java based." java MyApp
Personally I would just bundle the whole thing with a shortcut where you can edit the properties such as the current directory, the command, it's parameters, and the window size, style and title (if I remember rightly). Give it a nice icon and people will use it.
Here's my solution using JNA:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class SetTitle {
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)
Native.loadLibrary((Platform.isWindows() ? "kernel32" : "c"),
CLibrary.class);
boolean SetConsoleTitleA(String title);
}
public static void main(String[] args) {
CLibrary.INSTANCE.SetConsoleTitleA("Testing 123");
System.exit(0);
}
}
You can use the CLITools Java library
following dlamblin's revelation ;-)
here's a python code.
note that there are 2 different commands in most programming languages:
system
exec
system will issue a system command, exec indeed spawns a new process. thus:
C:\>python
>>> import os
>>> os.system("title berry tsakala")
which works inside a running program. Just find the java equivalent.