August 03, 2016
On Wednesday, 3 August 2016 at 15:24:56 UTC, llaine wrote:
> On Wednesday, 3 August 2016 at 15:14:24 UTC, Kagamin wrote:

After digging a bit more, I get a different error.

import std.stdio;
import core.runtime;

extern(C)
{
  void initialize()
  {
    Runtime.initialize();
  }

  void foo(string str)
  {
    writeln(str);
  }


  void terminate()
  {
    Runtime.terminate();
  }

}

on my code ofc I call the three methods and I get

uncaught exception
dwarfeh(224) fatal error
Abandon (core dumped)

August 03, 2016
On Wednesday, 3 August 2016 at 15:24:56 UTC, llaine wrote:
> On Wednesday, 3 August 2016 at 15:14:24 UTC, Kagamin wrote:
>> On Wednesday, 3 August 2016 at 15:08:51 UTC, llaine wrote:
>>> So basically I have to create wrapper.c ?
>>
>> Yes, but you should write it in D. Runtime initialization is at https://dlang.org/phobos/core_runtime.html#.Runtime
>
> Okay I tried to do something like this
>
>
> import std.stdio;
> import core.runtime;
>
> extern(C)
> {
>
>   void foo(string str)
>   {
>     writeln(str);
>   }
>
> }
>
> void main(){
>   Runtime.initialize();
>   Runtime.terminate();
> }
>
> Am I doing it wrong ?
> Still getting a Segmentation fault

I have no way to test this, but translating the example to D, I get this:

import core.runtime;
import std.stdio;

extern(C) {
  example_init() {
    Runtime.initialize();
  }

  example_exit() {
    Runtime.terminate();
  }

  void foo(int x) {
    writeln(2*x);
  }
}

// No main
// compile as libffi-example.so

Then in Ruby:

module Example
    extend DL::Importable
    dlload "./libffi-example.so"
    extern "void example_init()"
    extern "void example_exit()"
    extern "void foo(int)"
end

Example.example_init
Example.foo(3)
Example.example_exit

August 03, 2016
On Wednesday, 3 August 2016 at 15:47:48 UTC, bachmeier wrote:
> On Wednesday, 3 August 2016 at 15:24:56 UTC, llaine wrote:
>> On Wednesday, 3 August 2016 at 15:14:24 UTC, Kagamin wrote:
>>> On Wednesday, 3 August 2016 at 15:08:51 UTC, llaine wrote:
>>>> So basically I have to create wrapper.c ?
>>>
>>> Yes, but you should write it in D. Runtime initialization is at https://dlang.org/phobos/core_runtime.html#.Runtime
>>
>
> // No main
> // compile as libffi-example.so
>
> Then in Ruby:
>
> module Example
>     extend DL::Importable
>     dlload "./libffi-example.so"
>     extern "void example_init()"
>     extern "void example_exit()"
>     extern "void foo(int)"
> end
>
> Example.example_init
> Example.foo(3)
> Example.example_exit

Okay on stack overflow, they are not using ffi but dl.
I tried changing ffi to dl, it's the same don't work unfortunatly.


August 03, 2016
On Wednesday, 3 August 2016 at 15:56:34 UTC, llaine wrote:
> Okay on stack overflow, they are not using ffi but dl.
> I tried changing ffi to dl, it's the same don't work unfortunatly.

That's about as far as I can go without having it set up on my machine. The procedure should be the same as I spelled out though. You need to create an extern(C) function that calls Runtime.initialize(). Then you call that function from Ruby the same as any other function you call with FFI. I'm familiar with the R FFI and the only difference is that some parts of that are automated.
August 03, 2016
On Wednesday, 3 August 2016 at 15:56:34 UTC, llaine wrote:

>
> Okay on stack overflow, they are not using ffi but dl.
> I tried changing ffi to dl, it's the same don't work unfortunatly.

This FFI example calls an init function from a library:
https://github.com/ffi/ffi/blob/ce0e712bcb8876620e10c892d0b9005c84d92b53/samples/inotify.rb

August 04, 2016
On Wednesday, 3 August 2016 at 15:41:55 UTC, llaine wrote:

>   void foo(string str)
>   {
>     writeln(str);
>   }
>

shouldn't foo be:

void foo(char* str) {

    import std.string;
    writeln(str.fromStringz);

}


bye,
lobo
August 04, 2016
On Wednesday, 3 August 2016 at 16:09:15 UTC, bachmeier wrote:
> On Wednesday, 3 August 2016 at 15:56:34 UTC, llaine wrote:
>> Okay on stack overflow, they are not using ffi but dl.
>> I tried changing ffi to dl, it's the same don't work unfortunatly.
>
> That's about as far as I can go without having it set up on my machine. The procedure should be the same as I spelled out though. You need to create an extern(C) function that calls Runtime.initialize(). Then you call that function from Ruby the same as any other function you call with FFI. I'm familiar with the R FFI and the only difference is that some parts of that are automated.

Thank's for the help.

By creating two methods initialize/terminate using Runtime.initialize() it's crashing with this strange error.

I looked at the core.runtime source file and I saw a C binding for thoses one :

https://github.com/dlang/druntime/blob/master/src/core/runtime.d#L36

/// C interface for Runtime.initialize, returns 1/0 instead of bool
extern(C) int rt_init();
/// C interface for Runtime.terminate, returns 1/0 instead of bool
extern(C) int rt_term();

Any idea how can I call them ?


August 04, 2016
On Thursday, 4 August 2016 at 10:36:05 UTC, llaine wrote:
> Any idea how can I call them ?

Just like any other function. Consider this:

----------

// i.d
import std.stdio;

extern(C)
void hello() {
        writeln("hi from 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


----------


Compile... since I have 64 bit ruby on this computer, I had to build the 64 bit .so which is a pain:

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

Now, run the ruby:

ruby ./d.rb



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


And boom, it runs.


===============


Now, you might want to make it a bit more automatic for the Ruby user. I'd do that by calling rt_init in the include file and doing an at_exit for the term.

Let's also pass a string. So here's the new files:


---------
// 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));
}


--------

# 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

----------

# user.rb
# this is the user code

require './d'

DInterface::hello 'Ruby user!'

===========


Compile

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

and run

LD_LIBRARY_PATH=~/d/dmd2/linux/lib64 ruby ./user.rb

hi from D, Ruby user!
August 04, 2016
On Thursday, 4 August 2016 at 12:14:48 UTC, Adam D. Ruppe wrote:
> On Thursday, 4 August 2016 at 10:36:05 UTC, llaine wrote:
>> Any idea how can I call them ?
>
> Just like any other function. Consider this:
>
> ----------
> hi from D, Ruby user!


Wow thank you Adam, it's pretty impressive.

I saw that your compiling using dmd with all thoses options. Can you explain me what is the benefit of using this ?

I'm using just "dub" so far and its also working.

Here is my repo https://github.com/llaine/ruby-dlang

August 04, 2016
On Thursday, 4 August 2016 at 13:14:34 UTC, llaine wrote:
> I saw that your compiling using dmd with all thoses options. Can you explain me what is the benefit of using this ?

very simple: avoiding dub. Adam is not using it.