What Exactly Is a Gem Native Extension

What exactly is a gem native extension?

A gem native extension might link to a separate library that needs to be pre-installed, and RMagick is an example of that.

However, the term really just means "includes some code that needs to be compiled for your machine". The code is compiled and linked so that the resulting executable file can be required by Ruby on the machine.

The usual reasons for writing a Ruby C or C++ extension are:

  • Speed. For some CPU-intense tasks, C code can be 100 times faster than Ruby. In this case a native extension can be completely stand-alone with all C source code included in the gem.

  • Third-party library already written in C. In this case the gem will have C source code that binds the library functions into Ruby modules, classes and methods.

You can view the C source code for gems with native extensions, it is installed alongside the Ruby source code. By convention, there is a folder inside the gem called ext/gem_name which contains a Ruby file extconf.rb that passes information to the compiler (technically it creates a make file). In addition the C source files are put there as well.

MRI Ruby is implemented as a very "flat" structure in C, basically consisting of a large number of C functions. This makes it relatively easy to learn how to implement a native extension, even if you don't know much C. You can read Extending Ruby 1.9 as an introduction to the topic.

Native extensions can fail to install or work properly. There are many questions on Stack Overflow asking for help with specific failed installs. The usual problems are:

  • Missing libraries. Hopefully the gem author will explain what you need to pre-install in the README, but is not always clear.

  • Compiler mismatches. It is difficult to test all target systems, so sometimes the instructions in extconf.rb won't work on a specific system, or the C code will raise warnings or not compile due to differences. In Windows, you probably won't have a working compiler unless you install the Ruby Devkit

  • Will not work with all versions of Ruby. For instance, JRuby can use C native extensions, if it has been enabled but it is not always advisable - the topic is quite complex, but generally avoid mixing JRuby and native extensions.

How can I determine if a ruby gem is actually a native C extension?

You can check the gem specification to see if extensions is defined. You have to download the gem or check its source to do this, but it's not to difficult to do programmatically with a bit of unix-fu:

curl -L <gem-url> | tar xOf - metadata.gz | gunzip | ruby -r yaml -e 'p YAML.load($stdin.read).extensions.any?'

Let's compare bson & bson_ext (since they're the first non-C-extension and C-extension versions of the same gem I could think of):

% curl -L https://rubygems.org/downloads/bson-1.8.0.gem | tar xOf - metadata.gz | gunzip | ruby -r yaml -e 'p YAML.load($stdin.read).extensions.any?'
false

% curl -L https://rubygems.org/downloads/bson_ext-1.8.0.gem | tar xOf - metadata.gz | gunzip | ruby -r yaml -e 'p YAML.load($stdin.read).extensions.any?'
true

You could automate the need to know the current version of the gem by using the RubyGems API:

curl https://rubygems.org/api/v1/gems/bson.yaml | ruby -r yaml -e 'p YAML.load($stdin.read)["version"]'

Why do I get a Failed to build gem native extension error, pg (0.8.0), while running 'bundle install'?

The pg gem is used to access PostgreSQL databases from ruby. Check your Gemfile.lock to find out which gem is requiring it as a dependency.

Please see this Stack Overflow question if you actually need to use the pg gem.

Failed to build gem native extension?

Usually, this "multiple target patterns" error when compile gem extensions is caused by spaces in directory names where you have installed your Ruby or your gems.

Especially on Windows, you should install your Ruby to a directory which contains no spaces, rather than your current location D:/Program Files/Ruby30-x64. To fix this, I recommend to uninstall Ruby and install it again to a more appropriate location.



Related Topics



Leave a reply



Submit