shaker-0.3: src/Shaker/SourceHelper.hs
-- | Utilities function for compilation and haskell file management
module Shaker.SourceHelper(
-- * Compile input management
CompileFile(..)
,mergeCompileInputsSources
,constructCompileFileList
-- * Target files filtering
,setAllHsFilesAsTargets
,removeFileWithMain
,removeFileWithTemplateHaskell
-- * GHC Compile management
,ghcCompile
)
where
import GHC
import Data.List
import Shaker.Io
import Shaker.Type
import Control.Monad.Reader
type CompileR = Reader [CompileFile]
data CompileFile = CompileFile {
cfFp :: FilePath
,cfHasMain :: Bool
,cfHasTH :: Bool
} deriving Show
-- | Build the list of haskell source files located in
-- CompileInput source dirs
constructCompileFileList :: CompileInput -> IO [CompileFile]
constructCompileFileList cpIn = do
files <- recurseMultipleListFiles fli
mapM constructCompileFile files
where fli = getFileListenInfoForCompileInput cpIn
constructCompileFile :: FilePath -> IO CompileFile
constructCompileFile fp = do
hasMain <- isFileContainingMain fp
hasTH <- isFileContainingTH fp
return $ CompileFile fp hasMain hasTH
-- | Merge source dirs informations from the CompileInput list to
-- create a single CompileInput
mergeCompileInputsSources :: [CompileInput] -> CompileInput
mergeCompileInputsSources [] = defaultCompileInput
mergeCompileInputsSources cplInps@(cpIn:_) = do
let srcDirs = nub $ concatMap cfSourceDirs cplInps
cpIn {cfSourceDirs = srcDirs, cfDescription ="Full compilation" }
-- | Configure the CompileInput with all haskell files configured as targets
setAllHsFilesAsTargets :: CompileInput -> CompileR CompileInput
setAllHsFilesAsTargets cpIn = do
files <- ask
return cpIn {cfTargetFiles = map cfFp files }
-- | Change the dynflags with information from the CompileInput like importPaths
-- and .o and .hi directory
configureDynFlagsWithCompileInput :: CompileInput -> DynFlags -> DynFlags
configureDynFlagsWithCompileInput cpIn dflags = dflags{
importPaths = sourceDirs
,objectDir = Just compileTarget
,hiDir = Just compileTarget
}
where compileTarget = cfCompileTarget cpIn
sourceDirs = cfSourceDirs cpIn
getFileListenInfoForCompileInput :: CompileInput -> [FileListenInfo]
getFileListenInfoForCompileInput cpIn =
map (\a -> FileListenInfo a defaultExclude defaultHaskellPatterns) (cfSourceDirs cpIn)
removeFileWithTemplateHaskell :: CompileInput ->CompileR CompileInput
removeFileWithTemplateHaskell = removeFileWithPredicate cfHasTH
removeFileWithMain :: CompileInput -> CompileR CompileInput
removeFileWithMain = removeFileWithPredicate cfHasMain
removeFileWithPredicate :: (CompileFile -> Bool) -> CompileInput -> CompileR CompileInput
removeFileWithPredicate predicate cpIn = do
cpFl <- ask
let toRemove = map cfFp $ filter predicate cpFl
return $ cpIn {cfTargetFiles = targets \\ toRemove}
where targets = cfTargetFiles cpIn
-- | Configure and load targets of compilation.
-- It is possible to exploit the compilation result after this step.
ghcCompile :: GhcMonad m => CompileInput -> m SuccessFlag
ghcCompile cpIn@(CompileInput _ _ _ procFlags strflags targetFiles) = do
dflags <- getSessionDynFlags
(newFlags,_,_) <- parseDynamicFlags dflags (map noLoc strflags)
let chgdFlags = configureDynFlagsWithCompileInput cpIn newFlags
_ <- setSessionDynFlags $ procFlags chgdFlags
target <- mapM (`guessTarget` Nothing) targetFiles
setTargets target
load LoadAllTargets