Installing bleak house 3.6 on Mac OS X Leopard 10.5.1Edit

These notes were made while installing bleak_house 3.6 on Mac OS X Leopard 10.5.1.

My initial attempt failed:

$ sudo gem install bleak_house
Password:
Updating metadata for 31 gems from http://gems.rubyforge.org
...............................
complete
Building native extensions.  This could take a while...
Building native extensions.  This could take a while...
ERROR:  Error installing bleak_house:
	ERROR: Failed to build gem native extension.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby extconf.rb install bleak_house
/usr/lib/ruby/1.8/mkmf.rb:4:in `require': no such file to load -- rbconfig (LoadError)
	from /usr/lib/ruby/1.8/mkmf.rb:4
	from build_logger.rb:1:in `require'
	from build_logger.rb:1


Gem files will remain installed in /Library/Ruby/Gems/1.8/gems/bleak_house-3.6 for inspection.
Results logged to /Library/Ruby/Gems/1.8/gems/bleak_house-3.6/ext/bleak_house/logger/gem_make.out

I see there are a few open tickets for this already:

Before going any further, I turned to Google but found only this:

So I investigated further:

cd /Library/Ruby/Gems/1.8/gems/bleak_house-3.6/ext/bleak_house/logger
less extconf.rb

# extconf.rb runs buildruby.rb
less buildruby.rb

# do this as root seeing as that's what RubyGems did too
sudo ruby buildruby.rb

# seems to work, did it actually build ruby?
/usr/bin/ruby-bleak-house --version

# so the next line in extconf.rb must be the one that fails, let's try that
sudo ruby-bleak-house build_logger.rb

This yields the same error as shown above, so we’ve now pinpointed the location of the failure. It’s failing on the very first line of build_logger.rb:

require 'mkmf'

The custom ruby-bleak-house build is using the standard mkmf.rb file and failing to find any rbconfig require.

So, let’s see what rbconfig.rb files we have on the system:

$ find / -name rbconfig.rb 2> /dev/null
/private/tmp/bleak_house/ruby-1.8.6-p110/rbconfig.rb
/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0/rbconfig.rb
/Users/wincent/trabajo/vendor/ruby/ruby-1.9.0-0/rbconfig.rb
/usr/local/ruby19/lib/ruby/1.9.0/i686-darwin9.1.0/rbconfig.rb

Let’s see what ruby-bleak-house has in its load path:

$ ruby-bleak-house -e "p $:"
["/usr/lib/ruby/site_ruby/1.8",
"/usr/lib/ruby/site_ruby/1.8/i686-darwin9.1.0",
"/usr/lib/ruby/site_ruby",
"/usr/lib/ruby/1.8",
"/usr/lib/ruby/1.8/i686-darwin9.1.0",
"."]

Compare that with the stock Leopard Ruby:

$ ruby -e "p $:"
["/Library/Ruby/Site/1.8",
"/Library/Ruby/Site/1.8/powerpc-darwin9.0",
"/Library/Ruby/Site/1.8/universal-darwin9.0",
"/Library/Ruby/Site",
"/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8",
"/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/powerpc-darwin9.0",
"/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0",
"."]

So you can see why it fails to find any rbconfig.rb. It isn’t configured to look in either /private/tmp/bleak_house/ruby-1.8.6-p110/ (where it could find its own), or in /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0 (where it could find Leopard’s).

Out of interest, what are the differences between the two files?

$ diff /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/universal-darwin9.0/rbconfig.rb \
/private/tmp/bleak_house/ruby-1.8.6-p110/rbconfig.rb

Output:

