Skip to content
Advertisement

How to fix a java.lang.UnsatisfiedLinkError for JSSC? (Needs hard float?)

I have a Java application in a JAR that needs to communicate via serial using JSSC (On Ubuntu in a SOPine board). It is throwing the following java.lang.UnsatisfiedLinkError exception:

Exception in thread "CommThread" java.lang.UnsatisfiedLinkError: /root/.jssc/linux/libjSSC-2.7_armsf.so: /root/.jssc/linux/libjSSC-2.7_armsf.so: cannot open shared object file: No such file or directory
    at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
    at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2430)
    at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2487)
    at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
    at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2617)
    at java.base/java.lang.Runtime.load0(Runtime.java:767)
    at java.base/java.lang.System.load(System.java:1831)
    at jssc.SerialNativeInterface.<clinit>(SerialNativeInterface.java:172)
    at jssc.SerialPort.<init>(SerialPort.java:118)
    at com.company.comm.transport.serial.CommSerial.initialize(CommSerial.java:51)
    at com.company.product.adapters.comm.Communicator.connect(Communicator.java:73)
    at com.company.product.services.comm.CommThread.run(CommThread.java:18)

TL;DR: Skip to the answer if you don’t want to read several day’s worth of troubleshooting.


I exported my JAR file in Eclipse with the jssc.jar added to the project’s Java Build Path’s Libraries in the Classpath and its included in the exported entries.

I did confirm that the file libjSSC-2.7_armsf.so is there:

sudo ls –la /root/.jssc/linux/
drwxr-xr-x 2 root root  4096 Sep 23 14:41 .
drwxr-xr-x 3 root root  4096 Sep 20 15:39 ..
-rw-r--r-- 1 root root 10539 Sep 20 15:39 libjSSC-2.7_armsf.so

The closest answer to my issue that I can find is the Stack Overflow question unsatisfied link error runnable jar referencing jssc library. I confirmed that the SOPine board I’m using has a VFPv4 Floating Point Unit, contains the directory /lib/arm-linux-gnueablhf/, and I have the JDK bellsoft-java11:armhf (From dpkg -l) installed, so I am not clear on why it is using libjSSC-2.7_armsf.so instead of libjSSC-2.7_armhf.so, which is in the same jssc.jar.

I tried adding libjSSC-2.7_armhf.so to the /root/.jssc/linux/ directory, installing libjssc-java to linux, and modifying LD_LIBRARY_PATH and -Djava.library.path to point to another directory, but it throwing the same exception that it cannot locate libjSSC-2.7_armsf.so.

I’m using the following command to run the JAR file with the pine user:

sudo java -jar product-0.1.0.jar &> output-0.1.0_1.txt

Edit 10/2/2019: I tried to change the JSSC shared library it’s using by deleting the libjSSC-2.7_armsf.so, installing jssc locally using sudo apt install libjssc-java, and using LD_LIBRARY_PATH and -Djava.library.path to focus my program at running the new library, but it is still asking for libjSSC-2.7_armsf.so. I’m going to configure the Eclipse project to not package the JSSC JAR file with my project’s exported JAR file and try running it again.

Edit 10/7/2019: Last week, I decided to create a simple HelloSerial.java program to reduce potential dependencies. The code is below:

import jssc.SerialPortList;

public class HelloSerial {

    static {
        System.out.println("HelloSerial: loading JSSC");
        try {
            System.load("/root/.jssc/linux/libjSSC-2.7_armhf.so");
            System.out.println("HelloSerial: loading JSSC");
        } catch (UnsatisfiedLinkError e) {
            System.err.println("Native core library failed to load.n" + e);
            System.exit(1);;
        }
    }

    public static void main(String[] args) {
        System.out.println("HelloSerial: start");

        String[] portNames = SerialPortList.getPortNames();
        System.out.println("HelloSerial: listing " + portNames.length + " port names");
        for(int i = 0; i < portNames.length; i++){
            System.out.println(portNames[i]);
        }

        System.out.println("HelloSerial: end");
    }
}

