Wednesday, April 18, 2012

Telling Ruby Where To Find C++ Headers In Native Extensions

On my current project I'm responsible for maintaining the Ruby language bindings for some C++ code. And part of what I've worked on was to write some Ruby extensions in C to overcome some blocking I/O issues. So initially I wrote a simple extconf.rb file that looked like this:

require 'mkmf'
create_makefile('nonblockio')

and that was it.

Now, a few months later, we need to have some enhancements to this. And we also need to support two versions of Ruby (1.8 and 1.9). So I decided to enhance this simple extconf.rb file to ensure that certain libraries and headers were present depending on the version of Ruby being used.

The problem is that some of the header files for our project themselves include headers from the C++ standard library. And, by default, Ruby will use gcc on Linux when testing for headers. So when the following snippet executed in extconf.rb:

fail("Missing header file: exceptions.h") unless have_header("qpid/messaging/exceptions.h")

it would fail in exceptions. h includes <string> and gcc doesn't know how to load a C++ header file.

Telling Ruby To Use C++

To overcome this problem, you need to tell Ruby to use a C++ compiler rather than a C compiler when necessary. To accomplish this, I added the following to extconf.rb:

Config::CONFIG['CPP'] = "g++ -E"

Now when Ruby creates the Makefile and first checks for the headers it uses g++ instead of gcc. Also, you MUST include the "-E" commandline argument: this argument tells the compiler to stop after the preprocessor stage. That way it ONLY checks that the included header file and its header dependencies are all present.