Ruby Weekly is a weekly newsletter covering the latest Ruby and Rails news.

How to create a Ruby extension in C in under 5 minutes

By Peter Cooper / June 18, 2006

Many coders will reach a situation where developing a C extension makes sense, whether for doing 'heavy lifting', diving into assembly language, interfacing with other C code, etc. Luckily, developing a basic Ruby extension in C is easy.

Note: This article assumes you are using a UNIX of some sort (this was all tested on OS X) and that you have Ruby installed properly (from source, ideally, so you have ruby.h available). If not, you may be stuck.

First, create a directory called MyTest (or whatever you want your extension to be called) and in there create two files, extconf.rb and MyTest.c (if you want to download pre-written sources, they're in this tar file). In extconf.rb, put the following:

# 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)

This code is pretty self descriptive. It loads up Ruby's makefile library, sets up the environment, and creates a Makefile. Next, create the actual extension in MyTest.c. Here's some demonstration code to create a basic module with a single method called 'test1' which returns '10' when called:

// Include the Ruby headers and goodies
#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);

// The initialization method for this module
void Init_mytest() {
	MyTest = rb_define_module("MyTest");
	rb_define_method(MyTest, "test1", method_test1, 0);
}

// Our 'test1' method.. it simply returns a value of '10' for now.
VALUE method_test1(VALUE self) {
	int x = 10;
	return INT2NUM(x);
}

For C, it's reasonably simple code. We include the Ruby headers via ruby.h, set up a variable to store the module in, and create two functions, one which is called by Ruby when it initiates the module, and the other is our test1 method (Note that in the code above we define MyTest as a module, but you could just as easily use rb_define_class to create a class, if that's what you wanted to do.)

Next we need to compile our hard work. Make sure you're in the MyTest directory and run ruby extconf.rb, and it should say that the Makefile has been created. If so, you can then run make to compile and build the extension. As long as no errors occur, run up irb (or create a new Ruby program) and test out your newly build extension like so:

irb(main):001:0> require 'mytest'
=> true
irb(main):002:0> include MyTest
=> Object
irb(main):003:0> puts test1
10

Et voila! The world's simplest Ruby extension written in C in under 5 minutes. It doesn't do much, it's overly basic, but this is the springboard to greater things :)

Comments

  1. zenspider says:

    It should be noted that 5 minutes is glacial compared to what you can do with inline (and how much easier it is). The above example was done (and ran) in less than 30 seconds!

    require 'rubygems'
    require 'inline'

    class Example
    inline(:C) do |builder|
    builder.c "int method_test1() {
    int x = 10;
    return x;
    }"
    end
    end

    p Example.new.method_test1

    Please take notice of a couple things. 1) you just write it and run it. This is important. No extra development cycles are needed. I realize that your mkmf example is pretty straight forward, but there is a world of difference between having to think about what you need to do next vs just running your script and having it taken care of automatically. That includes compiler/linker flag changes, missing a make, etc etc... 2) notice I just say int and return x. Type conversions are taken care for you. 3) the resultant code looks almost exactly like yours, but with 1/10th the effort and time.

    As an aside, your MyTest should probably be made static, or better, just local to your Init. You can also avoid all your prototypes if you just reorder your two functions.

  2. zenspider says:

    that looked prettier in the comment box. :/

  3. Peter Cooper says:

    Thanks for the example. RubyInline has been covered here, btw (and at InfoQ), and I'm keeping an eye on developments, it looks like it's going great. Well done!

    I like these type conversions..

  4. Chris says:

    "require 'inline'
    LoadError: no such file to load -- inline"

    How can i get the module 'inline'?

    Thanks

  5. Peter Cooper says:

    gem install rubyinline or gem install RubyInline .. I forget :)

  6. Justin says:

    Windows gets no love here. I think you have ot have Visual C++ 6.0 installed to use these tools. Ugh.

  7. crispee says:

    awesome sample. thanks zenspider and peter.

  8. Pingback: Anonymous

  9. Combatjuan says:

    To Just and Windows Users:
    It tried this under Cygwin and it worked fine. Don't bother with Visual C++ 6.0. Cygwin is free and wonderful.

  10. RMX says:

    What I'd rather see is a RubyInline example that interacts with arrays. It's pretty rare that operating on a single value is the slow thing I want to extend; and pretty common that processing large arrays sucks.

    Anyone have that kind of 5-minute example?

  11. anonny says:

    sooo much easier with SWIG: http://www.swig.org

  12. peppermonkey says:

    Hmm..using Cygwin (just installed).
    I get a Makefile:104: *** target pattern contains no '%'. Stop.
    error...any ideas?

  13. martynJ says:

    Me too peppermonkey - maddening! did you find the solution?

Other Posts to Enjoy

Twitter Mentions