packages feed

hubris (empty) → 0.0.1

raw patch · 11 files changed

+618/−0 lines, 11 filesdep +Cabaldep +arraydep +basesetup-changed

Dependencies added: Cabal, array, base, bytestring, containers, ghc, ghc-paths, haskell-src-meta, haskell98, hint, mtl, old-time

Files

+ Hubrify.hs view
@@ -0,0 +1,7 @@+module Main where+import Language.Ruby.Hubris.LibraryBuilder+import System++main = do+   (mod:extra_src) <- getArgs+   generateLib extra_src mod >>= print
+ LICENSE view
@@ -0,0 +1,22 @@+(The MIT License)++Copyright (c) 2009 Mark Wotton++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+'Software'), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+            permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be+included in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ Language/Ruby/Hubris.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} +module Language.Ruby.Hubris where++import Data.Word+import Data.Map as Map+-- import Language.Ruby.Hubris.Binding+import System.IO.Unsafe (unsafePerformIO)+import Foreign.C.Types+import Language.Ruby.Hubris.Binding+import Control.Monad (forM)+-- type Value = CULong++++wrap :: (Haskellable a, Rubyable b) => (a->b) -> (Value -> Value)+wrap func ar = fromRVal $ case (toHaskell $ fromVal ar) of+                Just a ->  toRuby $ func a+                Nothing -> T_NIL++-- fromVal :: Value -> RValue+-- fromRVal ::RValue -> Value+-- fromVal = undefined+-- fromRVal = undefined++class Haskellable a where+  toHaskell :: RValue -> Maybe a++class Rubyable a where+  toRuby :: a -> RValue++instance Haskellable Int where+  toHaskell (T_FIXNUM i) = Just i+  toHaskell _ = Nothing++instance Rubyable Int where+  toRuby i = T_FIXNUM i++instance Haskellable Integer where+  toHaskell (T_BIGNUM i) = Just i+  toHaskell _ = Nothing++instance Rubyable Integer where+  toRuby i = T_BIGNUM i++instance Haskellable Bool where+  toHaskell T_TRUE  = Just True+  toHaskell T_FALSE = Just False+  toHaskell _       = Nothing++instance Rubyable Bool where+  toRuby True = T_TRUE+  toRuby False = T_FALSE++instance Rubyable Double where+  toRuby d = T_FLOAT d++instance Haskellable Double where+  toHaskell (T_FLOAT f)  = Just f+  toHaskell (T_FIXNUM i) = Just $ fromIntegral i -- does this make sense?+  toHaskell _ = Nothing ++instance Haskellable String where+  toHaskell (T_STRING s) = Just s+  toHaskell _ = Nothing+instance Rubyable String where+  toRuby s = (T_STRING s)+++-- This is a tricky case.+-- The ruby FFI wants us to pass a C callback which it can apply to each key-value pair+-- of the hash, so Haskell cannot be fully in control of the process - this makes building+-- up a Data.Map object in the natural way a bit tricky.++-- current thoughts:+--  1. write a direct binding to the ruby API, include a C level function for getting the keys.+--     just eat the cost of transferring through a keys call + looping over the elements.+--     One big benefit - while iteration is expensive, using it as a hash table should be cheap+--     (although probably needs to stay in the IO monad, which is less convenient.)+--+--  2. write a binding to the Judy library that creates a Judy object directly. If we can convince+--     HsJudy to accept that, then we're golden - we still have to copy over, but keys operations+--     should be cheap (and hopefully lazy, but test to make sure).+--+-- These are of course not mutually exclusive.+--+-- The first should probably be a part of the base package. The second needs access to internals,+-- but should probably be an optional package. This means that in Hubris.Internals, we should expose++-- > rb_foreach :: Value {- HASH -} -> (CFunction ((Key,Value,a) -> a)) -> a -> IO a +-- +-- ++-- instance Haskellable (Map.Map a b ) where +--   toHaskell (T_HASH s) = unsafePerformIO $ +--                          get_each+                         +--   toHaskell _ = Nothing++instance (Rubyable a, Rubyable b) => Rubyable (Map.Map a b) where+  toRuby s = unsafePerformIO $ +             do hash <- rb_hash_new+                forM (toList s)+                     (\(k,v) -> rb_hash_aset hash (fromRVal $ toRuby k) (fromRVal $ toRuby v))+                return $ T_HASH hash
+ Language/Ruby/Hubris/Binding.chs view
@@ -0,0 +1,156 @@+{-# LANGUAGE ForeignFunctionInterface, TypeSynonymInstances #-}++{- TODO++Rip the array trnaslation stuff out to a utility function. same with hashes.++install as package. This is a bit iffy for GHC/JHC compatibility - if we commit to+Cabal, that leaves JHC out in the cold.++perhaps need cabal file for ghc and equivalent for jhc.++also: do we want to support different versions of ruby? for the moment, you just get+whichever ruby.h is first in the search place.++-}+++module Language.Ruby.Hubris.Binding where+#include "rshim.h"+#include <ruby.h>++-- import Control.Applicative+-- import Control.Monad+import Data.Word+-- import Foreign.Ptr+import Foreign.C.Types	+import Foreign.C.String+-- import Foreign.Storable+import System.IO.Unsafe (unsafePerformIO)++-- import Foreign.Marshal.Array++{# context lib="rshim" #}++{# enum RubyType {} deriving (Eq, Show) #} -- maybe Ord?+#if RUBY_VERSION_CODE <= 187+data RubyConsts = RUBY_Qfalse +                | RUBY_Qtrue  +                | RUBY_Qnil   +                | RUBY_Qundef ++instance Enum RubyConsts where+  fromEnum RUBY_Qfalse = 0+  fromEnum RUBY_Qtrue = 2+  fromEnum RUBY_Qnil = 4+  fromEnum RUBY_Qundef = 6++  toEnum 0 = RUBY_Qfalse+  toEnum 2 = RUBY_Qtrue+  toEnum 4 = RUBY_Qnil+  toEnum 6 = RUBY_Qundef+#else+{# enum ruby_special_consts as RubyConsts {} deriving (Eq,Show) #}+#endif+type Value = CULong -- FIXME, we'd prefer to import the type VALUE directly+foreign import ccall unsafe "ruby.h rb_str2cstr"    rb_str2cstr    :: Value -> CInt -> CString+foreign import ccall unsafe "ruby.h rb_str_new2"    rb_str_new2    :: CString -> Value+foreign import ccall unsafe "ruby.h rb_ary_new2"    rb_ary_new2    :: CLong -> IO Value+foreign import ccall unsafe "ruby.h rb_ary_push"    rb_ary_push    :: Value -> Value -> IO ()+foreign import ccall unsafe "ruby.h rb_float_new"   rb_float_new   :: Double -> Value+foreign import ccall unsafe "ruby.h rb_big2str"     rb_big2str     :: Value -> Int -> Value+foreign import ccall unsafe "ruby.h rb_str_to_inum" rb_str_to_inum :: Value -> Int -> Int -> Value+foreign import ccall unsafe "ruby.h ruby_init" ruby_init :: IO ()++-- we're being a bit filthy here - the interface is all macros, so we're digging in to find what it actually is+foreign import ccall unsafe "rshim.h rb_ary_len" rb_ary_len :: Value -> CUInt+foreign import ccall unsafe "rshim.h rtype"      rtype      :: Value -> Int+foreign import ccall unsafe "rshim.h int2fix"    int2fix    :: Int -> Value+foreign import ccall unsafe "rshim.h fix2int"    fix2int    :: Value -> Int+foreign import ccall unsafe "rshim.h num2dbl"    num2dbl    :: Value -> Double  -- technically CDoubles, but jhc promises they're the same+foreign import ccall unsafe "rshim.h keys"       rb_keys    :: Value -> IO Value++-- this line crashes jhc+foreign import ccall unsafe "intern.h rb_ary_entry" rb_ary_entry :: Value -> CLong -> IO Value++foreign import ccall safe "ruby.h rb_raise" rb_raise :: Value -> CString -> IO ()+foreign import ccall unsafe "ruby.h rb_eval_string" rb_eval_string :: CString -> Value++foreign import ccall unsafe "intern.h rb_hash_aset" rb_hash_aset :: Value -> Value -> Value -> IO ()+foreign import ccall unsafe "intern.h rb_hash_new" rb_hash_new :: IO Value+foreign import ccall unsafe "intern.h rb_hash_aref" rb_hash_aref :: Value -> Value -> IO Value++++data RValue = T_NIL  +            | T_FLOAT Double+            | T_STRING String++            -- List is non-ideal. Switch to uvector? Array? There's always going+            -- to be an extraction step to pull the RValues out.+            | T_ARRAY [RValue]+            | T_FIXNUM Int +            | T_HASH  Value --  Int -- definitely FIXME - native ruby hashes, or going to transliterate into Data.Map?+            | T_BIGNUM Integer    ++            -- technically, these are mapping over the types True and False,+            -- I'm going to treat them as values, though.+            | T_TRUE  +            | T_FALSE      ++            | T_SYMBOL Word -- interned string+              deriving (Eq, Show)+-- These are the other basic Ruby structures that we're not handling yet.+--          | T_REGEXP     +--          | T_FILE+--          | T_STRUCT     +--          | T_DATA       +--          | T_OBJECT +--          | T_CLASS      +--          | T_MODULE     +-- leaky as hell+fromRVal :: RValue -> Value+fromRVal r = case r of+           T_FLOAT d -> rb_float_new d+           -- need to take the address of the cstr, just cast it to a value+           -- sadly no bytestrings yet - unpack it to a list. yeah it's ugly.+           T_STRING str -> rb_str_new2 $ unsafePerformIO $ newCAString str+           T_FIXNUM i -> int2fix i++           -- so this is just bizarre - there's no boolean type. True and False have their own types+           -- as well as their own values.+           T_TRUE     -> fromIntegral $ fromEnum RUBY_Qtrue+           T_FALSE    -> fromIntegral $ fromEnum RUBY_Qfalse+           T_NIL      -> fromIntegral $ fromEnum RUBY_Qnil+           T_HASH h   -> h+           T_ARRAY l  -> unsafePerformIO $ do+                           ary <- rb_ary_new2 $ fromIntegral $ length l+                           mapM_ (rb_ary_push ary . fromRVal) l+                           return ary+           T_BIGNUM b -> rb_str_to_inum (rb_str_new2 $ unsafePerformIO $ newCAString $ show b) 10 1+           _          -> error "sorry, haven't implemented that yet."++fromVal :: Value -> RValue+fromVal v = case target of+               RT_NIL -> T_NIL+               RT_FIXNUM -> T_FIXNUM $ fix2int v+               RT_STRING -> T_STRING $ unsafePerformIO $ peekCString $ rb_str2cstr v 0+               RT_FLOAT ->  T_FLOAT $ num2dbl v+               RT_BIGNUM -> T_BIGNUM $ read  $ unsafePerformIO $ peekCString $ rb_str2cstr (rb_big2str v 10) 0+               RT_TRUE -> T_TRUE+               RT_FALSE -> T_FALSE+               RT_HASH  -> T_HASH v+               RT_ARRAY -> T_ARRAY $ map fromVal $ unsafePerformIO  $ mapM (rb_ary_entry v . fromIntegral) [0..(rb_ary_len v) - 1]++               _ -> error "didn't work" -- (show target)+      where target :: RubyType+            target = toEnum $ rtype v+++unsafeThrow :: String -> a+unsafeThrow s = unsafePerformIO $ throwException s >> undefined+throwException :: String -> IO Value+throwException s = do he <- newCAString "HaskellError"+                      err <- newCAString s+                      rb_raise (rb_eval_string he) err+                      error "shouldn't ever get here"
+ Language/Ruby/Hubris/GHCBuild.hs view
@@ -0,0 +1,51 @@+module Language.Ruby.Hubris.GHCBuild (ghcBuild, defaultGHCOptions, GHCOptions(..)) where+import Config+import Debug.Trace+import DynFlags+import GHC+import GHC.Paths+import Outputable+import StringBuffer+import System.Time+import Control.Monad(forM_)++newtype GHCOptions = GHCOptions { strict :: Bool }+defaultGHCOptions = GHCOptions { strict = True }+type Filename = String+++sh = showSDoc . ppr+-- this one's a bit tricky: we _could_ use the GHC api, but i don't care too much.+-- let's keep it simple.+--+-- ok, new plan: handling it the filthy way is awful.+ghcBuild :: Filename -> String -> String -> [Filename] -> GHCOptions -> IO Bool+ghcBuild libFile immediateSource modName extra_sources options =+       do srcBuffer <- stringToStringBuffer immediateSource+          putStrLn ("modname is " ++ modName)+          writeFile "/tmp/foo.hs" immediateSource+          time <- getClockTime -- i suppose we've just made it now...+          defaultErrorHandler defaultDynFlags $ do+          res <- runGhc (Just libdir) $ do+            dflags <- getSessionDynFlags++            (newflags, leftovers, warnings) <- GHC.parseDynamicFlags dflags +                                               $ map noLoc $ (words $ "-shared -o " ++ libFile ++ " -optl-Wl,-rpath," ++ libdir +                                                      ++ " /Users/mwotton/projects/Hubris/lib/rshim.o -lHSrts-ghc" ++ Config.cProjectVersion)+            trace ("left: " ++ sh leftovers) $ trace (sh warnings) $ setSessionDynFlags newflags+            +            forM_ ("/tmp/foo.hs":extra_sources)  (\file -> guessTarget file Nothing >>= addTarget) ++            load LoadAllTargets+            -- do something with c_sources and extra_sources+--             setTargets [Target { targetContents = Just ( srcBuffer, time ), +--                                  targetAllowObjCode = True,+--                                  targetId = TargetModule $ mkModuleName modName+--                                } ]++                              -- } ]+       +          return (case res of+                  Succeeded -> True+                  _ -> False)+
+ Language/Ruby/Hubris/LibraryBuilder.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}+module Language.Ruby.Hubris.LibraryBuilder (generateLib) where+import Language.Ruby.Hubris.ZCode (zenc, zdec)+import Language.Ruby.Hubris+import Language.Haskell.Interpreter+import Language.Haskell.Meta.QQ.HsHere+import Language.Ruby.Hubris.GHCBuild++import Debug.Trace+import Control.Monad+import Control.Monad.Error.Class++import GHC(parseStaticFlags, noLoc)+type Filename = String++generateLib :: [Filename] -> ModuleName -> IO (Maybe Filename)+generateLib sources moduleName = do+  -- set up the static args once+  GHC.parseStaticFlags $ map noLoc $ words "-dynamic -fPIC -package hubris"++  let libFile = zenc ("libHubris_" ++ moduleName)+  s <- generateSource sources moduleName+  case s of+    Left s -> putStrLn ("HINT error: " ++ show s) >> return Nothing+    Right mod -> do+       putStrLn mod+       res <- ghcBuild libFile mod ("Language.Ruby.Hubris.Exports." ++ moduleName) sources defaultGHCOptions +       +       return (if res +                   then Just libFile+                   else Nothing)++generateSource :: [Filename] ->   -- optional haskell source to load into the interpreter+                   ModuleName ->   -- name of the module to build a wrapper for+                   IO (Either InterpreterError String)+generateSource sources moduleName = runInterpreter $ do+         say $ show sources+         loadModules sources+         say "loaded"+         -- setTopLevelModules [moduleName]+         setImportsQ $ map (\x->(x,Just x)) $ ("Language.Ruby.Hubris"):("Language.Ruby.Hubris.Binding"):moduleName:[]+++         functions <- getFunctions moduleName+         say $ "Candidates: " ++ (show functions)+       -- ok, let's see if we can come up with an expression of the right type+++         exportable <- filterM (\func -> do let rubyVal ="(fromIntegral $ fromEnum $ Language.Ruby.Hubris.Binding.RUBY_Qtrue)"+                                            let f = "Language.Ruby.Hubris.wrap " ++ moduleName ++"." ++func ++" " ++ rubyVal+                                            say f+                                            (typeOf f >>= \n -> say $ "type of wrap." ++ func ++ " is " ++ show n) +                                                 `catchError` (say . show)+                                            typeChecks (f ++ "==" ++ rubyVal )) functions++         say $ "Exportable: " ++ (show exportable)+            -- withTypes <- mapM  (\x ->  typeOf x >>= \t -> return (x,t)) exportable+         return $ unlines $+         -- ideally, all this stuff would be using something like the Interpolator module,+        -- but haskell-src-meta is not going on 6.12 yet, so let's do it traditionally instead.++          ["{-# LANGUAGE ForeignFunctionInterface #-}", +           "module Language.Ruby.Hubris.Exports." ++ moduleName ++ " where",+          "import Language.Ruby.Hubris",+          "import qualified Prelude",+          "import Language.Ruby.Hubris.Binding",+          "import qualified " ++ moduleName] +++          [fun ++ " :: Value -> Value" | fun <- exportable ] +++          [fun ++ " = Language.Ruby.Hubris.wrap " ++ moduleName ++ "." ++  fun | fun <- exportable ] ++++          ["foreign export ccall \"" ++  fun ++ "\" " ++ fun ++ " :: Value -> Value" | fun <- exportable ]++say = liftIO . putStrLn++getFunctions moduleName = do+  exports <- getModuleExports moduleName+  return $ map (\(Fun f) -> f) $ filter isFun exports++isFun (Fun f) = True+isFun _ = False
+ Language/Ruby/Hubris/ZCode.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE PatternGuards #-}++module Language.Ruby.Hubris.ZCode (zenc,zdec) where++import Data.Char+import Data.Ix+import qualified Data.Map as M+import Numeric++zemap :: M.Map Char String+zemap = M.fromList $+    [ ('(', "ZL")+    , (')', "ZR")+    , ('[', "ZM")+    , (']', "ZN")+    , (':', "ZC")+    , ('Z', "ZZ")++    , ('z', "zz")+    , ('&', "za")+    , ('|', "zb")+    , ('^', "zc")+    , ('$', "zd")+    , ('=', "ze")+    , ('>', "zg")+    , ('#', "zh")+    , ('.', "zi")+    , ('<', "zl")+    , ('-', "zm")+    , ('!', "zn")+    , ('+', "zp")+    , ('\'', "zq")+    , ('\\', "zr")+    , ('/', "zs")+    , ('*', "zt")+    , ('_', "zu")+    , ('%', "zv")+    ]++zdmap :: M.Map String Char+zdmap = M.fromList . map (\(a, b) -> (b, a)) . M.toList $ zemap++zenc, zdec :: String -> String++zenc = concatMap (\c -> M.findWithDefault (z c) c zemap)+    where+    z c+        | any (($ c) . inRange) [('a', 'y'), ('A', 'Z'), ('0', '9')] =+            [c]+        | otherwise =+            let+                s = showHex (ord c) "U"+                p = if inRange ('0', '9') (head s) then id else ('0' :)+            in+            'z' : p s++zdec "" = ""+zdec [c] = [c]+zdec (c : cs@(c' : cs'))+    | c `elem` "zZ"+    , Just x <- M.lookup [c, c'] zdmap+    = x : zdec cs'+    | c == 'z'+    , (h@(_ : _), 'U' : t) <- span isHexDigit cs+    , [(n, "")] <- readHex h+    = chr n : zdec t+    | otherwise = c : zdec cs
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ cbits/rshim.c view
@@ -0,0 +1,34 @@++#include "rshim.h"++#include <ruby.h>+#include <stdio.h>++/* void Init_rshim() { */+/*   printf("loaded, bitches\n"); */+/* } */++// did this really have to be a macro? BAD MATZ+unsigned int rtype(VALUE obj) {+  return TYPE(obj);+}++VALUE int2fix(int x) {+  return INT2FIX(x);+}++int fix2int(VALUE x) {+  return FIX2INT(x);+}++double num2dbl(VALUE x) {+  return NUM2DBL(x);+}++unsigned int rb_ary_len(VALUE x) {+  return RARRAY_LEN(x);+}++VALUE keys(VALUE hash) {+  rb_funcall(hash, rb_intern("keys"), 0);+}
+ cbits/rshim.h view
@@ -0,0 +1,49 @@+#ifndef __FOOSHIM__+#define __FOOSHIM__ 1+#define HAVE_STRUCT_TIMESPEC 1 +#include <ruby.h>++// did this really have to be a macro? BAD MATZ+unsigned int rtype(VALUE obj);+VALUE int2fix(int i);+int fix2int(VALUE x);+double num2dbl(VALUE x);+unsigned int rb_ary_len(VALUE x);+VALUE keys(VALUE hash);+// argh, and again+enum RubyType {+ RT_NONE     = T_NONE,++ RT_NIL      = T_NIL    ,+ RT_OBJECT   = T_OBJECT ,+ RT_CLASS    = T_CLASS  ,+ RT_ICLASS   = T_ICLASS ,+ RT_MODULE   = T_MODULE ,+ RT_FLOAT    = T_FLOAT  ,+ RT_STRING   = T_STRING ,+ RT_REGEXP   = T_REGEXP ,+ RT_ARRAY    = T_ARRAY  ,+ RT_FIXNUM   = T_FIXNUM ,+ RT_HASH     = T_HASH   ,+ RT_STRUCT   = T_STRUCT ,+ RT_BIGNUM   = T_BIGNUM ,+ RT_FILE     = T_FILE   ,++ RT_TRUE     = T_TRUE   ,+ RT_FALSE    = T_FALSE  ,+ RT_DATA     = T_DATA   ,+ RT_MATCH    = T_MATCH  ,+ RT_SYMBOL   = T_SYMBOL ,++ // t_BLKTAG   = T_BLKTAG , // this one is broken in ruby 1.9++ RT_UNDEF    = T_UNDEF  ,+ // t_VARMAP   = T_VARMAP , // this one is broken in ruby 1.9+ // t_SCOPE    = T_SCOPE  , // this one is broken in ruby 1.9+ RT_NODE     = T_NODE   ,++ RT_MASK     = T_MASK   ,+};+#endif++
+ hubris.cabal view
@@ -0,0 +1,46 @@+Name:                hubris+Version:             0.0.1+Author:              Mark Wotton+Maintainer:          mwotton@gmail.com+Build-Type:          Simple+Cabal-Version:       >=1.2+License:        OtherLicense+License-File:   LICENSE+Build-Type:     Simple+Author:         Mark Wotton <mwotton@gmail.com>+Maintainer:     Mark Wotton <mwotton@gmail.com>+bug-reports:    mailto:mwotton@gmail.com+Category:       Language+Stability:      Experimental+extra-source-files: +Synopsis:       Support library for Hubris, the Ruby <=> Haskell bridge+Description:    Support library for Hubris, the Ruby <=> Haskell bridge++Library+-- the ordering is critical, because Cabal doesn't do dependency analysis.+        Exposed-Modules: Language.Ruby.Hubris.Binding, Language.Ruby.Hubris, Language.Ruby.Hubris.LibraryBuilder, Language.Ruby.Hubris.ZCode, Language.Ruby.Hubris.GHCBuild+-- so this is a really filthy hack.+        c-sources: cbits/rshim.c +        includes:  cbits/rshim.h+        install-includes:  cbits/rshim.h++-- a proper fix for this would involve autoconf and I'm not feeling up to it.+        include-dirs: cbits /opt/local/include/ruby-1.9.1/ +        extra-lib-dirs: /opt/local/lib+       -- c2hsoptions: --cpp=gcc --cppopts=-E --cppopts=-xc+        extra-libraries: ruby+        build-depends:  ghc, Cabal>=1.7.4 && < 1.8, base, haskell98, containers, bytestring, array, mtl, old-time, ghc-paths, haskell-src-meta, hint++Executable Hubrify+  Main-is:           Hubrify.hs+  Build-Depends:     base >= 3 && < 5, ghc, Cabal>=1.7.4 && < 1.8, base, haskell98, containers, bytestring, array, mtl, old-time, ghc-paths, haskell-src-meta, hint+  Other-Modules:     Language.Ruby.Hubris.Binding+  c-sources: cbits/rshim.c +  include-dirs: cbits /opt/local/include/ruby-1.9.1/ +  extra-lib-dirs: /opt/local/lib+  extra-libraries: ruby+  -- This is bad form, apparently, and if i include it, ./Setup dist cries big fat tears,+  --  but you _really_ want a dynamic lib with Hubrify, or you'll get a truly+  -- huge binary (may not even link, I had problems with the iconv dependency from HSbase)+  -- anyway, pass "--ghc-options=-dynamic" to ./Setup build, and you should be apples.+  -- ghc-options: -dynamic