#! /usr/bin/env runhaskell
module Main (main) where
import Control.Monad (liftM, when)
import Data.List (intersperse)
import Distribution.Simple
import Distribution.Simple.Setup
import Distribution.Simple.LocalBuildInfo
import Distribution.PackageDescription
import System.Process
import System.Exit
import System.Directory
import System.FilePath
main :: IO ()
main = defaultMainWithHooks simpleUserHooks{runTests=forsydeTests,
postInst=forsydePostInst,
postCopy=forsydePostCopy}
forsydeTests :: Args -> Bool -> PackageDescription -> LocalBuildInfo -> IO ()
forsydeTests _ _ _ _ = do
e <- runCommandMsg "runghc"
["-itests/properties", "-iexamples", "tests/properties/Main.hs"]
when (not e) exitFailure
forsydePostInst :: Args -> InstallFlags -> PackageDescription ->
LocalBuildInfo -> IO ()
forsydePostInst _ _ = compile_forsyde_vhd NoCopyDest
forsydePostCopy :: Args -> CopyFlags -> PackageDescription ->
LocalBuildInfo -> IO ()
forsydePostCopy _ cf = compile_forsyde_vhd $ removeFlag $ (copyDest cf) where
removeFlag c = case c of
Distribution.Simple.Setup.Flag x -> x
_ -> error "Not a Flag"
-- NOTE: Most of this code is duplicated from ForSyDe.Backend.VHDL.Modelsim,
-- however, it allows Setup.hs to be selfcontained
-- Compile forsyde.vhd if possible, showing what's going on to the end user
compile_forsyde_vhd :: CopyDest -> PackageDescription -> LocalBuildInfo
-> IO ()
compile_forsyde_vhd cd pd lbi = do
putStrLn "Compiling ForSyDe's VHDL library with Modelsim ..."
(ifNot isModelsimInstalled
(modelsimError "Modelsim executables could not be found.")) <&&>
(ifNot (do_compile_forsyde_vhd forsyde_vhd_dir)
( modelsimError "Compilation failed.")) <&&>
(putStrLn "Compilation succeded." >> return True)
return ()
where
forsyde_vhd_dir = (datadir $ absoluteInstallDirs pd lbi cd) </>
"lib"
modelsimError err = putStrLn $
"Error: " ++ err ++ "\n" ++
" ForSyDe will work, but you will not be able to automatically\n" ++
" compile or simulate the ForSyDe-generated VHDL models with Modelsim\n\n" ++
" In order to fix this, make sure that the Modelsim executables\n" ++
" can be found in PATH and reinstall ForSyDe"
-- Look for modelsim executables
isModelsimInstalled :: IO Bool
isModelsimInstalled = executablePresent "vlib" <&&>
executablePresent "vmap" <&&>
executablePresent "vcom"
where executablePresent = (liftM (maybe False (\_-> True))) .findExecutable
-- Create a modelsim library for forsyde.vhd
-- in the same directory in which forsyde.vhd was copied
do_compile_forsyde_vhd :: FilePath -- ^ absolute directory which
-- forsyde.vhd was copied into
-> IO Bool
do_compile_forsyde_vhd dir =
(runCommandMsg "vlib" [dir </> "modelsim"]) <&&>
(runCommandMsg
"vcom" ["-93", "-quiet", "-nologo", "-work", dir </> "modelsim",
dir </> "forsyde.vhd"])
where runWait :: String -> FilePath -> [String] -> IO Bool
runWait msg proc args = do
putStrLn msg
h <- runProcess proc args (Just dir) Nothing Nothing Nothing Nothing
code <- waitForProcess h
return $ code == ExitSuccess
-- | run a command showing what's being run
runCommandMsg :: String -- ^ Command to execute
-> [String] -- ^ Command arguments
-> IO Bool
runCommandMsg command args = runWait msg command args
where msg = "Running: " ++ command ++ " " ++ (concat $ intersperse " " args)
-- | Run a process, previously announcing a message and waiting for it
-- to finnish its execution.
runWait :: String -- ^ message to show
-> FilePath -- ^ command to execute
-> [String] -- ^ command arguments
-> IO Bool -- ^ Did the execution end succesfully?
runWait msg proc args = do
putStrLn msg
h <- runProcess proc args Nothing Nothing Nothing Nothing Nothing
code <- waitForProcess h
return $ code == ExitSuccess
-- | short-circuit and for monads
(<&&>) :: Monad m => m Bool -> m Bool -> m Bool
x <&&> y = do p <- x
if p then y else return False
-- | execute an action when the argument is False
-- and return the boolean value
ifNot :: Monad m => m Bool -> m () -> m Bool
ifNot x a = do p <- x
when (not p) a
return p