Building an extension in C++

I'm using cygwin to try to build an extension in C++. I've stripped
down the pickaxe book's example (http://www.rubycentral.com/pickaxe/
ext_ruby.html) to the bare minimum. It looks like:

#include "ruby.h

VALUE cTest;

void Init_Test() {
  cTest = rb_define_class("Test", rb_cObject);
}

If I name the file Test.c, it works nicely. If I name the file
Test.cpp I get the following error when I try to require the file in
irb.

LoadError: No such file or directory - /usr/lib/ruby/site_ruby/1.8/
i386-cygwin/Test.so
  from /usr/lib/ruby/site_ruby/1.8/i386-cygwin/Text.so
  from (irb):1

For the whole proceedure I do:

make clean
ruby extconf.rb
make
make install
irb
require "Test"

Any helpful ideas?

Although it is not the source of the problem with the shared object
not being found, you need to declare Init_Test with C linkage
(extern "C"), or else Ruby will not be able to find the entry point.

Besides this, though, safe handling of C++ and Ruby exceptions is
extremely difficult when writing an extension in C++. You should
probably consider writing the Ruby-facing portion of extension in
C, with a C-linkage interface to the C++ portion of the extension,
and be sure to intercept any C++ exceptions before they can cross
into C or Ruby and create havoc. Similarly, C++ code should not
raise Ruby exceptions or call anything which could raise them.

-mental

···

On Sat, 20 Oct 2007 07:15:05 +0900, Gary <gapjunk@gmail.com> wrote:

I'm using cygwin to try to build an extension in C++. I've stripped
down the pickaxe book's example (http://www.rubycentral.com/pickaxe/
ext_ruby.html) to the bare minimum. It looks like:

#include "ruby.h

VALUE cTest;

void Init_Test() {
  cTest = rb_define_class("Test", rb_cObject);
}

Thank you mental!!! It works. I should have figured it out myself,
but I needed your help.

I'm I bit confused about a C-linkage interface to the C++ portion. Is
this going to be more than wrapping the C++ calls in try catch(...)
In other words having something like

extern "C" VALUE t_init(VALUE self)
{
  //declare any Ruby C++ data conversion vars in C
  try
    {
    //call C++ functions
    }
  catch(...)
    {
    //process exceptions
    }
  //Do any data interactions between C++ and Ruby
}

Once again, thanks! I spent several hours stumped.

     -Gary

···

On Oct 19, 3:33 pm, MenTaLguY <men...@rydia.net> wrote:

On Sat, 20 Oct 2007 07:15:05 +0900, Gary <gapj...@gmail.com> wrote:
> I'm using cygwin to try to build an extension in C++. I've stripped
> down the pickaxe book's example (http://www.rubycentral.com/pickaxe/
> ext_ruby.html) to the bare minimum. It looks like:

> #include "ruby.h

> VALUE cTest;

> void Init_Test() {
> cTest = rb_define_class("Test", rb_cObject);
> }

Although it is not the source of the problem with the shared object
not being found, you need to declare Init_Test with C linkage
(extern "C"), or else Ruby will not be able to find the entry point.

Besides this, though, safe handling of C++ and Ruby exceptions is
extremely difficult when writing an extension in C++. You should
probably consider writing the Ruby-facing portion of extension in
C, with a C-linkage interface to the C++ portion of the extension,
and be sure to intercept any C++ exceptions before they can cross
into C or Ruby and create havoc. Similarly, C++ code should not
raise Ruby exceptions or call anything which could raise them.

-mental

That'll probably suffice. You might get a bit better results by catching explicit exception types and converting them to Ruby world exceptions. Other than that your code should prevent any havoc caused by C++ exceptions raised into the Ruby interpreter.

Kind regards

  robert

···

On 20.10.2007 17:19, Gary wrote:

Thank you mental!!! It works. I should have figured it out myself,
but I needed your help.

I'm I bit confused about a C-linkage interface to the C++ portion. Is
this going to be more than wrapping the C++ calls in try catch(...)
In other words having something like

