Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

9.3 : Gem::LoadError: You have already activated ffi 1.15.1, but your Gemfile requires ffi 1.15.3. #6751

Closed
HoneyryderChuck opened this issue Jul 12, 2021 · 11 comments · Fixed by #6760 or #6747
Milestone

Comments

@HoneyryderChuck
Copy link

Continuing after fixing #6732 , I'm seeing an issue when testing on Windows, using jruby-head and ffi, namely, there's a conflict between a "loose" dependency, and what jruby perceives as the default gem version.

The dependency is set like:

# in gemspec
spec.add_dependency "ffi", ["~> 1.12"]

The error message is:

Gem::LoadError: You have already activated ffi 1.15.1, but your Gemfile requires ffi 1.15.3. Since ffi is a default gem, you can either remove your dependency on it or try updating to a newer version of bundler that supports ffi as a default gem.

Build log here: https://github.com/HoneyryderChuck/idnx/runs/3044772603?check_suite_focus=true

It's worth noting that this issue happens only on windows (if you run through the other jruby jobs, on mac and linux, all is well).

Is the change a plain bundler update, or is it more involved?

Environment Information

Provide at least:

  • JRuby version: 9.3 (head)
  • Operating system and platform: Windows (Github actions CI)
@headius
Copy link
Member

headius commented Jul 21, 2021

Ok I suspect that the problem here is due to some Windows logic in our standard library or boot code is probably activating FFI before Bundler can get in there and pick the right one. The most likely suspect is the code linked below, which loads on boot to support IO#fcntl on Windows:

There are a few ways we could fix this:

  • Make all use of FFI for this function lazy, by doing a deferred load of the necessary FFI logic. This is probably the simplest fix, but it means any failure to load FFI would not be seen until the first use of IO#fcntl.
  • Move this code into Java and use the underlying jnr-ffi library to implement this logic. This would avoid activating the built-in Ruby FFI library but requires more work and testing.

I think deferring the load of this fcntl code until first use is the best option. Maybe you can give it a shot and push a PR?

@headius headius added this to the JRuby 9.3.0.0 milestone Jul 21, 2021
@headius
Copy link
Member

headius commented Jul 21, 2021

Note there's similar code below this for Solaris that could also be moved inside a lazy load.

@HoneyryderChuck
Copy link
Author

It's not very obvious to me where I can lazy-load it. I see that these workarounds are loaded in kernel.rb, but apart from that, not quite sure where they're used.

Can you give me some pointers on the where, and perhaps referencing a similar workaround in the code?

@headius
Copy link
Member

headius commented Jul 23, 2021

@HoneyryderChuck Yeah looking at it more closely this would be difficult to do lazily. The constants are being pulled out of FFI as well, and would be accessed before any method is called.

It may be possible to modify that file (jruby/kernel/file.rb) to attempt to activate the gem first, which will impact startup but may be compatible with Bundler installing a newer FFI.

headius added a commit to headius/jruby that referenced this issue Jul 23, 2021
Activating FFI this early prevents it being upgraded by RubyGems
or Bundler. This also happens so early that there's no way to
eagerly activate the gem to pick up a newer version. As a result,
bundles or gems that depend on newer FFI will error or warn about
the mismatch.

This change modifies the FFI-based File methods on Windows
(File.symlink) and Solaris (File#flock) to lazily require a
separate file that loads FFI and redefines those methods.

Fixes jruby#6751
@HoneyryderChuck
Copy link
Author

Looks like an acceptable trade-off. Thx @headius

@headius
Copy link
Member

headius commented Jul 23, 2021

I realized the constants I was worried about are literally just used by the adjacent FFI logic, so I have moved the entire ball of crap into a separate file that is lazy-loaded on first call of File.symlink (on WIndows) or File#fcntl (on Solaris).

If you can test it out that would be great! Easy to build from the branch in #6760 or I will merge it once green and you can pick up a snapshot build of master.

headius added a commit to headius/jruby that referenced this issue Jul 26, 2021
It seems like this code was broken before I messed with it. The
FFI::Config constant does not exist, so this was not actually
defining the FFI-based File.symlink. As a result, my change to
load that logic lazily caused a stack overflow.

The changes here fix this:

* Always define the Windows-specific String function present here.
* Only check for the FFI constant to know if FFI is available.
* If FFI is not available *or* it cannot bind the necessary
  functions, instead define File.symlink to raise NotImplemented.

See jruby#6751.
@headius
Copy link
Member

headius commented Jul 26, 2021

A few issues were unearthed by my fix so I have pushed #6762 to address them. I have confirmed the following:

  • File.symlink is back to working on Windows again (provided you have the right permissions)
  • If FFI is unavailable, native support is disabled, or the CreateSymbolicLinkW function is not available, we will define a version of File.symlink that raises NotImplementedError.
  • A newer FFI activated by Bundler or RubyGems will be used by the lazy-loaded logic

@headius
Copy link
Member

headius commented Jul 26, 2021

@HoneyryderChuck Could you help us out by writing some tests for the cases I describe above, perhaps including a case that confirms FFI does not get loaded until after you try to call symlink? I have merged in #6762 and I am convinced it is working, but my virtualized Windows environment is painful to use.

Tests that basically just shell out and relaunch JRuby with various options would be great!

@HoneyryderChuck
Copy link
Author

@headius I'm currently on holidays, will come back to it next week 👍

@HoneyryderChuck
Copy link
Author

@headius I can confirm that the ffi issue doesn't show up anymore.

Only had some issues in my test build due to declaring "win32ole" instead of "jruby-win32ole" in my Gemfile (installing works, requiring works, but there's no "WIN32OLE" available after). Once I got it done, all went well: https://github.com/HoneyryderChuck/idnx/actions/runs/1087751417

Thank you again for your help!

@headius headius linked a pull request Aug 16, 2021 that will close this issue
@OrenMag
Copy link

OrenMag commented Oct 14, 2021

If it helps anyone, what eventually helped me was to uninstall the wrong ffi version completely:
gem uninstall ffi -v 1.15.4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants