gary-rowe / hid4java

A cross-platform Java Native Access (JNA) wrapper for the libusb/hidapi library. Works out of the box on Windows/Mac/Linux.
MIT License
223 stars 70 forks source link

Support RPi OS "bullseye" aarch64; support old glibc versions #150

Open Masterxilo opened 1 month ago

Masterxilo commented 1 month ago

Is your feature request related to a problem? Please describe. First of all, thanks for creating this; very close to what I am looking for.

I just started playing around with this trying to get rid of some native code (a C REST server and a JNI shared library) which is using libusb/hidapi-0.14.0 directly and implements higher-level functionality on top of our custom inhouse HID report format protocol (exchange of 64 byte reports with a custom device).

It works out of the box on Windows 10 x64 and Ubuntu 22.04 which are my dev environments. Unfortunately my target is RPi (Raspberry Pi) OS buster, armhf (yes it's a bit old... it's out in the field, tricky to update...). My other rpi target is rpi bullseye (bookworm works) on aarch64 architecture and this is the one that's making problems.

Describe the solution you'd like

Describe alternatives you've considered I imagine it might be a JNA issue, but I really only care about doing USB HID, these technicalities are just a (necessary...) evil, so I reported my issue here where I see it.

Possible alternatives:

I would prefer a community effort where a solution is included in the next maven central release of this library for everyone to benefit from. I see no reason this library should not be as backwards-compatible as possible. I would like to help, but I need to be pointed into the right direction. I am familiar with make, cmake, gcc (vaguely with glibc and incompatibilities there...) and JNI, but not JNA or how this library handles the low-level stuff.

Additional context right now I only have access to an RPi 4 running bullseye aarch64, but I expect the same problem on the even older platform:

system information:

pi@usbmux1:~ $ cat /sys/firmware/devicetree/base/model
Raspberry Pi 4 Model B Rev 1.5
pi@usbmux1:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye
pi@usbmux1:~ $ uname -m
aarch64
pi@usbmux1:~ $ ldd --version ldd
ldd (Debian GLIBC 2.31-13+rpt2+rpi1+deb11u5) 2.31
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
pi@usbmux1:~ $ java -version
openjdk version "11.0.23" 2024-04-16
OpenJDK Runtime Environment (build 11.0.23+9-post-Debian-1deb11u1)
OpenJDK 64-Bit Server VM (build 11.0.23+9-post-Debian-1deb11u1, mixed mode)

observed behavior:

pi@usbmux1:~ $ java -cp hid4java-test-1.0-SNAPSHOT-jar-with-dependencies.jar -ea org.example.Main
Hello and welcome!
2024-05-24T21:01:47.644892Z main WARN Runtime environment or build system does not support multi-release JARs. This will impact location-based features.
2024-05-24T23:01:47,635 INFO  [main] org.example.Main - Hello and welcome!
Exception in thread "main" java.lang.ExceptionInInitializerError
        at org.example.Main.main(Main.java:22)
Caused by: org.hid4java.HidException: Hidapi did not initialise: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by /home/pi/.cache/JNA/temp/jna512391573883764077.tmp)
        at org.hid4java.HidDeviceManager.<init>(HidDeviceManager.java:87)
        at org.hid4java.HidServices.<init>(HidServices.java:81)
        at org.hid4java.HidManager.getHidServices(HidManager.java:72)
        at org.example.tihidapi.impl.hid4java.TiHidSessionFactoryHid4JavaImplementation.<clinit>(TiHidApiSessionFactoryHid4JavaImplementation.java:25)
        ... 1 more
Caused by: java.lang.UnsatisfiedLinkError: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by /home/pi/.cache/JNA/temp/jna512391573883764077.tmp)
        at com.sun.jna.Native.open(Native Method)
        at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:300)
        at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:481)
        at com.sun.jna.Library$Handler.<init>(Library.java:197)
        at com.sun.jna.Native.load(Native.java:618)
        at com.sun.jna.Native.load(Native.java:592)
        at org.hid4java.jna.HidrawHidApiLibrary.<clinit>(HidrawHidApiLibrary.java:37)
        at org.hid4java.jna.HidApi.init(HidApi.java:123)
        at org.hid4java.HidDeviceManager.<init>(HidDeviceManager.java:84)

