dvda-0.1: Dvda/HSBuilder.hs
{-# OPTIONS_GHC -Wall #-}
{-# Language GADTs #-}
{-# Language FlexibleContexts #-}
{-# Language TypeOperators #-}
{-# Language TypeFamilies #-}
module Dvda.HSBuilder ( buildHSFunction
) where
import qualified Data.Hashable as H
import qualified Data.Vector.Unboxed as V
import System.Directory
import Control.Monad(when)
import qualified System.Plugins.Make as Make
import qualified System.Plugins.Load as Load
--import System.Process( runCommand, waitForProcess )
--import System.Exit( ExitCode(ExitSuccess) )
import Dvda.HSSyntax ( writeHSSource )
import Dvda.Graph ( FunGraph(..) )
import Dvda.SymMonad ( Exprs )
import qualified Dvda.Config as Config
-- | make source functions
buildHSFunction :: (H.Hashable a, Show a, V.Unbox a, Show b, Show c) =>
FunGraph a b c -> IO (Exprs b Double -> Exprs c Double)
buildHSFunction fg = do
-- source and hash
let hash = show $ abs $ H.hash fg
source = writeHSSource fg hash
-- function directory
dir <- Config.functionDir hash
-- make function directory if it doesn't exist
createDirectoryIfMissing False dir
-- filenames
let sourcePath = dir ++ "/" ++ Config.nameHSSource hash
-- objectPath = dir ++ "/" ++ Config.nameHSObject hash
-- if the source already exists, make sure it matches the old source
srcExists <- doesFileExist sourcePath
when srcExists $ do
oldSrc <- readFile sourcePath
when (source /= oldSrc) $ putStrLn $
"====================================================\n" ++
"WARNING: Hash not unique or source code has been edited\n"++
"If you have not edited the auto-generated code, please let me\n" ++
"know that Hash collisions are a problem at gregmainland@gmail.com\n" ++
"====================================================\n\n"
-- write source
putStrLn "writing source"
writeFile sourcePath source
-- compile code
putStrLn "building source"
objpath <- makeWithPlugins sourcePath
-- objpath <- makeWithProcess sourcePath objectPath
-- load object
putStrLn "loading object"
loadWithPlugins objpath hash
makeWithPlugins :: FilePath -> IO FilePath
makeWithPlugins sourcePath = do
status <- Make.make sourcePath [] -- ["-v3"]
case status of (Make.MakeSuccess _ path) -> do putStrLn "Success!"
return path
(Make.MakeFailure code) -> do mapM_ putStrLn code
error "Make Failure"
loadWithPlugins :: FilePath -> String -> IO a
loadWithPlugins objpath hash = do
status' <- Load.load_ objpath [] (Config.nameHSFunction hash)
case status' of (Load.LoadFailure codes) -> do mapM_ putStrLn codes
error "Load Failure"
(Load.LoadSuccess _ fun) -> do putStrLn "load success!"
return fun
-- -- | take in name of source and future object, compile object
-- makeWithProcess :: FilePath -> FilePath -> IO FilePath
-- makeWithProcess srcname objname = do
-- -- compile new object
-- let compileString = Config.ghcString srcname objname
-- displayString = Config.ghcString (shortName srcname) (shortName objname)
--
-- -- print compilation string
-- when Config.spewGccCall $ putStrLn displayString
--
-- -- run compilation string
-- p <- runCommand compileString
--
-- -- check for errors
-- exitCode <- waitForProcess p
-- when (exitCode /= ExitSuccess) $ error $ "failed compiling " ++ srcname
--
-- return objname
--
--
-- -- | shorten path name for display purposes
-- shortName :: String -> String
-- shortName full
-- | length name <= maxN = name ++ extension
-- | otherwise = take firstN name ++ "..." ++ drop (length name - lastN) name ++ extension
-- where
-- firstN = 20
-- lastN = 10
-- maxN = firstN + lastN
--
-- (name, extension) = break (== '.') $ reverse $ takeWhile (/= '/') (reverse full)