2016-02-10 77 views
3

我想從Ruby中調用D代碼。我試圖用DMD編譯d代碼,並使用extconf.rb來讓我能在紅寶石使用共享對象文件,但我不知何故鏈接失敗時,d STD庫顯然是缺少:將D庫鏈接到Ruby

hello.rb:1:in `require_relative': /tmp/druby/hello_c.so: undefined symbol: _D3std5stdio12__ModuleInfoZ - /tmp/druby/hello_c.so (LoadError) 
    from hello.rb:1:in `<main>' 

請讓我知道如何從Ruby調用D代碼。

我嘗試的代碼是在這裏:

mkdir -p /tmp/druby 
    cd /tmp/druby 
    cat ->hello_d.d <<EOF 
    import std.stdio; 
    // a D function that we would like to call from ruby 
    extern(C) void hello_d() nothrow { 
     try { writeln("hello from d"); } catch(Throwable t) {} 
    } 
    EOF 

    cat ->hello_d.c <<EOF 
    /* This is a dummy file to trick extconf.rb to include the hello_d.o file, surely this could be done from extconf.rb as well, but how? */ 
    EOF 

    cat ->hello_c.c <<EOF 
    #include <stdio.h> 
    #include "ruby.h" 

    /* c function */ 
    void hello_c(){ 
     printf("hello from c\n"); 
    } 


    /* ruby function for hello_c */ 
    VALUE method_hello_c(VALUE self){ 
     hello_c(); 
     return Qnil; 
    } 


    /* ruby function for hello_d */ 
    VALUE method_hello_d(VALUE self){ 
     if(!rt_init()) { return 1; } 
     hello_d(); 
     rt_term(); 
     return Qnil; 
    } 


    /* ruby module and class definition */ 
    /* This method must be named "Init_#{filename.lower}" */ 
    void Init_hello_c() { 
     VALUE hello_module = rb_define_module("HelloCModule"); 
     VALUE hello_class = rb_define_class_under(hello_module, "HelloC", rb_cObject); 
     rb_define_method(hello_class, "hello_c", method_hello_c, 0); 
     rb_define_method(hello_class, "hello_d", method_hello_d, 0); 
    } 

    EOF 

    cat ->extconf.rb <<EOF 
    # Loads mkmf which is used to make makefiles for Ruby extensions 
    require 'mkmf' 

    lib = File.expand_path('../../lib', __FILE__) 
    \$LOAD_PATH.unshift(lib) unless \$LOAD_PATH.include?(lib) 

    # Give it a name 
    extension_name = 'hello_c' 

    # The destination 
    dir_config(extension_name,".") 

    with_cflags('-fPIC -Wall -O3 -rdynamic -m64 -L/usr/lib/x86_64-linux-gnu -Xlinker --export-dynamic -Xlinker -Bstatic -lphobos2 -Xlinker -Bdynamic -lpthread -lm -lrt -ldl') do 
     create_makefile(extension_name) 
    end 

    EOF 

    cat ->hello.rb <<EOF 
    require_relative 'hello_c' 

    puts "hello from ruby" 

    hello_c = HelloCModule::HelloC.new 

    hello_c.hello_c() 

    EOF 


    # 1. First make the hello_d.o file 
    dmd -c -fPIC hello_d.d -defaultlib=libphobos2.so 


    # 2. Make the ruby Makefile 
    ruby extconf.rb 

    # 3. Compile the shared library 
    make 

    # 4. Try to call it from ruby 
    ruby hello.rb 

    cd - 
+0

您鏈接到Phobos共享庫嗎?看起來不是,嘗試在'dmd'命令中添加'-defaultlib = libphobos2.so'。 –

+0

我曾嘗試將libphobos2.so添加到dmd命令(請參閱上面的修改代碼),但它不會更改結果,無論如何都要感謝您的建議。另外phobos2庫已經在cflags中。 –

+0

您在單個代碼塊中列出文件和命令的方式非常繁瑣。 – weltensturm

回答

1

您可以在Ruby使用Ruby-FFI分機呼叫d。看一下this Wiki,它解釋瞭如何用示例來完成這個工作。如以下各項之一:

創建文件「I.D」含有

import std.stdio; 

extern(C) 
void hello() 
{ 
    writeln("hi from D"); 
} 

編譯爲一個共享庫。例如,編譯爲Linux上的64位共享庫,你可以做

dmd -shared -m64 -fPIC -defaultlib=libphobos2.so i.d 

創建文件 「d.rb」 載:

require 'rubygems' 
require 'ffi' 

module DInterface 
extend FFI::Library 
ffi_lib './i.so' 
attach_function :rt_init, :rt_init, [], :int 
attach_function :rt_term, :rt_term, [], :int 
attach_function :hello, :hello, [], :void 
end 

# call init 
DInterface::rt_init 

# our function 
DInterface::hello 

# terminate 
DInterface::rt_term 

運行Ruby的文件:

ruby ./d.rb 

您應該看到hi from D

+1

FFI解決方案運行良好,我相信目前這是最好的解決方案。但是,由於FFI功能非常有限,在Ruby和D運行時環境之間維護和同步對象被證明具有挑戰性。 –