Running C in Ruby
Compiling
Compiling C code to be loaded as a Ruby extension requires some fancy compiler
options. Ruby’s mkmf
stdlib makes it easy to do this by generating an
appropriate makefile for you.
Preparation
First create the file extconf.rb
in the same directory as your C code:
The preparation section should perform actions similar to the standard UNIX
configure
script e.g.
- Check features of the current platform
- Check for existence of required libraries and functions
- Check for programs needed for building
The most common of these actions are provided by mkmf
(but you have all of
Ruby at your disposal if you need it). For example, an extension which uses SDL2
and needs to know how big int
s are might call:
create_header
creates the file extconf.h
containing preprocessor definitions
based on the results of the mkmf
functions you called previously. For this
example, extconf.h
might contain
This header should be included in your C files so that you can adapt your code
to a variety of platforms. Note that you can and should abort the extconf.rb
script if a mkmf
function returns a value that indicates that the build will
fail. For example, if SDL2 is a requirement of your extension you should exit
with some meaningful error message if have_library('SDL2')
returns false
.
This is preferred to generating the Makefile anyway and leaving the user with an
opaque compiler error.
create_makefile
obviously creates the Makefile, but its argument is especially
important: it defines the entry point of your C code, the name of the compiled
library, and thus the argument for require
in Ruby! This should be the name of
your extension.
You can modify a few of the generated Makefile variables by modifying the
corresponding globals in Ruby: $CFLAGS
, $CPPFLAGS
, and $LDFLAGS
1.
You can also use the $objs
global to define a list of object files for the
Makefile if its method of automatically generating targets doesn’t work for
your extension.
All of the mkmf
functions and their options are well-documented
online. In addition to the functions for generating extconf.h
, there
are a variety of functions for handling different source file layouts, different
file dependencies, etc.
Execution
The rest couldn’t be simpler
2But of course that won’t do anything without some C code to compile.
Init
In your C code, you’ll want to include ruby.h
to access the API. Other than
that the only requirement is to define a function for the Ruby VM to call when
your library is require
d. The name of the function is determined by the
argument you passed to create_makefile
in extconf.rb
. We used “foobar” in
our example, so we’ll create foobar.c
containing
Filenames
If your extension has only a single C file, you should name it after your
extension as we did above. If your extensions has multiple C files do not name
any of them after your extension. This is because the Makefile may generate a
.o
file named after your extension for the linking stage, which would cause a
conflict if you also have a .c
file which compiles to that filename.
Also avoid naming any files conftest.c
as this file may be written to by
mkmf
.
Success
Now make should compile a .so
(or some other library) file which you can
require
in Ruby. You can fill in your Init
function with plain C code, but
you’ll probably want to go back and learn about the C API to do more
interesting stuff.
Gem
After you’ve got your extension working nicely, you may want to bundle it up as
an easily distributable Ruby gem. rubygems.org has a detailed guide on
creating gems, but as far as C extensions go you just need to tell the spec
about extconf.rb
3:
If your gem includes multiple independent extensions, you can organize them in
subdirectories of ext/
and pass all of the extconf.rb
s to the spec.
Footnotes
-
Check the official documentation. ↩
-
The official documentation hints that
mkmf
parses certain command line flags e.g.--vendor
. But I can’t find this documented anywhere. ↩