Repository navigation
Trouble locating libncurses on MacOS with reline + jruby + fiddle FFI #766
Copy link
Copy link
Closed
Description
Hello!
We recently started pulling the latest stdlib gems into JRuby for Ruby 3.4 support and ran into an issue with reline loading libncurses via fiddle:
$ jruby -e 'require "reline"'
LoadError: Could not open library 'libncursesw.dylib' : dlopen(libncursesw.dylib, 0x0009): tried: 'libncursesw.dylib' (no such file), '/System/Volumes/Preboot/Cryptexes/OSlibncursesw.dylib' (no such file), '/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home/bin/./libncursesw.dylib' (no such file), '/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home/bin/../lib/libncursesw.dylib' (no such file), '/usr/lib/libncursesw.dylib' (no such file, not in dyld cache), 'libncursesw.dylib' (no such file), '/usr/lib/libncursesw.dylib' (no such file, not in dyld cache)
open at org/jruby/ext/ffi/jffi/DynamicLibrary.java:100
initialize at /Users/headius/work/jruby/lib/ruby/gems/shared/gems/fiddle-1.1.3/lib/fiddle/ffi_backend.rb:478
new at org/jruby/RubyClass.java:921
curses_dl at /Users/headius/work/jruby/lib/ruby/stdlib/reline/terminfo.rb:41
each at org/jruby/RubyArray.java:1954
curses_dl at /Users/headius/work/jruby/lib/ruby/stdlib/reline/terminfo.rb:40
<main> at /Users/headius/work/jruby/lib/ruby/stdlib/reline/terminfo.rb:152
require at org/jruby/RubyKernel.java:1186
require at /Users/headius/work/jruby/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb:136
<main> at /Users/headius/work/jruby/lib/ruby/stdlib/reline.rb:9
require at org/jruby/RubyKernel.java:1186
require at /Users/headius/work/jruby/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb:136
<main> at -e:1
Several locations are searched here but the file is not found. A few possible issues:
- A small patch provided below was necessary to get reline to look for the proper
.dylibname rather than.so.RUBY_PLATFORMisjavaand RbConfig should be used to get the real host platform. - I do not have libncurses in /usr/lib or /usr/local/lib but I am not sure if there are other places on MacOS I should be looking.
- I do have
libncurses.dylibinstalled via Homebrew. - If reline depends on libncurses unconditionally (as here, can't even load reline without libncurses present), perhaps some message on install is needed?
- This could be a bug in the FFI-based fiddle we are using on JRuby (and TruffleRuby). cc @kou @eregon
We are keen to figure this issue out so we can proceed with running the latest gems, stdlib, and tests in JRuby's 3.4-compatible branch.
Patch for reline to properly select a set of libncurses file names:
diff --git a/reline/terminfo.rb b/reline/terminfo.rb
--- a/reline/terminfo.rb
+++ b/reline/terminfo.rb (date 1729186018729)
@@ -20,7 +20,7 @@
class TerminfoError < StandardError; end
def self.curses_dl_files
- case RUBY_PLATFORM
+ case RbConfig::CONFIG['host_os']
when /mingw/, /mswin/
# aren't supported
[]Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
eregon commentedon Oct 17, 2024
Re RUBY_PLATFORM, it would be nice if JRuby would be compatible there, and be the native platform, i.e. like the
[...]part in RUBY_DESCRIPTION: jruby/jruby#6152Because it sounds like this workaround is and will be needed in many places.
(and on top of that JRuby docs suggest/ed to use
RbConfig::CONFIG['host_os']but apparently that's the wrong one, and should betarget_os, I recall some discussion about this on the FFI & Ruby tracker).Re not finding the library, I suspect that's because JRuby uses a rather old FFI which doesn't have this fix to search for Homebrew on darwin-arm64: ffi/ffi#968
Or that your Homebrew is in a non-standard location maybe.
headius commentedon Oct 17, 2024
JRuby has used "java" for RUBY_PLATFORM for almost twenty years and there are hundreds of gems out there that expect it to remain that way, as I described in jruby/jruby#6152.
We originally were forced to use "java" here because RubyGems could not support JRuby-specific extension gems any other way. I'm not sure when RubyGems switched to
RbConfig::CONFIG['arch']but in any case the cat was out of the bag long before the other Ruby implementations even existed. Claiming "java" as our platform also made sense for many other reasons, and it has long been JRuby's goal that applications work the same on Windows as on Unix.JRuby does not use a "rather old FFI". JRuby sources all FFI Ruby code from the gem, currently at version 1.16.3. That fix appears to have been released in 1.16.0.
That should be updated to 1.17.0 but the fix you describe should already be shipping with JRuby.
headius commentedon Oct 17, 2024
Same result with FFI 1.17.0:
headius commentedon Oct 17, 2024
Again, as I said in the original description, this might be a JRuby issue, but I am filing it here for other reasons:
Perhaps there's a way to make this dependency on libncurses lazy and only load and use it if necessary? It's a separate issue from the inability to load on MacOS (or specifically on my machine), but it is definitely a concern for e.g. minimized Docker containers that may not need libncurses otherwise.
headius commentedon Oct 17, 2024
Another point: RubyGems decided it was better to use
RbConfig::CONFIG['arch']to select an appropriate native extension gem. Why isn't that (or similar) the right way to locate native dependencies in libraries like reline?eregon commentedon Oct 17, 2024
What's the path of your
libncurses.dylibin Homebrew?Are you on macos-arm64 or macos-amd64?
If the former,
/opt/homebrew/libshould be shown as part of the error message, that's why I thought too old FFI might be the issue.Maybe some platform detection goes wrong on JRuby? The logic on master is https://github.com/ffi/ffi/blob/c128cede750242fe19945af8bd6c797728489ad5/lib/ffi/dynamic_library.rb#L37-L49
headius commentedon Oct 17, 2024
ncurses appears to install in
/opt/homebrew/Cellar:I am on macos-aarch64. The SEARCH_PATH does appear to be set up with /opt/homebrew/lib but I do not know why it doesn't show in the error message:
Neither does
/opt/local/lib, or/usr/local/lib.eregon commentedon Oct 17, 2024
Mmh, so there is no
/opt/homebrew/lib/ncurses*.dylib? It seems not with thatfindoutput.Looking at https://github.com/Homebrew/homebrew-core/blob/a320ea608f4eef1318e12c3a5afeaa0a080858f3/Formula/n/ncurses.rb#L22 so it is keg-only and not linked under
/opt/homebrew/lib.The reason is "provided_by_macos", does macOS ship libncurses?
headius commentedon Oct 17, 2024
There are two issues to address here:
headius commentedon Oct 17, 2024
I have not been able to find it in the usual places, but macOS sprinkles libraries all over the place.
headius commentedon Oct 17, 2024
I have been unable to locate libncurses.dylib anywhere in the standard macOS dirs.
This may be related (.tbd as a new dylib extension for "text-based stub libraries"): https://discourse.cmake.org/t/newer-versions-of-macos-require-linking-against-tbd-files-and-not-old-system-paths-to-dylib/6871/2
I do have some
libncurses*.tbdfiles in various places.headius commentedon Oct 17, 2024
tbd files for libncurses on my machine. Note that without xcode these would not exist either. I can find no evidence that macOS provides libncurses in any reliable way (and there seems to be some debate about this elsewhere online too):
eregon commentedon Oct 18, 2024
@headius If you look at https://github.com/ruby/reline/blob/master/lib/reline/terminfo.rb libcurses is clearly optional.
You're getting a LoadError above, but it should be rescued by
https://github.com/ruby/fiddle/blob/1f818e46843965fbbb085114f0b875c3acf87489/lib/fiddle/ffi_backend.rb#L478-L479
eregon commentedon Oct 18, 2024
Ah it's a bug of that code:
is the same as
I'll fix it in ruby/fiddle: ruby/fiddle#156
Fix Fiddle::Handle.new for a missing library in the FFI backend
Fix Fiddle::Handle.new for a missing library in the FFI backend
Fix Fiddle::Handle.new for a missing library in the FFI backend
Fix Fiddle::Handle.new for a missing library in the FFI backend (#156)
tompng commentedon Oct 19, 2024
Thank you for addressing the fiddle issue.
In Reline, libncurses is optional, and in most case that environment variable TERM is set to
xtermor other frequently used values, Reline does not need libncurses at all.So another possible solution for this would be completely drop libncurses dependency. #769
Update fiddle to 1.1.4
headius commentedon Oct 22, 2024
@tompng Yes thank you for your response! I can confirm that there's no issue with libncurses anymore for me (on aarch64 macOS) using fiddle 1.1.4.
This issue can be closed. I would love to see #769 happen but for my purposes the fiddle fix is good enough.
[ruby/fiddle] Fix Fiddle::Handle.new for a missing library in the
[ruby/fiddle] Fix Fiddle::Handle.new for a missing library in the
Update fiddle to 1.1.4
[ruby/fiddle] Fix Fiddle::Handle.new for a missing library in the
[ruby/fiddle] Fix Fiddle::Handle.new for a missing library in the