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 +7/−0
- LICENSE +22/−0
- Language/Ruby/Hubris.hs +104/−0
- Language/Ruby/Hubris/Binding.chs +156/−0
- Language/Ruby/Hubris/GHCBuild.hs +51/−0
- Language/Ruby/Hubris/LibraryBuilder.hs +80/−0
- Language/Ruby/Hubris/ZCode.hs +67/−0
- Setup.hs +2/−0
- cbits/rshim.c +34/−0
- cbits/rshim.h +49/−0
- hubris.cabal +46/−0
+ 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