oneclick / rubyinstaller2

MSYS2 based RubyInstaller for Windows
https://rubyinstaller.org
BSD 3-Clause "New" or "Revised" License
646 stars 248 forks source link

Fiddle is preloaded by rubyinstaller #251

Closed thyresias closed 2 years ago

thyresias commented 2 years ago

What problems are you experiencing?

For a complete discussion, see https://github.com/rubygems/rubygems/issues/5043. It turns out that rubyinstaller requires fiddle before RubyGems hacks "require", so the loaded gem is always the native one, not the last one installed through RubyGems. David Rodríguez will fix the symlink issue that was the source of the reported problem, but the problem is that there is no way to load the latest fiddle version.

Steps to reproduce

> gem list fiddle

*** LOCAL GEMS ***

fiddle (1.1.0, default: 1.0.6)

> ruby -e "p Fiddle::VERSION"
"1.0.6"

> ruby -e "require 'fiddle'; p Fiddle::VERSION"
"1.0.6"

> ruby -e "gem 'fiddle', '=1.1.0'; require 'fiddle'; p Fiddle::VERSION"
c:/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/rubygems/specification.rb:2229:in `check_version_conflict': can't activate fiddle-1.1.0, already activated fiddle-1.0.6 (Gem::LoadError)
        from c:/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/rubygems/specification.rb:1366:in `activate'
        from c:/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/rubygems/core_ext/kernel_gem.rb:68:in `block in gem'
        from c:/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/rubygems/core_ext/kernel_gem.rb:68:in `synchronize'
        from c:/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/rubygems/core_ext/kernel_gem.rb:68:in `gem'
        from -e:1:in `<main>'

What's the output from ridk version?

> ridk version
c:/ruby-3.0.2/lib/ruby/site_ruby/3.0.0/ruby_installer/runtime/ridk.rb:104: warning: assigned but unused variable - tasks
---
ruby:
  path: c:/ruby-3.0.2
  version: 3.0.2
  platform: i386-mingw32
  cc: gcc.exe (Rev5, Built by MSYS2 project) 10.3.0
ruby_installer:
  package_version: 3.0.2-1
  git_commit: 80c9ca9
msys2:
  path: c:\msys32
cc: gcc (Rev1, Built by MSYS2 project) 11.2.0
sh: GNU bash, version 5.1.8(1)-release (i686-pc-msys)
os: Microsoft Windows [Version 10.0.19042.1348]
deivid-rodriguez commented 2 years ago

Unfortunately, I don't think rubyinstaller can do much about this either, but definitely worth asking! I think the only way to fix this kind of issue reliably and in general would be if ruby's require supported "vendoring". Something like:

require "fiddle", under: :RubyInstaller

A feature request was proposed for this a while ago, but it doesn't seem to be going anywhere: https://bugs.ruby-lang.org/issues/13847.

deivid-rodriguez commented 2 years ago

That's awesome @larskanis, thanks so much!

larskanis commented 2 years ago

RubyInstaller uses fiddle since ruby-2.4 to enable and configure DLL loading directories. It makes use of a DLL loading mode that was introduced in Windows-8. This is necessary to activate DLL loading from MSYS2 packages. And since gems can require MSYS2 packages to be loadable, fiddle needs to be loaded prior to rubygems. The mechanism is described here: https://github.com/oneclick/rubyinstaller2/wiki/For-gem-developers#user-content-dll-loading

For example the fiddle gem is linked to the MSYS2 package mingw-w64-x86_64-ucrt-libffi per default, so it needs to load libffi-7.dll from the MSYS2 directory at require 'fiddle'. This is enabled by rubygems/defaults/operating_system.rb.

Unfortunately loading fiddle prior to rubygems prevents loading of fiddle installed as a gem. To overcome this issue the now introduced mechanism works as follows:

This patch adds a new C-extension to ruby that is called win32/dll_directory and it isn't a gem, but part of the ruby stdlib.

The second part of the fix is this patch. It makes use of win32/dll_directory and therefore avoids fiddle in RubyInstaller::Runtime.add_dll_directory and in the pre-rubygems phase.

This fix will be released as part of RubyInstaller-3.1.0-1 and if everything works as expected with all other active ruby branches next year.