When I compile a ruby file to a java class using jrubyc
, I get different output when compiling with just jrubyc
and with jrubyc --java
(to generate the java file) and just javac
. Why?
Example:
First method:
jrubyc --java myscript.rb
javac -cp .:./jruby-complete.jar myscript.java
Second Method:
jrubyc myscript.rb
I'd expect the generated classes to be exactly the same, but they're not. What's jrubyc
doing under the covers?
Thanks!
jrubyc myscript.rb
compiles the Ruby file for JRuby consumption and cannot be used from Java, hence the name AOT. The code used to compile it is the normal JRuby compiler that's used to transform to bytecode. You can only use the resulting myscript.class
in a JRuby script, using for instance require 'myscript'
. When using javap
:
ubuntu@ubuntu:/tmp$ javap myscript
Compiled from "myscript.rb"
public class myscript extends org.jruby.ast.executable.AbstractScript {
public myscript();
public static org.jruby.runtime.builtin.IRubyObject __file__(myscript, org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.builtin.IRubyObject[], org.jruby.runtime.Block);
public org.jruby.runtime.builtin.IRubyObject __file__(org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.builtin.IRubyObject[], org.jruby.runtime.Block);
public static org.jruby.runtime.builtin.IRubyObject class_0$RUBY$MyScript(myscript, org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.Block);
public static org.jruby.runtime.builtin.IRubyObject method__1$RUBY$run(myscript, org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.Block);
public static org.jruby.runtime.builtin.IRubyObject method__1$RUBY$run(myscript, org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.builtin.IRubyObject[], org.jruby.runtime.Block);
public static org.jruby.runtime.builtin.IRubyObject class_0$RUBY$MyScript(myscript, org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, org.jruby.runtime.builtin.IRubyObject[], org.jruby.runtime.Block);
public org.jruby.runtime.builtin.IRubyObject load(org.jruby.runtime.ThreadContext, org.jruby.runtime.builtin.IRubyObject, boolean);
public static void main(java.lang.String[]);
}
we see the extended class inherits org.jruby.ast.executable.AbstractScript
and defines lots of internal methods, so it is clear this code is for JRuby's AST use.
That's why jrubyc
provides two extra options: --java
and --javac
: the first one generates the Java source code that wraps the code to the JRuby script using ScriptingContainer
, just as you normally would with the original script; the second one produces directly the compiled Java class directly. This code uses specific Java generator code that uses directives such as java_signature
to give the Java methods the correct signatures as expected by Java. When using javap
again:
ubuntu@ubuntu:/tmp$ jrubyc --javac myscript.rb
ubuntu@ubuntu:/tmp$ javap MyScript
Compiled from "MyScript.java"
public class MyScript extends org.jruby.RubyObject {
public static org.jruby.runtime.builtin.IRubyObject __allocate__(org.jruby.Ruby, org.jruby.RubyClass);
public MyScript();
public java.lang.Object run();
static {};
}
the class starts with an uppercase M, and inherits RubyObject
. Methods defined in the class will be exposed for Java consumption.
Using JRuby: Bringing Ruby to Java has a good description of these two forms in Chapter 4, The JRuby Compiler.