Difference between revisions of "Call D from Ruby using FFI"

From D Wiki
Jump to: navigation, search
(Created page with "Adam Ruppe posted this example in the [http://forum.dlang.org/post/fatqnbivseurruxsxsoh@forum.dlang.org Learn Forum]. The goal is to write a function in D and call it from Rub...")
 
 
(2 intermediate revisions by one other user not shown)
Line 5: Line 5:
 
Create the file "i.d" containing
 
Create the file "i.d" containing
  
import std.stdio;
+
<syntaxhighlight lang="d">
+
import std.stdio;
extern(C)
+
 
void hello() {
+
extern(C)
  writeln("hi from D");
+
void hello()
}
+
{
 +
writeln("hi from D");
 +
}
 +
</syntaxhighlight>
  
 
Compile it as a shared library. For example, to compile as a 64-bit shared library on Linux, you can do
 
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
+
<syntaxhighlight lang="bash">
 +
dmd -shared -m64 -fPIC -defaultlib=libphobos2.so i.d
 +
</syntaxhighlight>
  
 
Create the file "d.rb" containing
 
Create the file "d.rb" containing
  
 +
<syntaxhighlight lang="ruby">
 
  require 'rubygems'
 
  require 'rubygems'
 
  require 'ffi'
 
  require 'ffi'
Line 37: Line 43:
 
  # terminate
 
  # terminate
 
  DInterface::rt_term
 
  DInterface::rt_term
 +
</syntaxhighlight>
  
 
Run the Ruby file:  
 
Run the Ruby file:  
  
ruby ./d.rb
+
<syntaxhighlight lang="bash">
 +
ruby ./d.rb
 +
</syntaxhighlight>
  
 
You should see
 
You should see
Line 48: Line 57:
 
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:
 
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
+
<syntaxhighlight lang="bash">
 +
LD_LIBRARY_PATH=/path/to/dmd2/linux/lib64 ruby ./d.rb
 +
</syntaxhighlight>
  
 
==More Convenient Version==
 
==More Convenient Version==
Line 56: Line 67:
 
Create "i.d":
 
Create "i.d":
  
import std.stdio;
+
<syntaxhighlight lang="d">
import std.conv;
+
import std.stdio;
+
import std.conv;
extern(C)
+
 
void hello(const char* name) {
+
extern(C)
  // remember, it is a C function, so use C string
+
void hello(const char* name)
  // and convert inside
+
{
  writeln("hi from D, ", to!string(name));
+
// remember, it is a C function, so use C string
}
+
// and convert inside
 +
writeln("hi from D, ", to!string(name));
 +
}
 +
</syntaxhighlight>
  
 
Create "d.rb":
 
Create "d.rb":
  
 +
<syntaxhighlight lang="ruby">
 
  require 'rubygems'
 
  require 'rubygems'
 
  require 'ffi'
 
  require 'ffi'
Line 87: Line 102:
 
   DInterface::rt_term
 
   DInterface::rt_term
 
  end
 
  end
 +
</syntaxhighlight>
  
 
Create "user.rb":
 
Create "user.rb":
  
 +
<syntaxhighlight lang="ruby">
 
  require './d'
 
  require './d'
 
   
 
   
 
  DInterface::hello 'Ruby user!'
 
  DInterface::hello 'Ruby user!'
 +
</syntaxhighlight>
  
 
Compile and run (Linux 64-bit version):
 
Compile and run (Linux 64-bit version):
  
dmd -shared -m64 -fPIC -defaultlib=libphobos2.so i.d
+
<syntaxhighlight lang="bash">
LD_LIBRARY_PATH=~/d/dmd2/linux/lib64 ruby ./user.rb
+
dmd -shared -m64 -fPIC -defaultlib=libphobos2.so i.d
 +
LD_LIBRARY_PATH=~/d/dmd2/linux/lib64 ruby ./user.rb
 +
</syntaxhighlight>
 +
 
 +
 
 +
[[Category:HowTo]]

Latest revision as of 13:24, 3 March 2018

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