this is just a simple example application that tries to init hid4java and open a device and talk to it a bit.

Masterxilo commented 1 month ago

I am looking at https://github.com/gary-rowe/hid4java/wiki/How-to-set-up-cross-compilation-of-hidapi-using-Docker and I could probably help provide a build of libhidapi.so for armhf, which I see is missing in https://github.com/gary-rowe/hid4java/tree/hid4java-0.8.0/src/main/resources

but it seems from the stacktrace that there is an issue that appears even before the libhidapi shared library is even loaded... What would be required to make this work?

gary-rowe commented 1 month ago

It does appear that you're seeing a linking error due to a missing library for libc which is unusual - perhaps a path issue?

Before embarking on support for armhf have a read of issue #118 and PR #119.

Masterxilo commented 5 days ago

Thanks for your feedback @gary-rowe. I picked this up again, as getting a better hid solution working on rpi buster 32 bit to run is quite crucial for our usecase.

When I wrote this issue I had actually only tested it on bullseye 64 bit which reproducibly produces the problem above. I had foolishly assumed that this would imply it won't work on 32 bits and the older buster (buster < bullseye < bookworm) rpi os either...

However, it turns out that on the older buster rpi OS with 32 bits (armhf/armv7l) hid4java actually works out of the box which is very good news for us.

So actually, the problem only exists on aarch64/bullseye. I checked that JNA works fine on all the platforms I care about (rpi buster+, 23 & 64 bit arm), it really seems the only issue is that the libhidapi*.so included in hid4java/linux-aarch64 are built against an unnecessarily recent glibc (inconsistent with the glibc version required by the arm 32 bit which is an earlier version):

Running ldd on the .so on aarch64 bullseye shows the problem

pi@miniSTA-IV-opK:~/hid4java-0.8.0/linux-aarch64 $ ldd *.so
libhidapi-libusb.so:
./libhidapi-libusb.so: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./libhidapi-libusb.so)
        linux-vdso.so.1 (0x0000007f81f8e000)
        libusb-1.0.so.0 => /lib/aarch64-linux-gnu/libusb-1.0.so.0 (0x0000007f81eff000)
        libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007f81d8a000)
        libudev.so.1 => /lib/aarch64-linux-gnu/libudev.so.1 (0x0000007f81d53000)
        libpthread.so.0 => /lib/aarch64-linux-gnu/libpthread.so.0 (0x0000007f81d22000)
        /lib/ld-linux-aarch64.so.1 (0x0000007f81f5e000)
libhidapi.so:
./libhidapi.so: /lib/aarch64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found (required by ./libhidapi.so)
        linux-vdso.so.1 (0x0000007fbab68000)
        libudev.so.1 => /lib/aarch64-linux-gnu/libudev.so.1 (0x0000007fbaace000)
        libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000007fba959000)
        libpthread.so.0 => /lib/aarch64-linux-gnu/libpthread.so.0 (0x0000007fba928000)
        /lib/ld-linux-aarch64.so.1 (0x0000007fbab38000)

FWIW, I have created some minimal example projects for the two libraries in case someone wants to try this on other platforms:

Masterxilo commented 5 days ago

So I think the solution would indeed be to provide builds of the aarch64 .so built against older glibc, correct?

I am actually not sure how forward compatibility of the dynamic glibc library dependency is ensured, but it seems it's a given?

Masterxilo commented 5 days ago

After doing a bit more research, I think switching from dockcross/linux-arm64 to dockcross/linux-arm64-lts mit solve the problem as the latter depends on an older version of libc

https://github.com/gary-rowe/hid4java/blob/develop/build-hidapi.sh image

https://github.com/dockcross/dockcross?tab=readme-ov-file#summary-cross-compilers image

is there any reason not to use the -lts version of all the cross-compilers?


I think it would be awesome if this low-level library had such great compatibility like https://github.com/usb4java/usb4java which we have been using for years (last release from 6 years ago still working fine). I think this project would also deserve to be at hid4java/hid4java and hid4java.org.