Snow Leopard, Ruby & PostgreSQL: A Cautionary Tale
My development machine is a Mac running Snow Leopard in 64-bit mode with
PostgreSQL (via
MacPorts) and Ruby Enterprise
Edition (via Ruby Version
Manager). I recently upgraded my REE
installation to version 1.8.7-2009.10 only to discover that the ruby-pg
gem was no longer able to establish connections to PostgreSQL. In the
error message I saw the words pg-0.8.0/lib/pg.bundle: no matching
architecture
, performed a jaunty shrug (I was in a cheery mood)
and charged merrily into the task of reinstalling the ruby-pg gem in
64-bit mode.
(At this point a clever person would have paused to consider the fact that neither PostgreSQL nor the ruby-pg gem had changed at this point. A clever person would have taken a moment to double check the way the new version of REE was installed before wasting close to an hour that could have been better spent in the pub. I am not a clever person.)
I set about reinstalling the ruby-pg gem with no configuration options only to meet with verbose failure which began with:
In file included from compat.c:16:
compat.h:38:2: error: #error PostgreSQL client version too old, requires 7.3 or later.
In file included from compat.c:16:
compat.h:69: error: conflicting types for ‘PQconnectionNeedsPassword’
/opt/local/include/postgresql83/libpq-fe.h:266: error: previous declaration of ‘PQconnectionNeedsPassword’ was here
compat.h:70: error: conflicting types for ‘PQconnectionUsedPassword’
/opt/local/include/postgresql83/libpq-fe.h:267: error: previous declaration of ‘PQconnectionUsedPassword’ was here
I tried again with ARCHFLAGS="-arch x86_64"
but to no
avail. I tried ARCHFLAGS="-arch i386"
. Skunked again.
Version to old? How could that be. The only version of PostgreSQL I’d
ever installed on this machine was 8.3.8. I verified the installed
version and that pg_config
was in my path:
$ port installed postgresql*
The following ports are currently installed:
postgresql83 @8.3.8_0 (active)
postgresql83-server @8.3.8_0 (active)
$ pg_config | grep VERSION
VERSION = PostgreSQL 8.3.8
Finally my feeble brain caught up with obvious reality. The build
process was working with files from PostgreSQL 8.3.8 (see the path to
libpq-fe.h
in the error message), but it was unable to read
symbols from the PostgreSQL libraries. It was trying to read a 64-bit
library as if it were a 32-bit library. I took a closer look at the Ruby
and PostgreSQL binaries:
$ rvm use ree
Now using ree 1.8.7 2009.10
$ file $(whence ruby)
/Users/jparker/.rvm/ree-1.8.7-2009.10/bin/ruby: Mach-O executable i386
$ file $(whence pg_config)
/opt/local/lib/postgresql83/bin/pg_config: Mach-O 64-bit executable x86_64
PostgreSQL was indeed built in 64-bit mode, but REE had somehow been built in 32-bit mode. I rebuilt REE explicitly telling it to build in 64-bit mode:
$ export ARCHFLAGS="-arch x86_64"
$ rvm install ree
After verifying the new REE binary was indeed 64-bit, I took another shot at rebuilding the ruby-pg gem. It worked perfectly. God’s in his heaven. All is right with the world.
Having opened and closed windows a number of times while trying to fix
the problem, I’m unable to verify the state of the environment in which
I originally upgraded REE, but I suspect I had a tainted
ARCHFLAGS
environment variable left over from an earlier
task. The moral of the story is:
- When building software always make sure your environment is clean.
- Build everything 64-bit or nothing 64-bit.
- Before wasting prime pub hours fixing something that isn’t broken (ruby-pg), consider what pieces have changed (REE) and investigate them first.