9c9
<   TOPDIR = File.dirname(__FILE__).chomp!("/lib/ruby/1.8/universal-darwin9.0")
---
>   TOPDIR = File.dirname(__FILE__).chomp!("/lib/ruby/1.8/i686-darwin9.1.0")
11,18d10
<   ARCHFLAGS =
<     if e = ENV['ARCHFLAGS']
<       e
<     elsif e = ENV['RC_ARCHS']
<       e.split.map { |a| "-arch #{a}" }.join(' ')
<     else
<       '-arch ppc -arch i386'
<     end
22c14
<   CONFIG["prefix"] = (TOPDIR || DESTDIR + "/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr")
---
>   CONFIG["prefix"] = (TOPDIR || DESTDIR + "/usr")
46c38
<   CONFIG["infodir"] = "$(DESTDIR)/usr/share/info"
---
>   CONFIG["infodir"] = "$(datarootdir)/info"
53c45
<   CONFIG["mandir"] = "$(DESTDIR)/usr/share/man"
---
>   CONFIG["mandir"] = "$(datarootdir)/man"
57c49
<   CONFIG["LIBS"] = "-lpthread -ldl -lm "
---
>   CONFIG["LIBS"] = "-ldl -lobjc "
64,65c56,57
<   CONFIG["build"] = "powerpc-apple-darwin9.0"
<   CONFIG["build_cpu"] = "powerpc"
---
>   CONFIG["build"] = "i686-apple-darwin9.1.0"
>   CONFIG["build_cpu"] = "i686"
67,69c59,61
<   CONFIG["build_os"] = "darwin9.0"
<   CONFIG["host"] = "powerpc-apple-darwin9.0"
<   CONFIG["host_cpu"] = "powerpc"
---
>   CONFIG["build_os"] = "darwin9.1.0"
>   CONFIG["host"] = "i686-apple-darwin9.1.0"
>   CONFIG["host_cpu"] = "i686"
71,73c63,65
<   CONFIG["host_os"] = "darwin9.0"
<   CONFIG["target"] = "powerpc-apple-darwin9.0"
<   CONFIG["target_cpu"] = "powerpc"
---
>   CONFIG["host_os"] = "darwin9.1.0"
>   CONFIG["target"] = "i686-apple-darwin9.1.0"
>   CONFIG["target_cpu"] = "i686"
75c67
<   CONFIG["target_os"] = "darwin9.0"
---
>   CONFIG["target_os"] = "darwin9.1.0"
77,78c69,70
<   CONFIG["CFLAGS"] = "#{ARCHFLAGS} -Os -pipe -fno-common"
<   CONFIG["LDFLAGS"] = "-L. #{ARCHFLAGS}"
---
>   CONFIG["CFLAGS"] = "-g -O2 -pipe -fno-common"
>   CONFIG["LDFLAGS"] = "-L. "
105c97
<   CONFIG["ALLOCA"] = "$(LIBOBJDIR)alloca.o"
---
>   CONFIG["ALLOCA"] = ""
110c102
<   CONFIG["LDSHARED"] = "cc #{ARCHFLAGS} -pipe -bundle"
---
>   CONFIG["LDSHARED"] = "cc -dynamic -bundle -undefined suppress -flat_namespace"
130,131c122,123
<   CONFIG["LIBRUBY_LDSHARED"] = "cc #{ARCHFLAGS} -pipe -dynamiclib"
<   CONFIG["LIBRUBY_DLDFLAGS"] = "-install_name $(libdir)/lib$(RUBY_SO_NAME).$(MAJOR).dylib -current_version $(MAJOR).$(MINOR).$(TEENY) -compatibility_version $(MAJOR).$(MINOR)"
---
>   CONFIG["LIBRUBY_LDSHARED"] = "cc -dynamic -bundle -undefined suppress -flat_namespace"
>   CONFIG["LIBRUBY_DLDFLAGS"] = ""
135,140c127,132
<   CONFIG["LIBRUBY_SO"] = "lib$(RUBY_SO_NAME).$(MAJOR).dylib"
<   CONFIG["LIBRUBY_ALIASES"] = "lib$(RUBY_SO_NAME).dylib"
<   CONFIG["LIBRUBY"] = "$(LIBRUBY_SO)"
<   CONFIG["LIBRUBYARG"] = "$(LIBRUBYARG_SHARED)"
<   CONFIG["LIBRUBYARG_STATIC"] = "-l$(RUBY_SO_NAME)"
<   CONFIG["LIBRUBYARG_SHARED"] = "-l$(RUBY_SO_NAME)"
---
>   CONFIG["LIBRUBY_SO"] = "lib$(RUBY_SO_NAME).so.$(MAJOR).$(MINOR).$(TEENY)"
>   CONFIG["LIBRUBY_ALIASES"] = "lib$(RUBY_SO_NAME).so"
>   CONFIG["LIBRUBY"] = "$(LIBRUBY_A)"
>   CONFIG["LIBRUBYARG"] = "$(LIBRUBYARG_STATIC)"
>   CONFIG["LIBRUBYARG_STATIC"] = "-l$(RUBY_SO_NAME)-static"
>   CONFIG["LIBRUBYARG_SHARED"] = ""
143c135
<   CONFIG["ENABLE_SHARED"] = "yes"
---
>   CONFIG["ENABLE_SHARED"] = "no"
150,153c142,145
<   CONFIG["arch"] = "universal-darwin9.0"
<   CONFIG["sitearch"] = "universal-darwin9.0"
<   CONFIG["sitedir"] = "$(DESTDIR)/Library/Ruby/Site"
<   CONFIG["configure_args"] = " '--prefix=/usr' '--mandir=/usr/share/man' '--infodir=/usr/share/info' '--disable-dependency-tracking' '--enable-pthread' '--enable-shared' '--prefix=/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr' '--with-sitedir=/Library/Ruby/Site' 'ac_cv_func_getcontext=no' 'ac_cv_func_setcontext=no' 'CFLAGS=    -g -Os -pipe -fno-common -DENABLE_DTRACE     -pipe' 'LDFLAGS=               '"
---
>   CONFIG["arch"] = "i686-darwin9.1.0"
>   CONFIG["sitearch"] = "i686-darwin9.1.0"
>   CONFIG["sitedir"] = "$(prefix)/lib/ruby/site_ruby"
>   CONFIG["configure_args"] = " '--prefix=/usr'"
187,189d178
< RUBY_FRAMEWORK = true
< RUBY_FRAMEWORK_VERSION = Config::CONFIG['ruby_version']
< APPLE_GEM_HOME = File.join(Config::CONFIG['libdir'], 'ruby/gems', Config::CONFIG['ruby_version'])