Here is the output from compiling and running it within the Linux system:

$ sudo javac -classpath .:jssc.jar HelloSerial.java
$ sudo java -cp jssc.jar:. HelloSerial
HelloSerial: loading JSSC
HelloSerial: loading JSSC
HelloSerial: start
Exception in thread "main" java.lang.UnsatisfiedLinkError: /root/.jssc/linux/libjSSC-2.7_armsf.so: /root/.jssc/linux/libjSSC-2.7_armsf.so: cannot open shared object file: No such file or directory
    at java.base/java.lang.ClassLoader$NativeLibrary.load0(Native Method)
    at java.base/java.lang.ClassLoader$NativeLibrary.load(ClassLoader.java:2430)
    at java.base/java.lang.ClassLoader$NativeLibrary.loadLibrary(ClassLoader.java:2487)
    at java.base/java.lang.ClassLoader.loadLibrary0(ClassLoader.java:2684)
    at java.base/java.lang.ClassLoader.loadLibrary(ClassLoader.java:2617)
    at java.base/java.lang.Runtime.load0(Runtime.java:767)
    at java.base/java.lang.System.load(System.java:1831)
    at jssc.SerialNativeInterface.<clinit>(SerialNativeInterface.java:172)
    at jssc.SerialPortList.<clinit>(SerialPortList.java:43)
    at HelloSerial.main(HelloSerial.java:20)

Even though I’m explicitly using System.load to load the hard float version of the shared library, it is still defaulting to try using the soft float. What could be forcing it to use the soft float version? All of the libraries, including the JDK, are using either armhf, arm64, or all in dpkg -l.

Edit 10/8/2019: I found that JSSC uses logic in its SerialNativeInterface class to determine which shared library to use (This is just showing the relevant lines of code):

79  static {
80      String libFolderPath;
81      String libName;
82
83      String osName = System.getProperty("os.name");
84      String architecture = System.getProperty("os.arch");
85      String userHome = System.getProperty("user.home");
86      String fileSeparator = System.getProperty("file.separator");
87      String tmpFolder = System.getProperty("java.io.tmpdir");
...
118     else if(architecture.equals("arm")) {//since 2.1.0
119         String floatStr = "sf";
120 >>>>    if(javaLibPath.toLowerCase().contains("gnueabihf") || javaLibPath.toLowerCase().contains("armhf")){
121             floatStr = "hf";
122         }
123         else {
...
139         }
140         architecture = "arm" + floatStr;
141     }
142
143     libFolderPath = libRootFolder + fileSeparator + ".jssc" + fileSeparator + osName;
144     libName = "jSSC-" + libVersion + "_" + architecture;
145     libName = System.mapLibraryName(libName);

The important part is on line 120, where the ARM’s library is choosen be soft float or hard float based on whether the java.library.path includes a gnueabihf or armhf path. Including the following line of code shows those paths:

System.out.println("HelloSerial: java.library.path " + System.getProperty("java.library.path"));

This outputted:

HelloSerial: java.library.path /usr/java/packages/lib:/lib:/usr/lib

It looks like gnueabihf or armhf paths like /lib/gnueabihf aren’t being used, so I need to add one as a placeholder.

Using sudo java -D.java.library.path=".:/lib/gnueabihf" -jar HelloSerial-1.0.0.jar works.

I’ll see if I can permanently add /lib/gnueabihf to java.library.path in the future.

Advertisement

Answer

JSSC uses logic in its SerialNativeInterface class to determine which shared library to use. For OS’s with ARM architecture, it checks the java.library.path to see if it contains gnueabihf or armhf in the paths. If not, it will use the soft float shared library instead.

My current java.library.path doesn’t contain either, so I added the existing /lib/gnueabihf directory to the path using the following command:

$ sudo java -D.java.library.path=".:/lib/gnueabihf" -jar HelloSerial-1.0.0.jar

There are other ways to load a path that are listed in this article or you can search online for that info. You can use $ java -XshowSettings:properties to confirm that it is included in the java.library.path.

User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement