Call D from Ruby using FFI
Adam Ruppe posted this example in the Learn Forum. The goal is to write a function in D and call it from Ruby using the Ruby-FFI extension.
Shorter Version
Create the file "i.d" containing
import std.stdio; extern(C) void hello() { writeln("hi from D"); }
Compile it as a shared library. For example, to compile as a 64-bit shared library on Linux, you can do
dmd -shared -m64 -fPIC -defaultlib=libphobos2.so i.d
Create the file "d.rb" containing
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
Run the Ruby file:
ruby ./d.rb
You should see
hi from D
If you have the phobos shared lib installed system wide, that should work. If not, you'll get an error about not being able to find the libphobos2.so.whatever.version. In that case, just point the path:
LD_LIBRARY_PATH=/path/to/dmd2/linux/lib64 ruby ./d.rb
More Convenient Version
You might want to make it a bit more automatic for the Ruby user. You can do that by calling rt_init
in the include file and doing an at_exit
for the term.
Create "i.d":
import std.stdio; import std.conv; extern(C) void hello(const char* name) { // remember, it is a C function, so use C string // and convert inside writeln("hi from D, ", to!string(name)); }
Create "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 # now taking a string attach_function :hello, :hello, [:string], :void end # call init right here for the user DInterface::rt_init # terminate automatically at_exit do DInterface::rt_term end
Create "user.rb":
require './d' DInterface::hello 'Ruby user!'
Compile and run (Linux 64-bit version):
dmd -shared -m64 -fPIC -defaultlib=libphobos2.so i.d LD_LIBRARY_PATH=~/d/dmd2/linux/lib64 ruby ./user.rb