So we really have a few problems here:

  • Stock ruby on Leopard is a different version
  • Stock ruby on Leopard is a Universal Binary, but the bleak_house version is not
  • This mismatch could be an obstacle to testing compiled extensions
  • Stock ruby looks in completely different places to find things

All of this means that you can’t just use ruby-bleak-house as a drop-in replacement for ruby on Leopard.

So rather than use it as a drop-in, I am going to try creating a completely separate sandbox for it as I did with Ruby 1.9 (see "Installing Ruby 1.9 on Mac OS X 10.5.1").

# delete old installed binary
$ sudo rm /usr/bin/ruby-bleak-house

# make a backup before experimenting
$ sudo cp build_ruby.rb build_ruby.rb.orig

We have a backup copy, so now apply this patch:

--- build_ruby.rb.orig	2008-01-15 14:28:56.000000000 +0100
+++ build_ruby.rb	2008-01-15 14:32:31.000000000 +0100
@@ -42,19 +42,9 @@
           # Patch, configure, and build
           system("patch -p0 < \'#{source_dir}/gc.c.patch\' > ../gc.c.patch.log 2>&1")
           system("patch -p0 < \'#{source_dir}/parse.y.patch\' > ../parse.y.patch.log 2>&1")
-          system("./configure --prefix=#{binary_dir[0..-5]} > ../configure.log 2>&1") # --with-static-linked-ext
+          system("./configure --prefix=/usr/local/ruby-bleak-house > ../configure.log 2>&1") # --with-static-linked-ext
           system("make > ../make.log 2>&1")
-
-          binary = "#{binary_dir}/ruby-bleak-house"
-
-          # Install binary
-          if File.exist? "ruby"
-            # Avoid "Text file busy" error
-            File.delete binary if File.exist? binary
-            exec("cp ./ruby #{binary}; chmod 755 #{binary}")
-          else
-            raise "Binary did not build"
-          end
+          system("make install >> ../make.log 2>&1")
         end

       end

