Packaging ruby script w/ libusb, uninitialized constant error

I’m trying to package a collection of Ruby scripts (link) for use on NixOS. I’m mainly following the Ruby section (link) of the nixpkgs manual; the end of that section gives an outline of how to use bundlerEnv to package a Ruby script. The result is that the package is built without error, but when I run the resulting script polar_ftp, I get a Ruby uninitialized constant error within the Ruby libusb code, which I can’t make sense of.

Here’s a link to my repo, which is just the original repo along with a Gemfile and a default.nix file. Here’s a direct link to my default.nix file. The Gemfile.lock file and gemset.nix files were generated by running:

$ nix-shell -p bundix bundler --run 'bundle lock --update && bundix'

The default.nix file is not quite complete (missing patchShebang calls for all but two of the scripts) but should produce correct scripts polar_activitysamples2csv and polar_ftp. The first of these scripts seems to work fine, but running polar_ftp with no args gives:

Traceback (most recent call last):
        13: from /run/current-system/sw/bin/polar_ftp:30:in `<main>'
        12: from /run/current-system/sw/bin/polar_ftp:30:in `new'
        11: from /run/current-system/sw/bin/lib/polar_ftp.rb:13:in `initialize'
        10: from /nix/store/x11qjsj8fvyxafy46380j7n2mm0dhxnw-polar/bin/lib/polar_usb.rb:24:in `detect'
         9: from /nix/store/x11qjsj8fvyxafy46380j7n2mm0dhxnw-polar/bin/lib/polar_usb.rb:24:in `new'
         8: from /nix/store/x11qjsj8fvyxafy46380j7n2mm0dhxnw-polar/bin/lib/polar_usb_hid.rb:10:in `initialize'
         7: from /nix/store/p45fhb5v560dn5lz86ll1z3y7jdahn41-polar-env/lib/ruby/gems/2.6.0/gems/libusb-0.6.4/lib/libusb/context.rb:249:in `devices'
         6: from /nix/store/p45fhb5v560dn5lz86ll1z3y7jdahn41-polar-env/lib/ruby/gems/2.6.0/gems/libusb-0.6.4/lib/libusb/context.rb:163:in `device_list'
         5: from /nix/store/p45fhb5v560dn5lz86ll1z3y7jdahn41-polar-env/lib/ruby/gems/2.6.0/gems/libusb-0.6.4/lib/libusb/context.rb:163:in `times'
         4: from /nix/store/p45fhb5v560dn5lz86ll1z3y7jdahn41-polar-env/lib/ruby/gems/2.6.0/gems/libusb-0.6.4/lib/libusb/context.rb:165:in `block in device_list'
         3: from /nix/store/p3fxahqwzk79mhml27afkqb19ris4k45-ruby-2.6.6/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:72:in `require'
         2: from /nix/store/p3fxahqwzk79mhml27afkqb19ris4k45-ruby-2.6.6/lib/ruby/2.6.0/rubygems/core_ext/kernel_require.rb:72:in `require'
         1: from /nix/store/p45fhb5v560dn5lz86ll1z3y7jdahn41-polar-env/lib/ruby/gems/2.6.0/gems/libusb-0.6.4/lib/libusb/device.rb:18:in `<top (required)>'
/nix/store/p45fhb5v560dn5lz86ll1z3y7jdahn41-polar-env/lib/ruby/gems/2.6.0/gems/libusb-0.6.4/lib/libusb/device.rb:22:in `<module:LIBUSB>': uninitialized constant LIBUSB::Device (NameError)

The error occurs in the Ruby libusb package, version 0.6.4. In particular, the line of the error (device.rb:18; see here) is just the line class Device in the code below:

module LIBUSB
  # Class representing a USB device detected on the system.
  # Devices of the system can be obtained with {Context#devices} .
  class Device
    include Comparable

    # rest of class definition ...

I’m not very familiar with Ruby, but my web searches are failing to give me any clue why a class definition like the above (without any inheritance) would give rise to a NameError. Unfortunately I haven’t been able to test the package itself on a non-nix system, but based on the activity on the github repo, it seems to work fine for others.

Can anyone help figure out what is going on? If you’d like to reproduce:

  • clone my repo linked above
  • run the nix-shell command quoted above
  • change the path in default.nix to the path where you cloned the repo
  • build the package
  • run the resulting polar_ftp script with no arguments.

I solved the issue by adding copyGemFiles = true; to the options of bundlerEnv in default.nix. It’s still not clear to me what this option does or why it should make a difference, but it worked. See here for discussion of this option.

I’ll also note that the error has something to do with ruby’s autoloading mechanism, which the ruby libusb gem makes use of. That is, it seems like rewriting the libusb code to remove autoloads would also resolve the issue.