The Artima Developer Community
Sponsored Link

Agile Buzz Forum
Blending C and Ruby

0 replies on 1 page.

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 0 replies on 1 page
Jared Richardson

Posts: 1031
Nickname: jaredr
Registered: Jun, 2005

Jared Richardson is an author, speaker, and consultant who enjoys working with Ruby and Rails.
Blending C and Ruby Posted: Mar 25, 2006 1:00 PM
Reply to this message Reply

This post originated from an RSS feed registered with Agile Buzz by Jared Richardson.
Original Post: Blending C and Ruby
Feed Title: Jared's Weblog
Feed URL: http://www.jaredrichardson.net/blog/index.rss
Feed Description: Jared's weblog. The web site was created after the launch of the book "Ship It!" and discusses issues from Continuous Integration to web hosting providers.
Latest Agile Buzz Posts
Latest Agile Buzz Posts by Jared Richardson
Latest Posts From Jared's Weblog

Advertisement

A project that I've been working on has involved calling C code from Ruby code. It was much easier to do than I anticipated and I thought others might find it interesting.

Why would you do this? Suppose you have a bit of Ruby code that's too slow in a key portion of your program? You can easily move that bit of code out to C. This gets all the speed of execution in C where you need it combined with the speed of program creation that Ruby provides.

This would also be an easy way to wrap your legacy C code, access hardware with a C interface, etc. The possibilities are literally endless.

So how do you do this? First, let me tell you that these examples are on Linux, but they are pretty simple and I don't think you'll have much trouble duplicating them on Windows. I just don't have a C compiler installed on my Windows box at the moment. If enough people ask for it, I'll set up the environment and run this to Windows, but I don't see how an example this simple wouldn't translate directly.

Another caveat, I'm skimming this topic very lightly. I'm not explaining the "why" behind most of these directions. If you want to go deeper, check out the pickaxe book, avaiable in both the second edition (new, improved, and up to date) or the original first edition (online and free). The pick axe book has an entire chapter on extending Ruby with C.

You need three files to do this work. The first is your C code file, the second is your Ruby code file, and the last is a configuration file called "extconf.rb". Extconf.rb is used by a Ruby utility called mkmf (makes your Makefile). It creates your rather complicated build file for this project.

Let's start with the Ruby file. Here it is.

#include "ruby.h"
#include 

static VALUE cSampleC;

static VALUE exec(VALUE self) {
        printf("\n\nExec, written in C, was run from within the Ruby code \n\n");
        return Qnil;
}

void Init_SampleC() {
        cSampleC = rb_define_class("SampleC", rb_cObject);
        rb_define_method(cSampleC, "exec", exec, 0);
}

What do we have here? First, you must include ruby.h to make your C code ruby aware.

Next, you need a static variable to hold your object reference. That's cSampleC.

Your C routine has to return the type VALUE. This is equivalent to a Ruby Object. You need to have (at least) a single argument VALUE self. You can have more, but this one is required.

Finally, return Qnil if you really want a void type.

The last block, init_SampleC declares your C objects so that Ruby can see them. This code maps your C to Ruby.

rb_define_class creates a Ruby object for you. In my example, it's "SampleC". NOTE:This object must start with an upper case letter. I worked with "ingres" for nearly two hours before I tried "Ingres" and everything just worked. :( The second argument in this method is your static VALUE object that holds the referenc to this object.

Finally, create a mapping from your routine to your Ruby object. rb_define_method does this for you. The arguments? First, the static VALUE object again, then your Ruby object name, your C method name, and finally, the number of arguments you're passing in (don't count "self").

Okay, we're done with the C file. Let's create a Makefile.

Here's my extconf.rb file:

require 'mkmf' create_makefile("SampleC")

Complicated, but I think you can handle it. :) This file can get a lot more complicated, but this one does all we need.

To invoke this, type:

ruby -r mkmf extconf.rb

If all goes well, you'll see

creating Makefile

Now you can type make, then make install.

At this point, we should have a Ruby object we can run!

The Ruby code is pretty straightforward as well.

require "SampleC"
 i=SampleC.new
 i.exec

Of course, you can run this from within irb as well.

That's it. You can now run ruby testMyCode.rb and see

Exec, written in C, was run from within the Ruby code

I'm using this feature to include some database libraries. Let me know if that interests anyone. If it does, I'll write that one up. It's a bit more complicated (and not finished yet!), but if there's some interest, I'll get it posted in a few weeks.

Enjoy!

Jared

Read: Blending C and Ruby

Topic: IBM and Crossing Borders Previous Topic   Next Topic Topic: Anals of DRM

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use