abcminiuser / python-elgato-streamdeck

Python library to control the Elgato Stream Deck.
Other
874 stars 128 forks source link

The LibUSB locating code is looking up the wrong library name on linux according to documentation and fails on Debian 12+ #120

Closed cpw closed 7 months ago

cpw commented 10 months ago

Describe the bug I'm getting the dreaded ('Probe failed to find any functional HID backend.', {'libusb': FileNotFoundError(2, 'No such file or directory')}) error.

To Reproduce Unclear how to reproduce, but I'm running a pretty vanilla debian 12 (sid) setup. It's reliably failing here.

StreamDeck Information StreamDeck XL (gen 1?)

System Information I'm using 0.9.4 of the library, included with the streamdeck-ui package from streamdeck-linux-gui.

I have

libhidapi-libusb0:
  Installed: 0.14.0-1
  Candidate: 0.14.0-1

installed, and the streamdeck is 100% readable from the local user (no permission problems).

The issue is here: https://github.com/abcminiuser/python-elgato-streamdeck/blob/87f4f0fb24272f3d3ec51cdc446a4aeacafe6dce/src/StreamDeck/Transport/LibUSBHIDAPI.py#L145

The python (and linux) standard is not to include the word "lib" at the front of the library name. See: https://github.com/python/cpython/issues/86746, https://docs.python.org/dev/library/ctypes.html#ctypes.util.find_library and other sources (as you can see, there's some ridiculous gcc voodoo going on behind the scenes).

I have no idea how this has ever worked to be honest - this seems to have been the standard in linux world for at least the past 20 years or so (omitting the "lib" prefix).

Anyway, the fix I have tested locally works great - remove the "lib" prefix and everything works again.

Example from my python console tests:

python
Python 3.11.5 (main, Aug 29 2023, 15:31:31) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ctypes.util
>>> ctypes.util.find_library("libhidapi-libusb")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.11/ctypes/util.py", line 341, in find_library
    _get_soname(_findLib_gcc(name)) or _get_soname(_findLib_ld(name))
                ^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ctypes/util.py", line 147, in _findLib_gcc
    if not _is_elf(file):
           ^^^^^^^^^^^^^
  File "/usr/lib/python3.11/ctypes/util.py", line 99, in _is_elf
    with open(filename, 'br') as thefile:
         ^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: b'liblibhidapi-libusb.a'
>>> ctypes.util.find_library("hidapi-libusb")
'libhidapi-libusb.so.0'
>>> 

As you can see, looking for the name as you specify it fails, but without the "lib" prefix, works great. As far as I can tell, this has been how it should have worked for a LONG time, so removing the lib prefix shouldn't break compatibility across a wide range of versions.

brimston3 commented 10 months ago

It "works" because the result to ctypes.util.find_library() is not used and "libhidapi-libusb.so.0" is passed through to ctypes.cdll.LoadLibrary() directly. Either way there should be exception handling around find_library() because it can except. I don't generate the exception with find_library() on debian12 so I'm not sure the difference between our configurations.

edit: after looking into it a little more, the exception consistently happens when you have the static library libhidapi-libusb.a installed.

abcminiuser commented 7 months ago

Should be resolved with 7bc21c839618991c3360e5ad499a73741ccda830.