Details

    • Type: Bug Bug
    • Status: Closed Closed
    • Priority: Major Major
    • Resolution: Won't Fix
    • Affects Version/s: JRuby 1.6RC3
    • Fix Version/s: None
    • Component/s: Interpreter
    • Labels:
      None
    • Environment:
      MacOSX 1.0.6
    • Testcase included:
      yes
    • Number of attachments :
      0

      Description

      Here's the error

      LoadError: no such file to load -- whois/answer/parser/whois.nic
         require at org/jruby/RubyKernel.java:1037
         require at /Users/weppos/.rvm/rubies/jruby-1.6.0.RC3/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:29
          (root) at ./test/whois/answer/parser/whois.nic.so_test.rb:2
            load at org/jruby/RubyKernel.java:1062
        __file__ at /Users/weppos/.rvm/gems/jruby-1.6.0.RC3/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5
            each at org/jruby/RubyArray.java:1572
          (root) at /Users/weppos/.rvm/gems/jruby-1.6.0.RC3/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5
      rake aborted!
      

      You can reproduce it by trying to execute the test suite of the Whois Gem.
      https://github.com/weppos/whois/tree/222f9244884ed745842a4050909708b9b663376c

      The whois.nic.so_test.rb file attempts to include a whois.nic.so.rb file using the following syntax

      require 'whois/answer/parser/whois.nic.so'
      

        Issue Links

          Activity

          Hide
          Charles Oliver Nutter added a comment -

          Wow, this is a really weird case.

          We use ".so" in the file being required to know we should look for extensions. We then search for .so, .jar, etc but never search for .so.rb. This is mostly the behavior of Ruby, but perhaps there's something we're missing.

          I will say it's very questionable for the whois library to require files with .so at the end, since that's rather ambiguous...

          Looking into it.

          Show
          Charles Oliver Nutter added a comment - Wow, this is a really weird case. We use ".so" in the file being required to know we should look for extensions. We then search for .so, .jar, etc but never search for .so.rb. This is mostly the behavior of Ruby, but perhaps there's something we're missing. I will say it's very questionable for the whois library to require files with .so at the end, since that's rather ambiguous... Looking into it.
          Hide
          Charles Oliver Nutter added a comment -

          Behavior seems consistent across MRI-based (or originally-MRI-based) impls...they find the file. JRuby and Rubinius do not:

          ~/projects/jruby ➔ cat foo.so.rb 
          puts 'ok'
          
          ~/projects/jruby ➔ jruby -e "require 'foo.so'"
          LoadError: no such file to load -- foo
            require at org/jruby/RubyKernel.java:1037
             (root) at -e:1
          
          ~/projects/jruby ➔ ruby -e "require 'foo.so'"
          ok
          
          ~/projects/jruby ➔ ruby1.9 -I. -e "require 'foo.so'"
          ok
          
          ~/projects/jruby ➔ ../rubinius/bin/rbx -e "require 'foo.so'"
          An exception occurred evaluating command line code
              no such file to load -- foo.bundle (LoadError)
          
          Backtrace:
                 Rubinius::CodeLoader#load_error at kernel/common/codeloader.rb:343
            Rubinius::CodeLoader#resolve_require_path at kernel/common/codeloader.rb:330
                    Rubinius::CodeLoader#require at kernel/common/codeloader.rb:34
                    Rubinius::CodeLoader.require at kernel/common/codeloader.rb:140
                          Kernel(Object)#require at kernel/common/kernel.rb:737
                        { } in Object#__script__ at -e:1
                   Kernel(Rubinius::Loader)#eval at kernel/common/eval.rb:115
                          Rubinius::Loader#evals at kernel/loader.rb:544
                           Rubinius::Loader#main at kernel/loader.rb:673
                           Rubinius::Loader.main at kernel/loader.rb:713
                      Object#script (__script__) at kernel/loader.rb:724
          
          ~/projects/jruby ➔ macruby -e "require 'foo.so'"
          ok
          
          Show
          Charles Oliver Nutter added a comment - Behavior seems consistent across MRI-based (or originally-MRI-based) impls...they find the file. JRuby and Rubinius do not: ~/projects/jruby ➔ cat foo.so.rb puts 'ok' ~/projects/jruby ➔ jruby -e "require 'foo.so'" LoadError: no such file to load -- foo require at org/jruby/RubyKernel.java:1037 (root) at -e:1 ~/projects/jruby ➔ ruby -e "require 'foo.so'" ok ~/projects/jruby ➔ ruby1.9 -I. -e "require 'foo.so'" ok ~/projects/jruby ➔ ../rubinius/bin/rbx -e "require 'foo.so'" An exception occurred evaluating command line code no such file to load -- foo.bundle (LoadError) Backtrace: Rubinius::CodeLoader#load_error at kernel/common/codeloader.rb:343 Rubinius::CodeLoader#resolve_require_path at kernel/common/codeloader.rb:330 Rubinius::CodeLoader#require at kernel/common/codeloader.rb:34 Rubinius::CodeLoader.require at kernel/common/codeloader.rb:140 Kernel(Object)#require at kernel/common/kernel.rb:737 { } in Object#__script__ at -e:1 Kernel(Rubinius::Loader)#eval at kernel/common/eval.rb:115 Rubinius::Loader#evals at kernel/loader.rb:544 Rubinius::Loader#main at kernel/loader.rb:673 Rubinius::Loader.main at kernel/loader.rb:713 Object#script (__script__) at kernel/loader.rb:724 ~/projects/jruby ➔ macruby -e "require 'foo.so'" ok
          Hide
          Simone Carletti added a comment -

          I will say it's very questionable for the whois library to require files with .so at the end, since that's rather ambiguous...

          I agree, and I will probably change it. However, I reported it because all the other Ruby implementations worked and I thought you might want to give it a look.

          Show
          Simone Carletti added a comment - I will say it's very questionable for the whois library to require files with .so at the end, since that's rather ambiguous... I agree, and I will probably change it. However, I reported it because all the other Ruby implementations worked and I thought you might want to give it a look.
          Hide
          Charles Oliver Nutter added a comment -

          According to MRI docs, it seems like this working in MRI is just a lucky coincidence. The docs claim that if it ends with .so or .o or whatever the platform-specific native library extension is, it will try to load it as an extension:

          /*
           *  call-seq:
           *     require(string)    -> true or false
           *
           *  Ruby tries to load the library named _string_, returning
           *  +true+ if successful. If the filename does not resolve to
           *  an absolute path, it will be searched for in the directories listed
           *  in <code>$:</code>. If the file has the extension ``.rb'', it is
           *  loaded as a source file; if the extension is ``.so'', ``.o'', or
           *  ``.dll'', or whatever the default shared library extension is on
           *  the current platform, Ruby loads the shared library as a Ruby
           *  extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on
           *  to the name. The name of the loaded feature is added to the array in
           *  <code>$"</code>. A feature will not be loaded if its name already
           *  appears in <code>$"</code>. The file name is converted to an absolute
           *  path, so ``<code>require 'a'; require './a'</code>'' will not load
           *  <code>a.rb</code> twice.
           *
           *     require "my-library.rb"
           *     require "db-driver"
           */
          
          Show
          Charles Oliver Nutter added a comment - According to MRI docs, it seems like this working in MRI is just a lucky coincidence. The docs claim that if it ends with .so or .o or whatever the platform-specific native library extension is, it will try to load it as an extension: /* * call-seq: * require(string) -> true or false * * Ruby tries to load the library named _string_, returning * +true+ if successful. If the filename does not resolve to * an absolute path, it will be searched for in the directories listed * in <code>$:</code>. If the file has the extension ``.rb'', it is * loaded as a source file; if the extension is ``.so'', ``.o'', or * ``.dll'', or whatever the default shared library extension is on * the current platform, Ruby loads the shared library as a Ruby * extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on * to the name. The name of the loaded feature is added to the array in * <code>$"</code>. A feature will not be loaded if its name already * appears in <code>$"</code>. The file name is converted to an absolute * path, so ``<code>require 'a'; require './a'</code>'' will not load * <code>a.rb</code> twice. * * require "my-library.rb" * require "db-driver" */
          Hide
          Simone Carletti added a comment -

          I don't know if it is a coincidence or if MRI is smart enough to detect there's no shared extension with that name and tries to append .rb to the end.

          This might be interesting to know, however I agree the behavior can be confusing.

          Show
          Simone Carletti added a comment - I don't know if it is a coincidence or if MRI is smart enough to detect there's no shared extension with that name and tries to append .rb to the end. This might be interesting to know, however I agree the behavior can be confusing.
          Hide
          Charles Oliver Nutter added a comment -

          Let's put it this way...I don't really want to fix this

          A few more interesting cases...

          Here, there's a .bundle that's not an extension (so I can see it blow up) and a .bundle.rb that's a ruby file. Ruby tries to load the .bundle:

          ~/projects/jruby &#10132; cp foo.so.rb foo.bundle.rb
          
          ~/projects/jruby &#10132; ruby -e "require 'foo.bundle'"
          ./foo.bundle: dlopen(./foo.bundle, 9): no suitable image found.  Did find: (LoadError)
          	./foo.bundle: unknown file type, first eight bytes: 0x00 0xD2 0xBF 0x5F 0xFF 0x7F 0x00 0x00 - ./foo.bundle
          	from -e:1
          
          ~/projects/jruby &#10132; rm foo.bundle
          
          ~/projects/jruby &#10132; ruby -e "require 'foo.bundle'"
          ok
          

          Now the same with a .so and a .so.rb:

          ~/projects/jruby &#10132; ls foo.*
          foo.bundle.rb	foo.so		foo.so.rb
          
          ~/projects/jruby &#10132; ruby -e "require 'foo.so'"
          ok
          

          So this shows there's platform-specific logic here to attempt to load x.bundle as x.bundle before failing over to x.bundle.rb.

          Now, a case you might expect to work: loading bar.rb.rb with require 'bar.rb':

          ~/projects/jruby &#10132; cat bar.rb.rb
          puts 'ok'
          
          ~/projects/jruby &#10132; jruby -e "require 'bar.rb'"
          LoadError: no such file to load -- bar
            require at org/jruby/RubyKernel.java:1037
             (root) at -e:1
          
          ~/projects/jruby &#10132; ruby -e "require 'bar.rb'"
          -e:1:in `require': no such file to load -- bar.rb (LoadError)
          	from -e:1
          
          

          So there's no failover to adding .rb if the extension is already .rb in the require argument. It only seems to failover for the "native" extensions like .bundle and .so.

          How about .so.so:

          ~/projects/jruby &#10132; cat baz.so.so 
          puts 'ok'
          
          ~/projects/jruby &#10132; ruby -e "require 'baz.so'"
          -e:1:in `require': no such file to load -- baz.so (LoadError)
          	from -e:1
          

          But on my platform shared libs are .bundle:

          ~/projects/jruby &#10132; mv baz.so.so baz.bundle.bundle
          
          ~/projects/jruby &#10132; ruby -e "require 'baz.bundle'"
          ./baz.bundle.bundle: dlopen(./baz.bundle.bundle, 9): no suitable image found.  Did find: (LoadError)
          	./baz.bundle.bundle: unknown file type, first eight bytes: 0x70 0x75 0x74 0x73 0x20 0x27 0x6F 0x6B - ./baz.bundle.bundle
          	from -e:1
          

          The logic in JRuby is basically this:

          1. If no extension, search source extensions (.rb, .class) followed by extension extensions (.jar, .so, .bundle)
          2. If source extension, search only source extensions (require 'foo.rb' will look for foo.rb and foo.class)
          3. If extension extension, search only extension extensions (require 'foo.so' will look for foo.so, foo.jar, etc)

          It seems like the extra logic would apply only to (3) above, failing over to .rb searching in the extension case.

          Do we really need to fix this?

          Show
          Charles Oliver Nutter added a comment - Let's put it this way...I don't really want to fix this A few more interesting cases... Here, there's a .bundle that's not an extension (so I can see it blow up) and a .bundle.rb that's a ruby file. Ruby tries to load the .bundle: ~/projects/jruby &#10132; cp foo.so.rb foo.bundle.rb ~/projects/jruby &#10132; ruby -e "require 'foo.bundle'" ./foo.bundle: dlopen(./foo.bundle, 9): no suitable image found. Did find: (LoadError) ./foo.bundle: unknown file type, first eight bytes: 0x00 0xD2 0xBF 0x5F 0xFF 0x7F 0x00 0x00 - ./foo.bundle from -e:1 ~/projects/jruby &#10132; rm foo.bundle ~/projects/jruby &#10132; ruby -e "require 'foo.bundle'" ok Now the same with a .so and a .so.rb: ~/projects/jruby &#10132; ls foo.* foo.bundle.rb foo.so foo.so.rb ~/projects/jruby &#10132; ruby -e "require 'foo.so'" ok So this shows there's platform-specific logic here to attempt to load x.bundle as x.bundle before failing over to x.bundle.rb. Now, a case you might expect to work: loading bar.rb.rb with require 'bar.rb': ~/projects/jruby &#10132; cat bar.rb.rb puts 'ok' ~/projects/jruby &#10132; jruby -e "require 'bar.rb'" LoadError: no such file to load -- bar require at org/jruby/RubyKernel.java:1037 (root) at -e:1 ~/projects/jruby &#10132; ruby -e "require 'bar.rb'" -e:1:in `require': no such file to load -- bar.rb (LoadError) from -e:1 So there's no failover to adding .rb if the extension is already .rb in the require argument. It only seems to failover for the "native" extensions like .bundle and .so. How about .so.so: ~/projects/jruby &#10132; cat baz.so.so puts 'ok' ~/projects/jruby &#10132; ruby -e "require 'baz.so'" -e:1:in `require': no such file to load -- baz.so (LoadError) from -e:1 But on my platform shared libs are .bundle: ~/projects/jruby &#10132; mv baz.so.so baz.bundle.bundle ~/projects/jruby &#10132; ruby -e "require 'baz.bundle'" ./baz.bundle.bundle: dlopen(./baz.bundle.bundle, 9): no suitable image found. Did find: (LoadError) ./baz.bundle.bundle: unknown file type, first eight bytes: 0x70 0x75 0x74 0x73 0x20 0x27 0x6F 0x6B - ./baz.bundle.bundle from -e:1 The logic in JRuby is basically this: If no extension, search source extensions (.rb, .class) followed by extension extensions (.jar, .so, .bundle) If source extension, search only source extensions (require 'foo.rb' will look for foo.rb and foo.class) If extension extension, search only extension extensions (require 'foo.so' will look for foo.so, foo.jar, etc) It seems like the extra logic would apply only to (3) above, failing over to .rb searching in the extension case. Do we really need to fix this?
          Hide
          Simone Carletti added a comment - - edited

          Do we really need to fix this?

          I believe the answer is the response to the following question: is it a coincidence or a feature? In case it's just a coincidence, then MRI should probably fix this and make it less ambiguous. On the opposite, if it's a feature, you should probably consider it for JRuby as well.

          I changed my tests so that the issue is no longer applicable. All the 3k tests now passes successfully with JRuby 1.6.0 RC3.

          I'm going to open a ticket in the Ruby ML to see if someone else noticed this behavior before.

          Thanks for your support.

          Show
          Simone Carletti added a comment - - edited Do we really need to fix this? I believe the answer is the response to the following question: is it a coincidence or a feature? In case it's just a coincidence, then MRI should probably fix this and make it less ambiguous. On the opposite, if it's a feature, you should probably consider it for JRuby as well. I changed my tests so that the issue is no longer applicable. All the 3k tests now passes successfully with JRuby 1.6.0 RC3. I'm going to open a ticket in the Ruby ML to see if someone else noticed this behavior before. Thanks for your support.
          Hide
          Simone Carletti added a comment -

          Charles,

          I know you read ruby-core, but for the records, here's the link to the ML
          http://www.ruby-forum.com/topic/1248205

          Show
          Simone Carletti added a comment - Charles, I know you read ruby-core, but for the records, here's the link to the ML http://www.ruby-forum.com/topic/1248205
          Hide
          Charles Oliver Nutter added a comment -

          This fix makes it work, but breaks other things (presumably that depend on us normalizing extension extensions to ".jar" for searching purposes: https://gist.github.com/863022

          Perhaps we should wait and see what ruby-core thinks about this failover behavior.

          Show
          Charles Oliver Nutter added a comment - This fix makes it work, but breaks other things (presumably that depend on us normalizing extension extensions to ".jar" for searching purposes: https://gist.github.com/863022 Perhaps we should wait and see what ruby-core thinks about this failover behavior.
          Hide
          Charles Oliver Nutter added a comment -

          Simone: Thanks for posting that. I'll reply as well.

          Show
          Charles Oliver Nutter added a comment - Simone: Thanks for posting that. I'll reply as well.
          Hide
          Daniel Berger added a comment -

          I think the logic can be found in the search_required function in eval.c. Not pretty.

          Show
          Daniel Berger added a comment - I think the logic can be found in the search_required function in eval.c. Not pretty.
          Hide
          Charles Oliver Nutter added a comment -

          I'm satisfied calling this "Won't Fix".

          I believe the consistency from having .so and other extensions trigger an "extension load" in require is better than having to also do all the .rb searching on top of those extensions (which would slow extension file searches even more, and possibly load a .rb file when you really want it to load a .so.)

          Workaround is to simply require the full name (foo.so.rb) if you know it's a .rb file.

          Show
          Charles Oliver Nutter added a comment - I'm satisfied calling this "Won't Fix". I believe the consistency from having .so and other extensions trigger an "extension load" in require is better than having to also do all the .rb searching on top of those extensions (which would slow extension file searches even more, and possibly load a .rb file when you really want it to load a .so.) Workaround is to simply require the full name (foo.so.rb) if you know it's a .rb file.

            People

            • Assignee:
              Charles Oliver Nutter
              Reporter:
              Simone Carletti
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: