Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How did I cause gcc to produce a .bundle instead of a .so?

I'm trying to write a Ruby extension, and I've been successfully compiling my nmatrix.so shared object file all day. But then, suddenly, it starts producing nmatrix.bundle instead, without any .so file at all.

It's not giving me any linker errors, so I can't imagine why this would be. I also didn't change anything in my Makefile or extconf.rb. I've been consistently using Ruby 1.9.3p0 through rvm.

I've tried doing a git stash save with my work for the day and compiling something I know should work without linker errors (something that produced a .so) earlier. Unfortunately, that too produces a .bundle file.

Clearly I have done something -- perhaps installed something inadvertently -- which has changed some critical GCC setting. This is totally possible, as I spent most of the day trying to get LAPACK and ATLAS to build, and also installed homebrew at some point.

I have discovered that there is a work-around. I change these two lines:

DLLIB = $(TARGET).bundle
# ...
LDSHARED = $(CC) -dynamic -bundle

to

DLLIB = $(TARGET).so
# ...
LDSHARED = $(CC) -dynamic

And then the library compiles and loads correctly. However, I haven't the faintest what I changed in extconf.rb (or elsewhere) which would have caused it to auto-generate this Makefile with .bundle files instead of .so.

The question is: how exactly did I cause this, and what do I do to restore it?

like image 910
Translunar Avatar asked Jan 12 '12 00:01

Translunar


1 Answers

The C extensions RubyGems Guide has an overview of the building process.

The critical lines in your extconf.rb file are near the ends:

require "mkmf"
# ...
create_makefile("nmatrix")

This builds the Makefile for you. The Makefile is built using configuration values stored in the RbConfig::CONFIG[] array; the configuration value you're most interested in is RbConfig::CONFIG['DLEXT']:

$ ruby -e "require 'rbconfig'; puts RbConfig::CONFIG['DLEXT'];"
so

To easily see the entire configuration, look for the rbconfig.rb file; mine is located in /usr/lib/ruby/1.8/x86_64-linux/rbconfig.rb, and I'll include the first few lines here:

# This file was created by mkconfig.rb when ruby was built.  Any
# changes made to this file will be lost the next time ruby is built.

module Config
  RUBY_VERSION == "1.8.7" or
    raise "ruby lib version (1.8.7) doesn't match executable version (#{RUBY_VERSION})"

  TOPDIR = File.dirname(__FILE__).chomp!("/lib/ruby/1.8/x86_64-linux")
  DESTDIR = '' unless defined? DESTDIR
  CONFIG = {}
  CONFIG["DESTDIR"] = DESTDIR
  CONFIG["INSTALL"] = '/usr/bin/install -c'
  CONFIG["EXEEXT"] = ""
  CONFIG["prefix"] = (TOPDIR || DESTDIR + "/usr")
  ...
  CONFIG["DLEXT"] = "so"
  CONFIG["LDSHARED"] = "$(CC) -shared"
  CONFIG["CCDLFLAGS"] = " -fPIC"
  ...

So, some version of your rbconfig.rb file has been built when another version of Ruby was built that suggested that dynamically linked extensions should have a different extension. This might be a feature of rvm (which I still need to learn more about) or this might be a difference between Apple-supplied Ruby vs self-compiled Ruby. You can see in the comment header of the file that you could easily make the change in rbconfig.rb yourself -- but it will be blown away the next time you rebuild or install a differently-built Ruby.

(Incidentally, I thought the extension was .dylib, but it's been a while since I've used OS X, too.)

like image 180
sarnold Avatar answered Oct 15 '22 23:10

sarnold