miércoles, 24 de marzo de 2010

Como escribir una extension ruby en C en 5 minutos

Lo siguiente toma lugar entre las 15:51 pm y las 15:56 pm

Para crear una extension en ruby lo primero que hay que hacer, es crear el "extconf.rb", basicamente tiene que tener el siguiente contenido:


# extconf.rb
require 'mkmf'

dir_config("exttest")

create_makefile("exttest")


Posteriormente, hay que crear el archivo del codigo fuente en C de la extension, que minimamente tiene que haber uno, en este caso creamos uno de prueba, bastante resumido, el cual crea un modulo ruby y le define dos metodos, ambos implementados en C:


// exttest.c

#include "ruby.h"

static VALUE foo(VALUE self) {
printf("Foo invoqued\n");
return Qnil;
}

static VALUE sum(VALUE self, VALUE a, VALUE b) {
return INT2NUM( NUM2INT(a) + NUM2INT(b) );
}


void
Init_exttest()
{
VALUE rb_exttest = rb_define_module("Exttest"); // definir el modulo

rb_define_singleton_method(rb_exttest, // en que modulo
"foo", // nombre del metodo
foo, // puntero a la implementacion C del metodo
0 // cantidad de argumentos del metodo
);

rb_define_singleton_method(rb_exttest, // en que modulo
"sum", // nombre del metodo
sum, // puntero a la implementacion C del metodo
2 // cantidad de argumentos del metodo
);

}




Para generar el makefile (solo hay que hacer esto una vez), se ejecuta el script extconf.rb:

ruby extconf.rb


Para construir la extension, se debe lanzar el siguiente comando:


make


Eso genera, entre otros archivos intermedios, extconf.so, el cual contiene la extension misma compilada a codigo nativo de la plataforma donde estan corriendo todo, para instalarla en el sistema, hay que correr (como root):


make install


Para usar la extension:



# test.rb
require 'rubygems'
require 'exttest'

Exttest.foo # el metodo foo definido en exttest.c!!
print Exttest.sum(4,9),"\n" # el metodo sum definido en exttest.c!!



Posteriormente, se pueden hacer cosas mas interesantes como definir clases, clases anidadas en modulos, metodos, etc...
Para la proxima voy a explicar como encapsular la extension como gem y distribuirla

links:

* http://onlamp.com/pub/a/onlamp/2004/11/18/extending_ruby.html: Fuente que inspiro este articulo y ejemplo practico de como wrappear la libreria GenX como libreria ruby GenX4r
* http://rhg.rubyforge.org/chapter04.html: Tutorial que muestra como definir clases y modulos
* http://ruby-doc.org/doxygen/1.8.4/group__ruby__interp.html: Documentacion completa de funciones C para definir extensiones de ruby incluyendo funciones de conversion de datos

No hay comentarios: