So, recently I was looking around the blogosphere and I noticed Rice hit 1.0. This is quite good news, and it really looks like it makes the creation of Ruby bindings/extensions with C++ dead simple. As I paged through the documentation, I noticed the section on `embedding', and so the idea immediately struck me - how about creating new interpreters, or `toplevels' (in an OCamlish sense)?
Here's some sample code:
#include "rice/Data_Type.hpp"
#include "rice/Constructor.hpp"
#include "rice/VM.hpp"#include <string>
using namespace Rice;
class MyBuiltin
{
public:
MyBuiltin(const std::string &_message = "Hello, world!"): message(_message)
{ }const std::string &greet() const
{
return message;
}protected:
std::string message;
};int main(int argc, char **argv)
{
Rice::VM vm(argc, argv);Data_Type<MyBuiltin> rb_cMyBuiltin =
define_class<MyBuiltin>("MyBuiltin")
.define_constructor(Constructor<MyBuiltin>())
.define_method("greet", &MyBuiltin::greet);vm.run();
}
It looks mostly like two of the examples from the Rice page (http://rice.rubyforge.org/), and with good reason - I've never used Rice before. Compiling this with the recommended extconf Makefile gives a library to be `require'd by Ruby, which is no good for us: if we repeat the last step of compiling and drop `-shared' and change the output to be a binary instead, we get a normal linked executable:
celtic@sohma:~/code/rtl$ make
g++ -I. -I. -I/usr/lib/ruby/1.8/i486-linux -I. -I/var/lib/gems/1.8/gems/rice-1.0.1/ruby/lib/include -fPIC -fno-strict-aliasing -g -g -O2 -fPIC -Wall -g -c test.cpp
g++ -shared -o test.so test.o -L"." -L"/usr/lib" -L. -rdynamic -Wl,-export-dynamic -L/var/lib/gems/1.8/gems/rice-1.0.1/ruby/lib/lib -lrice -lruby1.8 -lpthread -ldl -lcrypt -lm -lc
celtic@sohma:~/code/rtl$ g++ -o test test.o -L"." -L"/usr/lib" -L. -L/var/lib/gems/1.8/gems/rice-1.0.1/ruby/lib/lib -lrice -lruby1.8 -lpthread -ldl -lcrypt -lm -lc
celtic@sohma:~/code/rtl$
We also can drop -rdynamic, -Wl,-export-dynamic, as they're specific to our creating a shared object. Now, we run the resulting binary!
celtic@sohma:~/code/rtl$ ./test
Nothing. That's because it's just like the `ruby' interpreter. Perfect. :) How about we try something more constructive?
celtic@sohma:~/code/rtl$ ./test `which irb`
>> MyBuiltin
=> MyBuiltin
>> x = MyBuiltin.new
=> #<MyBuiltin:0xb7909914>
>> x.greet
=> "Hello, world!"
>>
And it works just like that.
