Search code examples
crubyrubygemsnative-code

How do you use the C language to produce a ruby gem?


I would like to see some source code or maybe a link to some that gives at least a stub for writing ruby gems in the C languages (C++?? is that possible too?)

Also, some of you may know that Facebook compiles some of their code natively as php extensions for better performance. Is anyone doing this in Rails? If so, what has been your experience with it? Have you found it to be useful?

Thanks.

Edit: I guess I'll answer my own question with some stuff I learned today but I'm going to leave the question open for another answer because I'd like to see what others have to say on this topic


Solution

  • Ok, so I sat down a buddy of mine that is good with C. I have been showing him Ruby and he digs it. When we met last night I told him that you could write Ruby gems in C, which intrigued him. Here is what we found:

    Tutorials/Examples

    http://www.eqqon.com/index.php/Ruby_C_Extension

    http://drnicwilliams.com/2008/04/01/writing-c-extensions-in-rubygems/

    http://www.rubyinside.com/how-to-create-a-ruby-extension-in-c-in-under-5-minutes-100.html

    ruby-doc (ruby.h source code)

    http://ruby-doc.org/doxygen/1.8.4/ruby_8h-source.html

    Here is some source code that we wrote to test it out as well:

    Open up a terminal:

    prompt>mkdir MyTest
    prompt>cd MyTest
    prompt>gedit extconf.rb
    

    Then you put this code in extconf.rb

    # Loads mkmf which is used to make makefiles for Ruby extensions
    require 'mkmf'
    
    # Give it a name
    extension_name = 'mytest'
    
    # The destination
    dir_config(extension_name)
    
    # Do the work
    create_makefile(extension_name)
    

    Save the file then write MyTest.c

    #include "ruby.h"
    
    // Defining a space for information and references about the module to be stored internally
    VALUE MyTest = Qnil;
    
    // Prototype for the initialization method - Ruby calls this, not you
    void Init_mytest();
    
    // Prototype for our method 'test1' - methods are prefixed by 'method_' here
    VALUE method_test1(VALUE self);
    VALUE method_add(VALUE, VALUE, VALUE);
    
    // The initialization method for this module
    void Init_mytest() {
    MyTest = rb_define_module("MyTest");
    rb_define_method(MyTest, "test1", method_test1, 0);
    rb_define_method(MyTest, "add", method_add, 2);
    }
    
    // Our 'test1' method.. it simply returns a value of '10' for now.
    VALUE method_test1(VALUE self) {
    int x = 10;
    return INT2NUM(x);
    }
    
    // This is the method we added to test out passing parameters
    VALUE method_add(VALUE self, VALUE first, VALUE second) {
    int a = NUM2INT(first);
    int b = NUM2INT(second);
    return INT2NUM(a + b);
    }
    

    From the prompt you then need to create a Makefile by running extconf.rb:

    prompt>ruby extconf.rb
    prompt>make
    prompt>make install
    

    You can then test it out:

    prompt>irb
    irb>require 'mytest'
    irb>include MyTest
    irb>add 3, 4 # => 7
    

    We did a benchmark test and had ruby add 3 and 4 together 10 million times and then make a call to our C extension 10 million times as well. The result was that using only ruby it took 12 seconds to complete this task while using the C extension only took 6 seconds! Also note, that most of this processing is handing the job off to C to complete the task. In one of those tutorials the writer used recursion (Fibonacci sequence) and reported that the C extension took 51 times faster!