从Java启动的JRuby脚本加载JNI库失败

时间:2014-12-14 15:28:42

标签: java java-native-interface jruby

我想加载Apple的mDNS库以用于JRuby应用程序。 JRuby应用程序作为Java进程启动,然后评估Ruby脚本。

这是一个最小的repro案例的Java代码,它只是抓住Ruby脚本&逃避它:

package mdnsscratch;

import com.apple.dnssd.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import org.jruby.Ruby;
import org.jruby.RubyInstanceConfig;
import org.jruby.RubyRuntimeAdapter;
import org.jruby.javasupport.JavaEmbedUtils;
import org.jruby.runtime.builtin.IRubyObject;

public final class Main {
  public static void main(final String[] args) throws DNSSDException, IOException {
    final Main m = new Main();
    final byte[] buffy = Files.readAllBytes(Paths.get(args[0]));
    m.run(new String(buffy));
  }

  private void run(final String cmd) {
    //System.out.println("About to eval: "+ cmd);
    // Get a ruby runtime
    final RubyInstanceConfig rubyConfig = new RubyInstanceConfig();
    rubyConfig.setExternalEncoding("UTF-8");
    rubyConfig.setInternalEncoding("UTF-8");

    final Ruby runtime = JavaEmbedUtils.initialize(new ArrayList(), rubyConfig);
    final RubyRuntimeAdapter rubyEvaluater = JavaEmbedUtils.newRuntimeAdapter();

    final IRubyObject iro = rubyEvaluater.eval(runtime, cmd);
    System.out.println(iro.toString());
  }
}

这里有一个最小的Ruby脚本来重现问题:

require 'java'
require 'lib/dns_sd.jar'

# Listener
class RegistrarListener
  def recordRegistered(record, flags)
  end
  def operationFailed(service, errorCode)
    puts "WARNING: mDNS operation failed"
  end
end

# Registrar
puts "About to register"
DNSSD = Java::ComAppleDnssd::DNSSD
@@registrar = DNSSD.createRecordRegistrar(RegistrarListener.new)
puts "Done registering"

mDNS库有很多原生代码,所以我在lib /中有dns_sd.jar和.dylib(我在Mac上)。使用JRuby进行直接评估工作正常:

$ jruby -J-Djava.library.path=lib test_mdns.rb
About to register
Done registering

但是使用Java包装器失败了:

$ java -Djava.library.path=lib -cp target/classes:lib/dns_sd.jar:/opt/jruby/lib/jruby.jar mdnsscratch.Main test_mdns.rb
Exception in thread "main" org.jruby.exceptions.RaiseException: (LoadError) no such file to load -- lib/dns_sd
    at org.jruby.RubyKernel.require(org/jruby/RubyKernel.java:1071)
    at RUBY.(root)(<script>:4)

似乎JRuby从Java包装器调用时,看不到mDNS库的JNI部分。

有人可以帮忙吗?很高兴回应评论&amp;根据需要提供额外信息。

好的,所以这是实际由JRuby运行的Java命令:

/Library/Java/JavaVirtualMachines/java8/Contents/Home/bin/java -Xmx500m 
-Xss2048k -Djffi.boot.library.path=/opt/jruby-1.7.17/lib/jni 
-Djava.library.path=lib -Dfile.encoding=UTF-8 
-Xbootclasspath/a:/opt/jruby-1.7.17/lib/jruby.jar 
-classpath : -Djruby.home=/opt/jruby-1.7.17 
-Djruby.lib=/opt/jruby-1.7.17/lib -Djruby.script=jruby 
-Djruby.shell=/bin/sh org.jruby.Main test_mdns.rb

此等效命令行:

/Library/Java/JavaVirtualMachines/java8/Contents/Home/bin/java -Xmx500m 
-Xss2048k -Djffi.boot.library.path=/opt/jruby-1.7.17/lib/jni 
-Djava.library.path=lib -Dfile.encoding=UTF-8 
-Xbootclasspath/a:/opt/jruby-1.7.17/lib/jruby.jar 
-classpath target/classes:lib/dns_sd.jar 
-Djruby.home=/opt/jruby-1.7.17 -Djruby.lib=/opt/jruby-1.7.17/lib 
-Djruby.script=jruby -Djruby.shell=/bin/sh mdnsscratch.Main test_mdns.rb

仍然会出错。目前正在查看JRuby源代码,我看到一个特殊的线程局部类加载器,这很有趣,特别是当JRuby调用包含一个空的classpath参数时。

2 个答案:

答案 0 :(得分:0)

  从bootclasspath加载的

类只能链接到库中   $ JAVA_HOME / bin中

http://jira.codehaus.org/browse/JRUBY-4620

答案 1 :(得分:0)

来自Twitter上的对话:&#34; JRuby启动器放置。在classpath中类似于java命令,但是你的java cmd指定了一个类路径,所以没有pwd。&#34;

添加。到类路径修复此:

java -Djava.library.path=lib -cp target/classes:lib/dns_sd.jar:/opt/jruby/lib/jruby.jar:. mdnsscratch.Main test_mdns.rb
About to register
Done registering