C++ DLL example


#1

Can someone point me to a simple example of calling a C++ function from
Ruby?
I know how to do it with SWIG, but I’m trying to learn how to do it
without SWIG.
I’d like to do this under Windows and have the C++ code in a DLL.
No Windows APIs will be invoked. I just want to do something simple in
C++ like this

static void greet(const string& name) {
cout << "Hello " << name << endl;
}

and invoke the greet function from Ruby.

I know how to build a DLL using VC++ 8.
I suspect the issue is that I don’t have the right setup in my .cpp
file.


#2

The way I do it is to make sure all entry points in the C++ file are
extern “C”
and create a C wrapper file that calls the C++ funcs which have C
linkage.
Then I run extconf.rb for this wrapper file to create a Ruby extension
makefile.
I picked most of this up from Pickax I, “Extending Ruby.”

Also, for some reason I cannot fathom, I had to replace all C++ I/O with
C I/O
routines. After doing that, I was able to compile the C++ file, then
compile the
C extension and properly link everything together as long as I
remembered to add
-lstdc++ as a link option. I always link to either a .a or a .o so I
don’t know
how well this applies to a dll.

This was all done with Windows XP / Cygwin / gcc, so my particulars
probably do
not apply to your situation, but the overall plan of attack could be
applied.

BTW, you wont be able to link to a ‘static’ function. It would be better
to
rewrite it like this:

.cpp file:
extern “C” void greet(char *name) {
// C++ stuff here

printf( "Hello %s\n", name );

}

and then I would create a standard .c wrapper file for this, where the
Ruby extension initialization code is put.


#3

Mark V. wrote:

Can someone point me to a simple example of calling a C++ function from
Ruby?
I know how to do it with SWIG, but I’m trying to learn how to do it
without SWIG.
I’d like to do this under Windows and have the C++ code in a DLL.
No Windows APIs will be invoked. I just want to do something simple in
C++ like this

static void greet(const string& name) {
cout << "Hello " << name << endl;
}

and invoke the greet function from Ruby.

I know how to build a DLL using VC++ 8.
I suspect the issue is that I don’t have the right setup in my .cpp
file.

I had a question on C++ extensions that contained some code examples.
Its here http://www.ruby-forum.com/topic/57404#new.

Gareth


#4

Thanks for the detailed instructions Simon!

I’m trying to build my DLL with Visual C++ 2005 Express Edition which
is free. I saw your warning about the possibility that this won’t work
because the one-click installer is compiled with VC6. I’m not able to
get to the point to test that though. I’m getting a compile error that
says win32.h needs windows.h and it can’t find that. I searched my
entire hard drive for windows.h and only found one under my cygwin
directory. I don’t want to use that one because I want to find a
solution that doesn’t assume cygwin is installed. Any idea why it’s
looking for windows.h and where it should be?


#5

Hi Mark,

it’s not that hard, your cpp file should/could look like this:


#include “ruby.h”
#include
#include

using namespace std;

static void greet(const string& name) {
cout << "Hello " << name << endl;
}

static VALUE rb_greet(VALUE self, VALUE name){
greet(STR2CSTR(name));
return Qnil;
}

void Init_RubyDll() {
rb_define_global_function(“greet”, (VALUE(*)(ANYARGS))rb_greet, 1);
}

Add this to a new dll project, add the path to ruby.h to the project
settings and link against msvcrt-ruby18.lib.

Finally you have to export the Init_XXX (XXX has to be equal to the name
of your Dll) function. I usually add a /EXPORT:Init_RubyDll to the
command line options of the linker.

After doing so i could execute

C:>ruby -e “require ‘RubyDll’; greet 'Mark '”
Hello Mark

Hope that helps.

cheers

Simon

p.s.: one gotcha left: The ruby in the one-click-installer is compiled
with vc6, linking to libs from another version might be risky.

Mark V. schrieb: