Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I wrap up a Ruby C extension in a Ruby Gem?

Tags:

ruby

rubygems

I can't find many docs on this. How do I package a gem such that the C extension is compiled when the gem is installed?

In particular I want to do this:

  • on Linux and MacOSX i would like compile the C extension on gem install

  • on Windows I would like to simply install a precompiled .so

any help on this, in particular example source, would be very useful :)

like image 962
horseyguy Avatar asked Aug 22 '09 01:08

horseyguy


People also ask

How do we write Ruby in C?

Writing A Ruby Method From C A VALUE is a Ruby object. Now we need to attach this function to a Ruby class or module. You can create a new class or use an existing one. You can use the rb_define_method method to attach the C function to this module.

How do gems work in Ruby?

Gems can be used to extend or modify functionality in Ruby applications. Commonly they're used to distribute reusable functionality that is shared with other Rubyists for use in their applications and libraries. Some gems provide command line utilities to help automate tasks and speed up your work.


1 Answers

Luis Lavena has created rake-compiler just for this purpose.

  • Homepage / GitHub
  • GitHub Wiki

However, are you sure that you need a C extension? The thing about C extensions is that every Ruby implementation has their own C extension API (and non-C based ones like XRuby, JRuby, Ruby.NET, IronRuby, HotRuby, MagLev, Red Sun don't have one at all), which means that your C extension will only work on one implementation. And, since MRI only implements Ruby 1.8 and YARV only implements Ruby 1.9, and we are currently in a transition phase between 1.8 and 1.9, chances are that a lot of people will use at least two different implementations. (I personally use 5: MRI, YARV, JRuby, IronRuby and Rubinius.)

Maybe you are better off using Ruby-FFI. Ruby-FFI is an FFI (Foreign Function Interface) for Ruby (duh), which allows you to bind to and map C libraries in pure Ruby in a manner that is portable across Ruby implementations. The FFI API was first developed by Evan Phoenix as the native extension API for Rubinius, it was then adopted by Charles Oliver Nutter (and implemented by Wayne Meissner) for JRuby. Wayne then also wrote the Ruby-FFI gem, which contains C extensions for MRI and YARV. Laurent Sansonetti implemented Ruby-FFI for MacRuby, Marc-André Cournoyer's tinyrb also supports FFI (again written by Wayne Meissner) and the MagLev developers are also working on it. Which means that if you can make your library work with FFI as opposed to a C extension, you will automatically support 6 Ruby implementations instead of just one.

The only reason to use a C extension as opposed to an FFI extension would be, if you really do want some implementation specific behavior. One example of this would be the ParseTree gem, which reaches deep into the intestines of MRI and rips out the in-memory representation of the parse tree.

Last but not least, take a look at the Nice-FFI project by John Croisant, which aims to make using Ruby-FFI even nicer.

like image 131
Jörg W Mittag Avatar answered Sep 26 '22 03:09

Jörg W Mittag