Search code examples
rubyrubygemsgmp

Ruby LoadError with gmp


$ gem install gmp
Building native extensions. This could take a while...
Successfully installed gmp-0.7.43
Parsing documentation for gmp-0.7.43
Done installing documentation for gmp after 0 seconds
1 gem installed


$ cat gmp-test.rb
require 'gmp'

$ /opt/src/ruby-3.2.0/bin/ruby gmp-test.rb
<internal:/opt/src/ruby-3.2.0/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in `require': cannot load such file -- /home/dunham/.local/share/gem/ruby/3.2.0/gems/gmp-0.7.43/lib/../ext/gmp (LoadError)
    from <internal:/opt/src/ruby-3.2.0/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
    from /home/dunham/.local/share/gem/ruby/3.2.0/gems/gmp-0.7.43/lib/gmp.rb:9:in `<top (required)>'
    from <internal:/opt/src/ruby-3.2.0/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:159:in `require'
    from <internal:/opt/src/ruby-3.2.0/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:159:in `rescue in require'
    from <internal:/opt/src/ruby-3.2.0/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:149:in `require'
    from gmp-test.rb:1:in `<main>'
<internal:/opt/src/ruby-3.2.0/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in `require': cannot load such file -- gmp (LoadError)
    from <internal:/opt/src/ruby-3.2.0/lib/ruby/site_ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in `require'
    from gmp-test.rb:1:in `<main>'

Solution

  • Library seems to be dead. It's expecting gmp.so to be in ext directory but it ends up in lib directory, it's probably new rubygems doing things differently.

    >> require "gmp"
    <internal:/home/alex/.rbenv/versions/3.2.0/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:85:in 'require': 
    cannot load such file -- /home/alex/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/gmp-0.7.43/lib/../ext/gmp (LoadError)
    
    $ ls $(dirname $(gem which gmp))
    gmp.rb  gmp.so
    #  move ^ that to ../ext/
    
    $ mv $(dirname $(gem which gmp))/gmp.so $(dirname $(gem which gmp))/../ext/
    
    >> require "gmp"
    => true
    >> GMP::Z(0)
    => 0
    

    Update

    From the linked logs looks like you're still not loading gmp.so which is where all the classes are defined. You can copy gmp.so into your app:

    # copy `gmp.rb`
    $ cp $(gem which gmp) .
    # copy `gmp.so`
    $ cp $(dirname $(gem which gmp))/gmp.so .
    # or if you moved it to ext
    $ cp $(dirname $(gem which gmp))/../ext/gmp.so .
    
    $ touch app.rb
    $ ls
    app.rb  gmp.rb  gmp.so
    

    gmp.rb defines GMP.sprintf method, if this is not a required method and you don't use it, you can remove this file.

    # gmp.rb
    
    # require 'rbconfig'
    #
    # ENV['PATH'] = [File.expand_path(
    #   File.join(File.dirname(__FILE__), "..", "ext")
    # ), ENV['PATH']].compact.join(';') if RbConfig::CONFIG['host_os'] =~ /(mswin|mingw|mingw32)/i
    #
    # require File.dirname(__FILE__) + '/../ext/gmp'
    
    # unless RUBY_VERSION =~ /^1.8/
      module GMP
        def self.sprintf(format, *args)
          first_pct = format.index '%'
          result = format[0...first_pct]
          #format.gsub(/(?<!%)%[0#+ ']*[0-9]*.?[0-9]*[a-zA-Z][^%]*/) do |fragment|
          format.gsub(Regexp.new('(?<!%)%[0#+ \']*[0-9]*.?[0-9]*[a-zA-Z][^%]*')) do |fragment|
            arg = args.shift
            if fragment =~ /%[0#+ ']*[0-9]*.?[0-9]*[ZQF]/
              result << sprintf2(fragment, arg)
            elsif fragment =~ /%[0#+ ']*[0-9]*.?[0-9]*[PR]/ && GMP.const_defined?(:MPFR_VERSION)
              result << GMP::F.sprintf2(fragment, arg)
            else
              result << (fragment % arg)
            end
          end
          result
        end
      end
    # end
    
    # app.rb
    
    require_relative "gmp.so"
    p GMP::Z
    p GMP::Z(0)
    p GMP::Q
    p GMP::F
    
    require_relative "gmp.rb"
    p GMP.sprintf "%Zd", GMP.Z(0)
    
    $ ruby --yjit -v
    ruby 3.2.0 (2022-12-25 revision a528908271) +YJIT [x86_64-linux]
    $ ruby --yjit app.rb
    GMP::Z
    0
    GMP::Q
    GMP::F
    "0"