Now try rebuilding again:

$ sudo ruby build_ruby.rb

Let’s test that:

$ export PATH="/usr/local/ruby-bleak-house/bin:$PATH"
$ /usr/local/ruby-bleak-house/bin/ruby -r 'mkmf' -e 'p $:'
["/usr/local/ruby-bleak-house/lib/ruby/site_ruby/1.8",
"/usr/local/ruby-bleak-house/lib/ruby/site_ruby/1.8/i686-darwin9.1.0",
"/usr/local/ruby-bleak-house/lib/ruby/site_ruby",
"/usr/local/ruby-bleak-house/lib/ruby/1.8",
"/usr/local/ruby-bleak-house/lib/ruby/1.8/i686-darwin9.1.0", "."]

Note how the load path is now properly configured and the require of mkmf no longer produces any errors.

Now let’s continue with the next step from the extconf.rb:

$ ruby --version
ruby 1.8.6 (2007-09-23 patchlevel 110) [i686-darwin9.1.0]
$ sudo ruby build_logger.rb

And that works. So, I tried running sudo gem install bleak_house again but that wanted to rebuild the extension all over again rather than use the Makefile that I’d just generated. So time for one more patch:

--- extconf.rb.orig	2008-01-15 14:42:42.000000000 +0100
+++ extconf.rb	2008-01-15 14:46:33.000000000 +0100
@@ -1,3 +1,6 @@

 system('ruby build_ruby.rb &> /dev/null')
-exec('ruby-bleak-house build_logger.rb')
+old_path=ENV['PATH']
+ENV['PATH']="/usr/local/ruby-bleak-house/bin:#{old_path}"
+exec('ruby build_logger.rb')
+ENV['PATH']=old_path

And now:

# restore PATH to its previous value
. ~/.bash_profile
echo $PATH
sudo gem install bleak_house

Voila:

Building native extensions.  This could take a while...
Successfully installed bleak_house-3.6
1 gem installed
Installing ri documentation for bleak_house-3.6...
Installing RDoc documentation for bleak_house-3.6...

Now, to actually use this you’ll want to ensure that /usr/local/ruby-bleak-house/bin is in your PATH; any scripts which start with:

#!/usr/bin/env ruby

Will then automatically use it.

For this sandbox to actually be useful you’ll probably want to bootstrap it with a minimum of gems. For example, I wanted to test Walrus in this environment; all of these commands were executed with /usr/local/ruby-bleak_house/bin at the start of the PATH:

# with RubyGems we won't get very far
wget http://rubyforge.org/frs/download.php/29548/rubygems-1.0.1.tgz
tar xzvf rubygems-1.0.1.tgz
cd rubygems-1.0.1
sudo ruby setup.rb

# need RSpec to test Walrus
sudo gem install rspec

# need wopen3 to run Walrus
sudo gem install wopen3

# now let's see if Walrus actually works
# I'm going to use a checked out copy of the source
# (I want to test the latest code, not the code in the gem)
cd path_to_walrus_source_directory

# build C extensions
rake make

# run the specs
rake spec

And that all works, so I can now proceed to start playing with it using bleak_house. Note that the sandbox is so pristine that it doesn’t even have bleak_house in it; address that like this:

sudo gem install bleak_house

Note that this downloads a new copy of the gem without our patches, and it will therefore install a new ruby binary at /usr/local/ruby-bleak-house/bin/ruby-bleak-house which we can effectively ignore.

After adding my instrumentation to the tool:

require 'rubygems'
require 'bleak_house'
$memlogger = BleakHouse::Logger.new
File.delete($memlogger_file = '/tmp/walrus.log') rescue nil

# and later on...
$memlogger.snapshot($memlogger_file, 'tag/subtag', false)

I deploy it in the sandbox as follows:

rake gem
sudo gem install pkg/walrus-0.2.gem

# this is the instrumented version, in the sandbox
walrus --version

Now run the tool with a test workloand and analyze the output with:

bleak /tmp/walrus.log