extern "C" VALUE t_init(VALUE self)
{
  //declare any Ruby C++ data conversion vars in C
  try
    {
    //call C++ functions
    }
  catch(...)
    {
    //process exceptions
    }
  //Do any data interactions between C++ and Ruby
}

Once again, thanks! I spent several hours stumped.

Thank you Robert! I agree and understand about catching and
converting C++ exceptions to Ruby exceptions.

Now, on to my next problem. When I try using new I get linker errors
(grrr)

extern "C" void Init_Test() {
  cTest = rb_define_class("Test", rb_cObject);

  try
  {
    int *x=new int;
  }
  catch (...)
  {
  }
}

I get the following errors:

undefined reference to '___gxx_personality_sj0'
undefined reference to 'operator new(unsigned int)
undefined reference to '___cxa_begine_catch'
undefined reference to '___cxa_end_catch'

It compiles nicely if I replace:
  int *x=new int;
with
  int *x=NULL

     -Gary

···

On Oct 20, 9:05 am, Robert Klemme <shortcut...@googlemail.com> wrote:

On 20.10.2007 17:19, Gary wrote:

> Thank you mental!!! It works. I should have figured it out myself,
> but I needed your help.

> I'm I bit confused about a C-linkage interface to the C++ portion. Is
> this going to be more than wrapping the C++ calls in try catch(...)
> In other words having something like

> extern "C" VALUE t_init(VALUE self)
> {
> //declare any Ruby C++ data conversion vars in C
> try
> {
> //call C++ functions
> }
> catch(...)
> {
> //process exceptions
> }
> //Do any data interactions between C++ and Ruby
> }

> Once again, thanks! I spent several hours stumped.

That'll probably suffice. You might get a bit better results by
catching explicit exception types and converting them to Ruby world
exceptions. Other than that your code should prevent any havoc caused
by C++ exceptions raised into the Ruby interpreter.

Kind regards

        robert

Are you compiling with gcc or g++?

Paul

···

On Sun, Oct 21, 2007 at 01:55:03AM +0900, Gary wrote:

Now, on to my next problem. When I try using new I get linker errors
(grrr)

When I type make the line says

g++ (blah blah blah)

Although when I look at the Makefile it has the following line:

CC = gcc

If it is any help, my extconf.rb is as follows:

require 'mkmf'
create_makefile("Test")

I hope I've given you as much information as you need, and perhaps
more =-)

Thank you Paul

···

On Oct 24, 6:55 am, Paul Brannan <pbran...@atdesk.com> wrote:

On Sun, Oct 21, 2007 at 01:55:03AM +0900, Gary wrote:
> Now, on to my next problem. When I try using new I get linker errors
> (grrr)

Are you compiling with gcc or g++?

Paul

Hi,

At Sat, 27 Oct 2007 06:25:00 +0900,
Gary wrote in [ruby-talk:276038]:

Although when I look at the Makefile it has the following line:

CC = gcc

mkmf.rb in 1.8 doesn't support C++.

Perhaps make has default macro CXX and a rule for C++. But C++ runtime
library isn't linked by default using gcc, you'll need to add the
library in extconf.rb explicitly, like as:

  have_library("stdc++")

···

--
Nobu Nakada

Thank you Nobu!!! Your a genius!

This cleared up the last of my problems! Wheee!!!!

     -Gar

···

On Oct 26, 4:40 pm, Nobuyoshi Nakada <n...@ruby-lang.org> wrote:

Hi,

At Sat, 27 Oct 2007 06:25:00 +0900,
Gary wrote in [ruby-talk:276038]:

> Although when I look at the Makefile it has the following line:

> CC = gcc

mkmf.rb in 1.8 doesn't support C++.

Perhaps make has default macro CXX and a rule for C++. But C++ runtime
library isn't linked by default using gcc, you'll need to add the
library in extconf.rb explicitly, like as:

  have_library("stdc++")

--
Nobu Nakada