How to write C extensions easily in Ruby

Lots of Ruby libraries suffer from performance. It is in fact one of the biggest criticism that is being made to Ruby.

There are lots of ways to improve Ruby’s performance: use latest Ruby version, use JRuby, use Ruby Entreprise Edition, optimize your code…
A great comparison of the different Ruby interpreters can be found here. It is a bit old, but helps getting the picture.

However the most drastic performance gain you can get is by dropping Ruby and using C instead.

The best part is that you just need to drop Ruby for your critical algorithms that need performance, and keep it for the rest of your application.
The even-more-best part is that it is really easy to mix C and Ruby together. The learning curve is quite simple, and this blog post is here to remove natural fears in bridging 2 different languages.

This post is the first part of a series dealing with C extensions in Ruby. Others will be linked here.

What is a C extension?

A C extension is just a compiled file (.so or .dll) that is used exactly the same way as a Ruby library (.rb).
A C extension has to define just 1 C method that will be called upon its load. This method can then define classes, modules, functions and also execute arbitrary code.
Simple, no ?

A C extension needs of course its source written in C, and then needs to be compiled using a C compiler before being usable by your Ruby environment.

By convention, Ruby libraries are stored in a lib/ folder from a Ruby project.
By the same convention, C extensions are stored in a ext/ folder from a Ruby project.

What do I need to create a C extension?

You need Ruby, and a C development environment ([g]cc, ld, [g]make…).
By default, this is already present in most *nix systems.

For Windows, you will have to install those. You can try the following environments:

How to setup your development environment lies beyond the scope of this post: Google indexes already plenty of resources dealing with those topics.

The Hello World from C

First things first, let’s write a Hello World in C and invoke it from Ruby. Our C extension is named myext in this tutorial.

  1. Let’s start by writing our Hello World in C:
    #include "ruby.h"
    
    void Init_myext() {
      printf("Hello Ruby from C!\n");
    }
    

    Notice the Init_myext function: this is the 1 needed function.
    Notice also the include directive that is mandatory for any C extension: it declares the Ruby/C API that will be needed later.

  2. Now we write a little Ruby program that will generate a Makefile able to compile our C extension. By convention, this file is named extconf.rb:
    require 'mkmf'
    create_makefile('myext')
    
  3. Then we generate the makefile using our script:
    > ruby extconf.rb
    creating Makefile
    
  4. And finally compile our extension by invoking make:
    > make
    compiling myext.c
    linking shared-object myext.so
    
  5. Now we can require our C extension from Ruby, the same way we do with Ruby files:
    > ruby -I. -e "require 'myext'"
    Hello Ruby from C!
    

    Notice that by default, you don’t need to specify your library’s extension (.so or .rb): Ruby is intelligent enough to find out by itself.

Next step

That’s all for the first part. You can now create C extensions and make C code run in a Ruby application.

Next we will see how to package our C extensions in nice gems.

About Muriel Salvan

I am a freelance project manager and polyglot developer, expert in Ruby and Rails. I created X-Aeon Solutions and rivierarb Ruby meetups. I also give trainings and conferences on technical topics. My core development principles: Plugins-oriented architectures, simple components, Open Source power, clever automation, constant technology watch, quality and optimized code. My experience includes big and small companies. I embrace agile methodologies and test driven development, without giving up on planning and risks containment methods as well. I love Open Source and became a big advocate.
C, Howto, Ruby , , , , , , , , , ,

2 comments


  1. Pingback: Packaging Ruby C extensions in nice gems | Muriel's Tech Blog

  2. Pingback: The Ruby C API – Basics | Muriel's Tech Blog

Leave a Reply

Your email address will not be published.