Writing our C Extension

juneira

Marcelo Junior

Posted on June 21, 2023

Writing our C Extension

How to compile C code for use in the program Ruby?

Write a Makefile to compile this program as shared lib to a program Ruby to use can be hard work, to solve this problem Ruby's core created the module MakeMakefile.

  • First: write a script in Ruby to "make our MakeFile" named extconf.rb on the same folder of program C:
require 'mkmf'

create_makefile 'foo'
Enter fullscreen mode Exit fullscreen mode

This simple code generates a MakeFile to the file foo.c.

  • Second: Run ruby extconf.rb

We'll find our Makefile in the current path! 🎉

But... and the file foo.c?

Writing our C Extension

See below basic skeleton of our C Extension:

#include "ruby.h"

void Init_foo()
{
  // Your C code goes here
}
Enter fullscreen mode Exit fullscreen mode

First include the lib ruby.h to use functions, constants... of Ruby.

Second create a function that returns void, named Init_ plus the name used in extconf.rb. In this example Init_foo.

Bingo! Our first C Extension is done!

To see the shared lib compiled by this code:

$ ruby extconf.rb
$ make
$ ls
Makefile  extconf.rb  foo.c  foo.o  foo.so
Enter fullscreen mode Exit fullscreen mode

Let's create a Class and a Method to say "hello"?

Adding Class and Method to foo.c

See below how file.c turned out:

#include "ruby.h"

VALUE rb_hello(VALUE class) {
  VALUE str = rb_str_new_cstr("hello!");
  rb_funcall(rb_mKernel, rb_intern("puts"), 1, str);
  return Qnil;
}

void Init_foo()
{
  VALUE class = rb_define_class("Greeting", rb_cObject);
  rb_define_singleton_method(class, "hello", rb_hello, 0);
}
Enter fullscreen mode Exit fullscreen mode

Like the first part of this article, we'll define the class Greeting using the function rb_define_class inheriting from Object. And we'll define the method of class hello using rb_define_singleton_method passing the function rb_hello as a parameter.

The function rb_hello should return VALUE and receive as a parameter the class. This function transforms a string of C to a string of Ruby using the method rb_str_new_cstr, then call method puts of Kernel through of function rb_funcall(rb_mKernel, rb_intern("puts"), 1, str). And finally returns Qnil, the same nil of Ruby.

In Ruby this code is like this:

class Greeting
  def self.hello
    Kernel.puts "hello" # or puts "hello"
  end
end
Enter fullscreen mode Exit fullscreen mode

LET'S RUN IT!

To test our work until here compile the C Extension again:

$ ruby extconf.rb
$ make
Enter fullscreen mode Exit fullscreen mode

Then open the irb inside of folder of shared lib and run this code:

require './foo'

Greeting.hello
# hello!
Enter fullscreen mode Exit fullscreen mode

🎉 🎉 YEAH! ITS DONE! 🎉 🎉

Next steps

Finally, we compile our C Extension! However, we don't create a Gem yet 🙄...

In the next article, we'll make this!

See you later 😀

💖 💪 🙅 🚩
juneira
Marcelo Junior

Posted on June 21, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related