Link D 库到 Ruby
Link a D library to Ruby
我想从 Ruby 调用 D 代码。我试图用 dmd 编译 D 代码并使用 extconf.rb 制作一个我可以在 ruby 中使用的共享对象文件,但我的链接不知何故失败,D std 库显然丢失了:
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 -
您可以使用 Ruby-FFI extension. Take a look at this Wiki 从 Ruby 调用 D,它通过示例解释了如何做到这一点。比如下面这个:
创建包含
的文件"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
我想从 Ruby 调用 D 代码。我试图用 dmd 编译 D 代码并使用 extconf.rb 制作一个我可以在 ruby 中使用的共享对象文件,但我的链接不知何故失败,D std 库显然丢失了:
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 -
您可以使用 Ruby-FFI extension. Take a look at this Wiki 从 Ruby 调用 D,它通过示例解释了如何做到这一点。比如下面这个:
创建包含
的文件"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