How to Call C++ Functions from Within Ruby

Calling C code from within Ruby -- How to use the returned pointer?

While I don't know why the Win32API approach did not work, I've found an easier solution using FFI to the problem of calling C functions from within Ruby or interfacing with DLLs.


Solution using FFI

Use FFI in Ruby for interfacing with DLLs, as follows:

  • (1) Install ffi (works with ruby 1.9.3, ymmv with previous versions)

    gem install ffi

  • (2) Create your own Ruby module to wrap the C function

require 'ffi'

module CodeGen # Ruby wrapper (your choice)
extend FFI::Library
ffi_lib 'codegen' # DLL name (given)
attach_function
:create_code, # method name (your choice)
:CreateCodeShort3, # DLL function name (given)
[ :int, :string, :string, :uint, :ushort, :ushort], :string
# specify C param / return value types
end

ret_str = CodeGen.create_code(3, "foo", "bar", 0,0,0)

puts ret_str
  • (3) Run. Result gives a string as desired.

Done!

Embedding Ruby, calling a function from C

Short answer:

extern VALUE rb_vm_top_self(void); /* Assumes 1.9.  Under 1.8, use the global
* VALUE ruby_top_self
*/
...
rb_funcall(rb_vm_top_self(), /* irb> RubyFunction() */
rb_intern("RubyFunction"), /* irb> self.RubyFunction() # same thing */
0,
NULL);

Longer answer:

The first argument to rb_funcall is the receiver of the method call.

Assuming you defined RubyFunction() outside of any explicit class or module context, then it is added to the eigenclass of the implicit, main object at the "top level" of every ruby vm.

In ruby, this object is accessible as the top-level self:

$ cat myRubyFile.rb
# file: myRubyFile.rb
def foo
puts "foo"
end

$ irb
irb> require "myRubyFile"
=> true
irb> foo
foo
=> nil
irb> self.foo() # same thing, more explicit
foo
=> nil
irb> self
=> main

In C under 1.9 it is accessible as indicated above.

C/C++ within Ruby code?

Besides "Extending Ruby", here are two other resources:

  • README.EXT (extension.rdoc) - shows you more about how to build C extensions. A good compliment to "Extending Ruby"
  • Ruby Inline - This is a library that tries to make it easier to build C extensions by having you call methods in ruby to compile C code.

Trying to call C program from Ruby script

You say you are trying to call a program so I assume you are not trying to statically or dynamically load a library and call a function. (If you are trying to load a library to call a function then look to the DL::Importer module.)

As for calling an external program from Ruby and receiving its result (from stdout, in this case), regardless of whether it was written in C or not, an easy way to do it is:

value = `program arg1 arg2 ...`

e.g. if the program you want to call compresses a given file and outputs the compressed size.

size = `mycompressionprogram filename.txt`
puts "compressed result is: #{size}"

Note those are back ticks " ` ".

So this is one easy way to code your computationally heavy stuff in C and wrap it up in a Ruby script.

Calling Ruby class methods from C++

First off, go is, as you've defined it, not a class method, but an instance method.

As an object oriented language, all ruby methods require a receiver, that is, an object that the method is invoked on. For instance methods, the receiver is an instance of the class, for class methods, the receiver is the class object itself.

The ? placeholder you have is the slot for the receiver of the method call.

If you want to leave it as an instance method, then you need to do this:

rb_funcall(a_CallTest_instance, rb_intern("go"), 0);

where a_CallTest_instance was an instance of CallTest you created using rb_class_new_instance().

If you make it into a class method:

class CallTest
def self.go
# ...
end
end

Then you need to use the CallTest class itself as the receiver:

rb_funcall(klass, rb_intern("go"), 0);

You can get a reference to the CallTest class using rb_const_get()

VALUE klass = rb_const_get(rb_cObject, rb_intern('CallTest'));

Use rb_cObject there, since CallTest is defined in the global context.

I'd suggest reading the chapter in the Pickaxe about extending ruby.



Related Topics



Leave a reply



Submit