ddc-war-0.2.1.1: DDC/War/Job/CompileHS.hs
module DDC.War.Job.CompileHS
( Spec (..)
, Result (..)
, resultSuccess
, build)
where
import BuildBox.Command.File
import BuildBox.Command.System
import BuildBox.Build.Benchmark
import BuildBox.Data.Physical
import BuildBox.IO.Directory
import BuildBox.Pretty
import BuildBox
import System.FilePath
import System.Directory
import Control.Monad
import Data.List
-- | Use GHC to compile/make file.
data Spec
= Spec
{ -- | Root source file of the program (the 'Main.ds')
specFile :: FilePath
-- | Extra DDC options for building in this way.
, specOptionsGHC :: [String]
-- | Scratch dir to do the build in.
, specScratchDir :: String
-- | Put what DDC says to stdout here.
, specCompileStdout :: FilePath
-- | Put what DDC says to stderr here.
, specCompileStderr :: FilePath
-- | If Just, then we're making an executable, and put the binary here.
-- Otherwise simply compile it
, specMainBin :: FilePath }
deriving Show
data Result
= ResultSuccess Seconds
| ResultFailure
deriving Show
resultSuccess :: Result -> Bool
resultSuccess result
= case result of
ResultSuccess{} -> True
_ -> False
instance Pretty Result where
ppr result
= case result of
ResultSuccess seconds -> text "success" <+> parens (ppr seconds)
ResultFailure -> text "failed"
-- | Compile a Haskell Source File
build :: Spec -> Build Result
build (Spec srcHS _optionsGHC
buildDir mainCompOut mainCompErr
mainBin)
= do needs srcHS
-- The directory holding the Main.hs file.
let (srcDir, srcFile) = splitFileName srcHS
-- Copy the .hs files to the build directory.
-- This freshens them and ensures we won't conflict with other make jobs
-- running on the same source files, but in different ways.
ensureDir buildDir
sources <- io
$ liftM (filter (\f -> isSuffixOf ".hs" f))
$ lsFilesIn srcDir
_ <- ssystemq $ "cp " ++ (intercalate " " sources) ++ " " ++ buildDir
-- The copied version of the root source file.
let srcCopyHS = buildDir ++ "/" ++ srcFile
let buildMk = buildDir ++ "/build.mk"
-- We're doing this via a makefile so we get the ghc flags and options
-- from the DDC build system. The paths in the make file need to be in
-- posix form with '/' as the separators.
currentDir <- io $ getCurrentDirectory
let hacks f = map (\z -> if z == '\\' then '/' else z) f
let mainBin' = hacks $ makeRelative currentDir mainBin
let srcCopyHS' = hacks $ makeRelative currentDir srcCopyHS
genBuildMk buildMk mainBin' srcCopyHS'
(time, (code, strOut, strErr))
<- timeBuild
$ systemTee False
("make -f " ++ buildMk)
""
atomicWriteFile mainCompOut strOut
atomicWriteFile mainCompErr strErr
case code of
ExitSuccess -> return $ ResultSuccess time
ExitFailure _ -> return ResultFailure
genBuildMk :: FilePath -> String -> String -> Build ()
genBuildMk outfile mainBin mainHs
= do let str = "# Generated Makefile\n\n"
++ "include make/build.mk\n\n"
++ mainBin ++ " : " ++ mainHs ++ "\n"
++ "\t$(GHC) $(GHC_LANGUAGE) $(DDC_PACKAGES) -ipackages/ddc-main --make $^ -o $@\n\n"
io $ writeFile outfile str