[Rubygems-developers] Build extensions with an .rb file [PATCH]

James M. Lawrence quixoticsycophant at gmail.com
Sun Oct 12 17:21:04 EDT 2008


The following patch addresses some issues I encountered while creating
the gem for a recent project.  To summarize, my solution is to have a
builder which recognizes .rb files,

Gem::Specification.new { |s|
  # ...
  s.extensions << "build.rb"
}

This bypasses the need for rake or make, and the need to generate
dummy Rakefiles or Makefiles.

For reference, the project is

http://github.com/quix/p4ruby/tree/master

The install.rb downloads files, compiles, and installs.  Passing --gem
to install.rb runs it under gem configuration mode, which "installs"
to ./ext and ./lib.

The first question was which builder in lib/rubygems/ext I should use.
My install.rb is not an extconf.rb, however an extconf.rb could be
used as a front for install.rb.

ConfigureBuilder and ExtConfBuilder would both require a dummy
Makefile to be generated.  However a Makefile consisting of just the
line "all:\n" would look like a bug, plus the 'make' dependency would
be unnecessary in the first place.

This leaves RakeBuilder.  The default task of my Rakefile runs
"install.rb --gem".  This is less than ideal for the following
reasons,

(a) The 'rake' dependency is unnecessary.  In fact I had forgotten to
add_dependency("rake") in the gemspec.  (Shouldn't this be done
automatically when spec.extensions << "Rakefile" is given?)

(b) I had been using system() to invoke the ruby executable with
"install.rb --gem" because I had run into rubygems' name pollution,

http://rubyforge.org/tracker/index.php?func=detail&aid=20801&group_id=126&atid=575

I had then encountered another issue where joining CONFIG['bindir']
with CONFIG['ruby_install_name'] does not produce a runnable ruby on
all platforms.

Therefore I went back to load("install.rb") after making a change to
accommodate the name pollution (crossing my fingers on other possible
pollution).

These problems are byproducts of rubygems not being able to call
install.rb.

(c) The Rakefile carries the baggage of tasks only used in development
('rake package', etc).  Already gempackagetask.rb outputs a warning
(for manage_gems).  I could generate a minimal Rakefile just for the
gem, but this seems too convoluted, like the near-empty Makefile.  It
would be better not to even need a Rakefile.

In my patch, rubygems passes "--gem" to the .rb file given in
gemspec.extensions.  This would be a nice feature since it allows an
install.rb to be used for both the normal install and the gem setup.
Otherwise I'd have to make a separate gem.rb (which would just set
ARGV and load install.rb anyway).

In any case, the --gem option is not important compared to having
RbBuilder in the first place.

Index: lib/rubygems/ext/rb_builder.rb
===================================================================
--- lib/rubygems/ext/rb_builder.rb	(revision 0)
+++ lib/rubygems/ext/rb_builder.rb	(revision 0)
@@ -0,0 +1,16 @@
+
+require 'rubygems/ext/builder'
+
+class Gem::Ext::RbBuilder < Gem::Ext::Builder
+
+  def self.build(extension, directory, dest_path, results)
+    cmd = "#{Gem.ruby} #{File.basename extension} --gem"
+    cmd << " #{ARGV.join ' '}" unless ARGV.empty?
+
+    run cmd, results
+
+    results
+  end
+
+end
+
Index: lib/rubygems/installer.rb
===================================================================
--- lib/rubygems/installer.rb	(revision 1904)
+++ lib/rubygems/installer.rb	(working copy)
@@ -474,6 +474,8 @@
                 when /rakefile/i, /mkrf_conf/i then
                   ran_rake = true
                   Gem::Ext::RakeBuilder
+                when /\.rb\Z/ then
+                  Gem::Ext::RbBuilder
                 else
                   results = ["No builder for extension '#{extension}'"]
                   nil
Index: lib/rubygems/ext.rb
===================================================================
--- lib/rubygems/ext.rb	(revision 1904)
+++ lib/rubygems/ext.rb	(working copy)
@@ -15,4 +15,5 @@
 require 'rubygems/ext/configure_builder'
 require 'rubygems/ext/ext_conf_builder'
 require 'rubygems/ext/rake_builder'
+require 'rubygems/ext/rb_builder'


More information about the Rubygems-developers mailing list