# Ruby C++ extensions

**URL:** <https://rubytalk.org/t/ruby-c-extensions/11540>\
**Category:** ruby-talk\
**Created:** [14 May 2004 07:43 UTC](https://rubytalk.org/t/ruby-c-extensions/11540 "2004-05-14T07:43:54Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jeff\_Mitchell](https://avatars.discourse-cdn.com/v4/letter/j/e480ec/32.png) [@Jeff\_Mitchell](https://rubytalk.org/u/Jeff_Mitchell)\
**Post date:** [14 May 2004 07:43 UTC](https://rubytalk.org/t/ruby-c-extensions/11540/1 "2004-05-14T07:43:54Z")

</div>

The recent C++/ruby post has reminded me to say a few words about my  
travails in ruby C++ extensions, if only to possibly help some poor  
soul googling in the future.

First, require ‘mkmf’;create\_makefile(“cxxruby”) will use  
CONFIG[‘LDSHARED’] to create your extension, which is most likely  
wrong. For gcc this results in the error

undefined symbol: \_\_gxx\_personality\_v0

when you attempt to load the module. The linker must be C++ aware due  
to static C++ objects: exceptions, iostream, rtti, etc. I solved this  
by setting CONFIG[‘LDSHARED’] = “g++ -shared”.

This solution is nonportable – perhaps someone can suggest a better  
way? To be consistent, ruby could detect the presence/absence of a  
C++ compiler during ./configure, setting CONFIG[‘CXX’] and  
CONFIG[‘CXX\_LDSHARED’]. Also, mkmf should know to use CXX\_LDSHARED  
when C++ sources exist.

Second, ruby’s exception handling via setjmp/longjmp effectively means  
you should never construct a C++ object with a nontrivial destructor  
on the stack. If ruby longjmps out of your code, your destructors  
will not be called.

Therefore if a ruby method you are implementing requires the use of  
temporary C++ objects, you must construct those objects on the heap.

The easiest and saftest technique I found is to write three C  
functions for a ruby method: the actual ruby hook, the body, and the  
ensure:

#include “ruby.h”

class CXXRuby { } ;

static VALUE rb\_cxxruby\_superfunk\_body( void\*\* args ) ;  
static VALUE rb\_cxxruby\_superfunk\_ensure( void\*\* args ) ;

static VALUE rb\_cxxruby\_superfunk( int argc,  
VALUE\* argv,  
VALUE self )  
{  
// construct all C++ objects on the heap

```
CXXRuby* cxx_obj = 0 ;

void* args[4] ;
args[0] = reinterpret_cast<void*>(argc) ;
args[1] = static_cast<void*>(argv) ;
args[2] = reinterpret_cast<void*>(self) ;
args[3] = static_cast<void*>(&cxx_obj) ;

try
{
    cxx_obj = new CXXRuby() ;
}
catch(...)
{
    rb_cxxruby_superfunk_ensure(args) ;
    rb_raise(rb_eRuntimeError,
             "caught exception from an unfunky constructor") ;
}

return rb_ensure(
    reinterpret_cast<VALUE(*)(...)>(rb_cxxruby_superfunk_body),
    reinterpret_cast<VALUE>(args),
    reinterpret_cast<VALUE(*)(...)>(rb_cxxruby_superfunk_ensure),
    reinterpret_cast<VALUE>(args)) ;

```

}

static VALUE rb\_cxxruby\_superfunk\_body( void\*\* args )  
{  
int argc = reinterpret\_cast(args[0]) ;  
VALUE\* argv = static\_cast\<VALUE\*\>(args[1]) ;  
VALUE self = reinterpret\_cast(args[2]) ;  
CXXRuby\* cxx\_obj = _static\_cast\<CXXRuby_\*\>(args[3]) ;

```
try
{
    VALUE get_out ;
    VALUE the_funk ;

    if( rb_scan_args(argc, argv, "11",
                     &get_out, &the_funk) == 1 )
    {
        the_funk = Qtrue ;
    }

    // ...
}
catch(...)
{
    rb_raise(rb_eRuntimeError, "insufficient funk levels") ;
}

return self ;

```

}

static VALUE rb\_cxxruby\_superfunk\_ensure( void\*\* args )  
{  
// C++ cleanup

```
CXXRuby* cxx_obj = *static_cast<CXXRuby**>(args[3]) ;
delete cxx_obj ;
return Qnil ;

```

}

static VALUE cCXXRuby ;

extern “C” {

void Init\_cxxruby()  
{  
cCXXRuby = rb\_define\_class(“CXXRuby”, rb\_cObject) ;  
rb\_define\_singleton\_method(  
cCXXRuby,  
“superfunk”,  
reinterpret\_cast\<VALUE(\*)(…)\>(rb\_cxxruby\_superfunk),  
-1) ;

```
rb_define_global_const("OperationSupergroove", cCXXRuby) ;

```

}

} // extern “C”

---

<div class="post-metadata">

**Author:** ![Nobuyoshi\_Nakada](https://avatars.discourse-cdn.com/v4/letter/n/edb3f5/32.png) [@Nobuyoshi\_Nakada](https://rubytalk.org/u/Nobuyoshi_Nakada)\
**Post date:** [14 May 2004 10:41 UTC](https://rubytalk.org/t/ruby-c-extensions/11540/2 "2004-05-14T10:41:46Z")

</div>

Hi,

At Fri, 14 May 2004 16:43:54 +0900,  
Jeff Mitchell wrote in [ruby-talk:100255]:

> This solution is nonportable – perhaps someone can suggest a better  
> way? To be consistent, ruby could detect the presence/absence of a  
> C++ compiler during ./configure, setting CONFIG[‘CXX’] and  
> CONFIG[‘CXX\_LDSHARED’]. Also, mkmf should know to use CXX\_LDSHARED  
> when C++ sources exist.

Indeed. I’ll consider about it.

> The easiest and saftest technique I found is to write three C  
> functions for a ruby method: the actual ruby hook, the body, and the  
> ensure:

You can use rb\_protect() instead, and should use a struct  
rather than ugly enumerated reinterpret\_casts I guess.

#include “ruby.h”

class CXXRuby {  
};

struct superfunk\_args {  
int argc;  
VALUE \*argv;  
VALUE self;  
CXXRuby cxx\_obj;  
};

static VALUE rb\_cxxruby\_superfunk\_body(VALUE);

static VALUE  
rb\_cxxruby\_superfunk(int argc, VALUE \* argv, VALUE self)  
{  
int status = 0;  
VALUE result;

```
try {
struct superfunk_args args = {argc, argv, self};
result = rb_protect(rb_cxxruby_superfunk_body,
		    reinterpret_cast<VALUE>(&args), &status);
}
catch(...) {
rb_raise(rb_eRuntimeError,
	 "caught exception from an unfunky constructor");
}
if (status)
rb_jump_tag(status);
return result;

```

}

static VALUE  
rb\_cxxruby\_superfunk\_body(VALUE args)  
{  
struct superfunk\_args \*const argp =  
reinterpret\_cast\<struct superfunk\_args \*\>(args);  
int argc = argp-\>argc;  
VALUE \*argv = argp-\>argv;  
VALUE self = argp-\>self;  
CXXRuby &cxx\_obj = argp-\>cxx\_obj;

```
VALUE get_out;
VALUE the_funk;

if (rb_scan_args(argc, argv, "11", &get_out, &the_funk) == 1) {
the_funk = Qtrue;
}
// ...

return self;

```

}

static VALUE cCXXRuby;

extern “C” void  
Init\_cxxruby(void)  
{  
cCXXRuby = rb\_define\_class(“CXXRuby”, rb\_cObject);  
rb\_define\_singleton\_method(cCXXRuby, “superfunk”,  
RUBY\_METHOD\_FUNC(rb\_cxxruby\_superfunk), -1);

```
rb_define_global_const("OperationSupergroove", cCXXRuby);

```

}

> **···**
>
> –  
> Nobu Nakada

---

<div class="post-metadata">

**Author:** ![Paul\_Brannan](https://avatars.discourse-cdn.com/v4/letter/p/76d3ee/32.png) [@Paul\_Brannan](https://rubytalk.org/u/Paul_Brannan)\
**Post date:** [17 May 2004 15:20 UTC](https://rubytalk.org/t/ruby-c-extensions/11540/3 "2004-05-17T15:20:03Z")

</div>

> Second, ruby’s exception handling via setjmp/longjmp effectively means  
> you should never construct a C++ object with a nontrivial destructor  
> on the stack. If ruby longjmps out of your code, your destructors  
> will not be called.

It’s worse than that; if ruby longjmps over the destruction of an  
automatic object, the program has undefined behavior. And if a C++  
exception ever leaves C++ code and goes into Ruby code, the result will  
also be undefined.

C99 programmers also have to be careful; longjmping over the destruction  
of a variable-length array can result in a memory leak.

> Therefore if a ruby method you are implementing requires the use of  
> temporary C++ objects, you must construct those objects on the heap.

If you construct the object on the heap, it’s useful to register the  
object with the Ruby GC so it will get destroyed and not leaked. An  
alternative is to translate the exception to a C++ exception and then  
back into a ruby exception. I support both techniques in excruby  
([http://excruby.sourceforge.net](http://excruby.sourceforge.net)):

// Register with the garbage collector  
class Foo  
{  
};  
Foo \* f = new Foo;  
REGISTER\_WITH\_RUBY\_GC(Foo, f);

// Allocate on the stack  
RUBY\_TRY  
{  
Foo f;  
// rb\_cpp\_funcall translates Ruby exceptions into the C++ exception  
// Ruby\_Exception; RUBY\_CATCH will translate it back for me:  
rb\_cpp\_funcall(xyz, rb\_intern(“foo”), Qtrue);  
}  
RUBY\_CATCH

I’ve also been playing with an idea somewhat borrowed from  
boost::python (I haven’t released any of this code yet):

rb\_cFoo = define\_class(“Foo”)  
.define\_creation\_funcs(  
default\_allocation\_func,  
&Foo::initialize)  
.define\_method(“foo”, &Foo::foo);

The above code works as is, but eventually I’ll also be able to write:

class My\_Exception\_Handler  
: public Exception\_Handler  
{  
Std\_Exception\_Handler(Exception\_Handler const \* next\_exception\_handler)  
: Exception\_Handler(next\_exception\_handler)  
{  
}

```
virtual void handle_exception() const
{
  try
  {
    call_next_exception_handler();
  }
  catch(My_Exception const & ex)
  {
    throw Ruby_Exception(rb_cMy_Exception, ex.what());
  }

```

};

// My\_Exception\_Handler will get used for any exceptions thrown inside  
// functions in class Foo:  
rb\_cFoo = define\_class(“Foo”)  
.add\_exception\_handler\<My\_Exception\_Handler\>()  
.define\_creation\_funcs(  
default\_allocation\_func,  
&Foo::initialize)  
.define\_method(“foo”, &Foo::foo);

Also note that SWIG ([http://www.swig.org](http://www.swig.org)) has support for exceptions,  
and makes translating C++ exceptions into Ruby exceptions easy (or at  
least easier than they otherwise would be). Swig also allocates all its  
objects on the heap, so you don’t have to worry about Ruby exceptions  
unless you explictly call back into Ruby code from your C++ code:

%exception {  
try {  
$action  
}  
catch(std::exception const & ex)  
{  
rb\_raise(rb\_eCPlusPlusException, ex.what());  
}  
}

And note too that excruby is not designed to replace SWIG; it’s  
designed so you can use it right alongside SWIG:

%exception {  
RUBY\_TRY {  
$action  
}  
RUBY\_CATCH  
}

Paul

> **···**
>
> On Fri, May 14, 2004 at 04:43:54PM +0900, Jeff Mitchell wrote:
