DEV Community

Cover image for Writing our C Extension
Marcelo Junior
Marcelo Junior

Posted on • Edited on

2

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 😀

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (2)

Collapse
 
daibushi profile image
Jaderson Nascimento

With this tutorial I could make my first gem.

Tankyou

Collapse
 
juneira profile image
Marcelo Junior

I'm happy that this tutorial help you ❤️

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs