Question

I am trying to compile a c++ extension for Ruby, and the compilation does not return an error, but it does not seem to be compiling correctly. What am I doing wrong?

I have the main cpp script foo.cpp:

#include <iostream>
#include <ruby.h>
extern "C"

VALUE cFoo;
void Init_foo(){cFoo = rb_define_class("Foo", rb_cObject);}

and extconf.rb:

require "mkmf"
$libs += " -lstdc++ "
create_makefile("foo")

and within the directory of these files, I did

$ ruby extconf.rb
creating Makefile
$ make
compiling foo.cpp
linking shared-object foo.so
$ ls
Makefile extconf.rb foo.cpp foo.o foo.so

Then, I have a Ruby script test.rb:

#!/usr/bin/env ruby
require "path_to_this_directory/foo"

and I run test.rb. It returns an error:

... in `require': .../foo.so: undefined symbol: cFoo - .../foo.so (LoadError)

What am I doing wrong?

Environment

  • OS: Ubuntu Linux 11.10
  • Ruby: 1.9.3
Was it helpful?

Solution

You're declaring that cFoo exists:

extern "C"

VALUE cFoo;

but you never define it. Saying extern "C" blahblah just says that blahblah exists, that it is externally visible, and that it won't have its name mangled (i.e. "C" linkage) but an extern declaration doesn't actually define anything; extern says that something exists but it doesn't bring it into existence.

Your C++ should look more like this:

#include <iostream>
#include <ruby.h>

extern "C" VALUE cFoo;
extern "C" void Init_foo();

VALUE cFoo;
void Init_foo(){cFoo = rb_define_class("Foo", rb_cObject);}

You need two extern "C" to tell the C++ compiler to leave the names alone and then separate definitions for the symbols. You could also say this:

#include <iostream>
#include <ruby.h>

extern "C" VALUE cFoo;

VALUE cFoo;
extern "C" void Init_foo(){cFoo = rb_define_class("Foo", rb_cObject);}

I'm not sure if the second version is standard C++ or a GCC extension.

I'm not much of a C++ person so I hope I haven't butchered the terminology too badly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top