digitalmars.D.learn - C binding with D function
- llaine (29/29) Aug 03 2016 Hi guys,
- bachmeier (3/32) Aug 03 2016 Probably because you need the D runtime. One way is to import
- llaine (2/4) Aug 03 2016 Where should I call this Runtime.initialize() ?
- bachmeier (6/10) Aug 03 2016 Does the second answer to this question
- llaine (7/20) Aug 03 2016 So basically I have to create wrapper.c ?
- llaine (13/14) Aug 03 2016 On Wednesday, 3 August 2016 at 15:08:51 UTC, llaine wrote:
- Kagamin (3/4) Aug 03 2016 Yes, but you should write it in D. Runtime initialization is at
- llaine (17/21) Aug 03 2016 Okay I tried to do something like this
- llaine (23/24) Aug 03 2016 After digging a bit more, I get a different error.
- lobo (8/12) Aug 03 2016 shouldn't foo be:
- bachmeier (29/51) Aug 03 2016 I have no way to test this, but translating the example to D, I
- llaine (3/24) Aug 03 2016 Okay on stack overflow, they are not using ffi but dl.
- bachmeier (8/11) Aug 03 2016 That's about as far as I can go without having it set up on my
- llaine (13/24) Aug 04 2016 Thank's for the help.
- Adam D. Ruppe (82/83) Aug 04 2016 Just like any other function. Consider this:
- llaine (6/11) Aug 04 2016 Wow thank you Adam, it's pretty impressive.
- ketmar (2/4) Aug 04 2016 very simple: avoiding dub. Adam is not using it.
- Adam D. Ruppe (3/5) Aug 04 2016 I just don't use dub, I don't see the benefit of it, but if it
- Adam D. Ruppe (4/5) Aug 05 2016 FYI: to!string is kinda slow. If you want to do a fast blank, you
- Adam D. Ruppe (6/6) Aug 05 2016 A fun project might be to use D's reflection to automatically
- bachmeier (3/6) Aug 04 2016 I'd like to put this example on the wiki unless you think there
- Adam D. Ruppe (3/5) Aug 04 2016 cool. I'll prolly slap it in this week in D soon too (I've been
- Martin Tschierschke (7/12) Aug 04 2016 [...]
- bachmeier (3/6) Aug 03 2016 This FFI example calls an init function from a library:
- Adam D. Ruppe (13/17) Aug 03 2016 A D string isn't the same as a C string, so your params won't
- llaine (3/21) Aug 03 2016 Okay so your advice is to directly replace string str by char* str
Hi guys, I'm trying to make a bridge between D and ruby with a gem called ffi. It's basically a loading/binding library that grab C function and make them callable from Ruby code. As you might already understand, i'm trying to develop extensions using D and uses them in Ruby. I tried to get the simplest example ever but nothing is working so far. Basically here is my D code : import std.stdio : writeln; extern(C) { void puts(string str) { writeln(str); } } void main(){ } I'm building it using "targetType": "dynamicLibrary" on my dub.json My problem is when I try to call it in C, it blows up with a segmentation fault. I'm looking for here extra documentation/help on how to properly create C binding in D. I already post an issue on FFI to seek from help, you can find here some extra informations about the C trace https://github.com/ffi/ffi/issues/522 Any help would be welcomed!
Aug 03 2016
On Wednesday, 3 August 2016 at 13:44:46 UTC, llaine wrote:Hi guys, I'm trying to make a bridge between D and ruby with a gem called ffi. It's basically a loading/binding library that grab C function and make them callable from Ruby code. As you might already understand, i'm trying to develop extensions using D and uses them in Ruby. I tried to get the simplest example ever but nothing is working so far. Basically here is my D code : import std.stdio : writeln; extern(C) { void puts(string str) { writeln(str); } } void main(){ } I'm building it using "targetType": "dynamicLibrary" on my dub.json My problem is when I try to call it in C, it blows up with a segmentation fault. I'm looking for here extra documentation/help on how to properly create C binding in D. I already post an issue on FFI to seek from help, you can find here some extra informations about the C trace https://github.com/ffi/ffi/issues/522 Any help would be welcomed!Probably because you need the D runtime. One way is to import core.runtime and call Runtime.initialize().
Aug 03 2016
On Wednesday, 3 August 2016 at 13:49:36 UTC, bachmeier wrote:Probably because you need the D runtime. One way is to import core.runtime and call Runtime.initialize().Where should I call this Runtime.initialize() ?
Aug 03 2016
On Wednesday, 3 August 2016 at 14:01:34 UTC, llaine wrote:On Wednesday, 3 August 2016 at 13:49:36 UTC, bachmeier wrote:Does the second answer to this question http://stackoverflow.com/questions/676498/haskell-binding-with-ruby-through-ffi help? It's Haskell, but I think the hs_init function call is equivalent to Runtime.initialize. I've never done this sort of thing with Ruby so I might be missing something.Probably because you need the D runtime. One way is to import core.runtime and call Runtime.initialize().Where should I call this Runtime.initialize() ?
Aug 03 2016
On Wednesday, 3 August 2016 at 14:58:04 UTC, bachmeier wrote:On Wednesday, 3 August 2016 at 14:01:34 UTC, llaine wrote:So basically I have to create wrapper.c ? I guess my D code is not valid. For example, if I call it directly from a C program it would also breaks for sure. Is there any good documentation on it? I've look at the official documentation, but i'm afraid it might be too advanced for me.On Wednesday, 3 August 2016 at 13:49:36 UTC, bachmeier wrote:Does the second answer to this question http://stackoverflow.com/questions/676498/haskell-binding-with-ruby-through-ffi help? It's Haskell, but I think the hs_init function call is equivalent to Runtime.initialize. I've never done this sort of thing with Ruby so I might be missing something.Probably because you need the D runtime. One way is to import core.runtime and call Runtime.initialize().Where should I call this Runtime.initialize() ?
Aug 03 2016
On Wednesday, 3 August 2016 at 15:08:51 UTC, llaine wrote:On Wednesday, 3 August 2016 at 14:58:04 UTC, bachmeier wrote:On Wednesday, 3 August 2016 at 15:08:51 UTC, llaine wrote: by switching my file to just this extern(C) { char* foo(char* str) { return str; } } It works. But it's really ... simple ahah I was expecting to have more advanced use.
Aug 03 2016
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
Aug 03 2016
On Wednesday, 3 August 2016 at 15:14:24 UTC, Kagamin wrote:On Wednesday, 3 August 2016 at 15:08:51 UTC, llaine wrote: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 faultSo 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
Aug 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)
Aug 03 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
Aug 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: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_exitOn Wednesday, 3 August 2016 at 15:08:51 UTC, llaine wrote: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 faultSo 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
Aug 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: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.On Wednesday, 3 August 2016 at 15:14:24 UTC, Kagamin wrote:// 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_exitOn 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
Aug 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.
Aug 03 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: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 ?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.
Aug 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"); } ---------- 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 DInterface::rt_init DInterface::hello 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)); } -------- 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, [:string], :void end DInterface::rt_init at_exit do DInterface::rt_term end ---------- 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!
Aug 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: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-dlangAny idea how can I call them ?Just like any other function. Consider this: ---------- hi from D, Ruby user!
Aug 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.
Aug 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 ?I just don't use dub, I don't see the benefit of it, but if it works for you, cool!
Aug 04 2016
On Thursday, 4 August 2016 at 13:14:34 UTC, llaine wrote:Here is my repo https://github.com/llaine/ruby-dlangFYI: to!string is kinda slow. If you want to do a fast blank, you should avoid conversions.... actually, I'm surprised it is faster than the native Ruby one at all.
Aug 05 2016
A fun project might be to use D's reflection to automatically generate any C binding translators to a nice D interface and the Ruby file to access it. I did something similar back in the day for PHP and JavaScript... it would be kinda tricky to do it with best efficiency, but getting it to work just conveniently would be fairly easy.
Aug 05 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:I'd like to put this example on the wiki unless you think there is a reason to not do so.Any idea how can I call them ?Just like any other function. Consider this:
Aug 04 2016
On Thursday, 4 August 2016 at 14:46:33 UTC, bachmeier wrote:I'd like to put this example on the wiki unless you think there is a reason to not do so.cool. I'll prolly slap it in this week in D soon too (I've been kinda short on material lately!)
Aug 04 2016
On Thursday, 4 August 2016 at 17:11:04 UTC, Adam D. Ruppe wrote:On Thursday, 4 August 2016 at 14:46:33 UTC, bachmeier wrote:https://wiki.dlang.org/Call_D_from_Ruby_using_FFI Please edit as desired.I'd like to put this example on the wiki unless you think there is a reason to not do so.cool. I'll prolly slap it in this week in D soon too (I've been kinda short on material lately!)
Aug 04 2016
On Thursday, 4 August 2016 at 23:35:55 UTC, bachmeier wrote:On Thursday, 4 August 2016 at 17:11:04 UTC, Adam D. Ruppe wrote:Happy that you guys put this on the Wiki !!
Aug 05 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:Compile[...]hi from D, Ruby user!Thank you a lot!!! I want to use some vibe.d rendering inside Ruby on Rails, this gives me a god starting point, for my experiments. Regards mt.
Aug 04 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
Aug 03 2016
On Wednesday, 3 August 2016 at 13:44:46 UTC, llaine wrote:void puts(string str) { writeln(str); }A D string isn't the same as a C string, so your params won't work as-is, and writeln requires the D runtime to be initialized. Does the ruby gem have a way to automatically call a particular setup and teardown function in the library? You could make init and and finalize functions that are called. Those run the Runtime.initialized and Runtime.finalize. Looking at their docs, I don't see an automatic one, but you could do a ruby constructor/destructor in the wrapper that does it for the end user. For the D string, either replace it with a C char* or try defining a struct on teh ruby side to match it... but C string is probably easiest.
Aug 03 2016
On Wednesday, 3 August 2016 at 14:02:12 UTC, Adam D. Ruppe wrote:On Wednesday, 3 August 2016 at 13:44:46 UTC, llaine wrote:Okay so your advice is to directly replace string str by char* str and then call the runtime initialisation in my function?void puts(string str) { writeln(str); }A D string isn't the same as a C string, so your params won't work as-is, and writeln requires the D runtime to be initialized. Does the ruby gem have a way to automatically call a particular setup and teardown function in the library? You could make init and and finalize functions that are called. Those run the Runtime.initialized and Runtime.finalize. Looking at their docs, I don't see an automatic one, but you could do a ruby constructor/destructor in the wrapper that does it for the end user. For the D string, either replace it with a C char* or try defining a struct on teh ruby side to match it... but C string is probably easiest.
Aug 03 2016