matt.freels.name

Haskell, HDBC, MYSQL, and Mac OS X

Saturday, 23 October 2010

I'm trying to learn Haskell, and as a part of the process, I have been learning the build and package tools around the language. The first rite of passage, of course, is to figure out how to install database drivers.

So, it turned out to be a bit harder than I first thought. I was hoping to just run cabal install HDBC-mysql but that resulted in a broken library. I managed to get it right after a bit of spelunking.

MySQL

As of this writing, GHC currently only compiles as 32-bit on Mac OS X. Hopefully this will be fixed soon, but until then, all linked libraries must be 32-bit compatible. I have MySQL 5.1 installed using homebrew, but by default it was installed as x86_64 only. Fortunately, the MySQL package allows installation as a universal binary:

$ brew install mysql --universal

If you already have it installed, you might have to uninstall first.

HDBC

Now for the tricky part. Figuring out how to get [HDBC]4] to talk to MySQL is a bit of a walk in the weeds, as there are multiple options in terms of drivers. There are both HDBC-odbc, an ODBC-based driver and HDBC-mysql, which wraps libmysqlclient.

I tried to get HDBC-odbc working first, as HDBC-mysql labels itself as "alpha" quality, but gave up after failing to string together the multiple layers of libraries.

HDBC-mysql was a bit more simple to get working. The only real problem I ran into was getting it to build against the universal binary of libmysqlclient. Its setup script was tripping over the multiple -arch flags emitted by mysql_config, so I ended up just hardcoding a modified string in the setup script. To get it working, unpack the library first:

$ cabal unpack HDBC-mysql
$ cd HDBC-mysql-*

Then, modify Setup.lhs. Replace the line that sets ldOptions with the output you get from mysql_config --libs, removing -arch x86_64. For me this ended up being:

- ldOptions   <- return . split ws =<< mysqlConfig ["--libs"]
+ let ldOptions = split ws "-L/usr/local/Cellar/readline/6.1/lib -arch i386 -L/usr/local/Cellar/mysql/5.1.51/lib/mysql -lmysqlclient -lz -lm"

Finally, install the modified library. You will need to specify --extra-lib-dirs so that the GHC runtime finds libmysqlclient:

$ cabal install --extra-lib-dirs=/usr/local/lib/mysql

Success! (Hopefully)

At this point, you should be able to connect to MySQL. I just ran the sample program from the HDBC-mysql docs:

import Control.Monad
import Database.HDBC
import Database.HDBC.MySQL
main = do conn <- connectMySQL defaultMySQLConnectInfo {
                    mysqlUser     = "root",
                    mysqlPassword = "somepass"
                 }

          rows <- quickQuery' conn "SELECT 1 + 1" []
          forM_ rows $ \row -> putStrLn $ show row

Running it with runhaskell should work like so:

$ runhaskell test.hs
[SqlInteger 2]

As I've barely scratched the surface at this point, I can't really give any gotchas of this setup, though if I run into any, I'll update this post.