548 lines
22 KiB
Haskell
548 lines
22 KiB
Haskell
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
|
|
{-# OPTIONS_GHC -fno-warn-unused-binds #-}
|
|
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
|
|
{-# OPTIONS_GHC -fno-warn-unused-matches #-}
|
|
{-
|
|
There is a lot of code copied from GHC here, and some conditional
|
|
compilation. Instead of fixing all warnings and making it much more
|
|
difficult to compare the code to the original, just ignore unused
|
|
binds and imports.
|
|
-}
|
|
{-# LANGUAGE CPP #-}
|
|
{-# LANGUAGE PatternGuards #-}
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
|
|
{-
|
|
build package with the GHC API
|
|
-}
|
|
|
|
module GhcBuild (getBuildFlags, buildPackage, getPackageArgs) where
|
|
|
|
import qualified Control.Exception as Ex
|
|
import Control.Monad (when)
|
|
import Data.IORef
|
|
import System.Process (rawSystem)
|
|
import System.Environment (getEnvironment)
|
|
|
|
import CmdLineParser
|
|
import Data.Char (toLower)
|
|
import Data.List (isPrefixOf, isSuffixOf, partition)
|
|
import Data.Maybe (fromMaybe)
|
|
import DriverPhases (Phase (..), anyHsc, isHaskellSrcFilename,
|
|
isSourceFilename, startPhase)
|
|
import DriverPipeline (compileFile, link, linkBinary, oneShot)
|
|
import DynFlags (DynFlags, compilerInfo)
|
|
import qualified DynFlags
|
|
import qualified DynFlags as DF
|
|
import qualified GHC
|
|
import GHC.Paths (libdir)
|
|
import HscTypes (HscEnv (..), emptyHomePackageTable)
|
|
import qualified Module
|
|
import MonadUtils (liftIO)
|
|
import Panic (throwGhcException, panic)
|
|
import SrcLoc (Located, mkGeneralLocated)
|
|
import qualified StaticFlags
|
|
#if __GLASGOW_HASKELL__ >= 707
|
|
import DynFlags (ldInputs)
|
|
#else
|
|
import StaticFlags (v_Ld_inputs)
|
|
#endif
|
|
import System.FilePath (normalise, (</>))
|
|
import Util (consIORef, looksLikeModuleName)
|
|
|
|
{-
|
|
This contains a huge hack:
|
|
GHC only accepts setting static flags once per process, however it has no way to
|
|
get the remaining options from the command line, without setting the static flags.
|
|
This code overwrites the IORef to disable the check. This will likely cause
|
|
problems if the flags are modified, but fortunately that's relatively uncommon.
|
|
-}
|
|
getBuildFlags :: IO [Located String]
|
|
getBuildFlags = do
|
|
argv0 <- fmap read $ readFile "yesod-devel/ghcargs.txt" -- generated by yesod-ghc-wrapper
|
|
argv0' <- prependHsenvArgv argv0
|
|
let (minusB_args, argv1) = partition ("-B" `isPrefixOf`) argv0'
|
|
mbMinusB | null minusB_args = Nothing
|
|
| otherwise = Just (drop 2 (last minusB_args))
|
|
let argv1' = map (mkGeneralLocated "on the commandline") argv1
|
|
writeIORef StaticFlags.v_opt_C_ready False -- the huge hack
|
|
(argv2, staticFlagWarnings) <- GHC.parseStaticFlags argv1'
|
|
return argv2
|
|
|
|
prependHsenvArgv :: [String] -> IO [String]
|
|
prependHsenvArgv argv = do
|
|
env <- getEnvironment
|
|
return $ case (lookup "HSENV" env) of
|
|
Nothing -> argv
|
|
_ -> hsenvArgv ++ argv
|
|
where hsenvArgv = words $ fromMaybe "" (lookup "PACKAGE_DB_FOR_GHC" env)
|
|
|
|
-- construct a command line for loading the right packages
|
|
getPackageArgs :: Maybe String -> [Located String] -> IO [String]
|
|
getPackageArgs buildDir argv2 = do
|
|
(mode, argv3, modeFlagWarnings) <- parseModeFlags argv2
|
|
GHC.runGhc (Just libdir) $ do
|
|
dflags0 <- GHC.getSessionDynFlags
|
|
(dflags1, _, _) <- GHC.parseDynamicFlags dflags0 argv3
|
|
let pkgFlags = map convertPkgFlag (GHC.packageFlags dflags1)
|
|
ignorePkgFlags =
|
|
#if __GLASGOW_HASKELL__ >= 800
|
|
map convertIgnorePkgFlag (GHC.ignorePackageFlags dflags1)
|
|
#else
|
|
[]
|
|
#endif
|
|
trustPkgFlags =
|
|
#if __GLASGOW_HASKELL__ >= 800
|
|
map convertTrustPkgFlag (GHC.trustFlags dflags1)
|
|
#else
|
|
[]
|
|
#endif
|
|
hideAll | gopt DF.Opt_HideAllPackages dflags1 = [ "-hide-all-packages"]
|
|
| otherwise = []
|
|
ownPkg = packageString (DF.thisPackage dflags1)
|
|
return (reverse (extra dflags1) ++ hideAll ++ trustPkgFlags ++ ignorePkgFlags ++ pkgFlags ++ ownPkg)
|
|
where
|
|
#if __GLASGOW_HASKELL__ >= 800
|
|
convertIgnorePkgFlag (DF.IgnorePackage p) = "-ignore-package" ++ p
|
|
convertTrustPkgFlag (DF.TrustPackage p) = "-trust" ++ p
|
|
convertTrustPkgFlag (DF.DistrustPackage p) = "-distrust" ++ p
|
|
#else
|
|
convertPkgFlag (DF.IgnorePackage p) = "-ignore-package" ++ p
|
|
convertPkgFlag (DF.TrustPackage p) = "-trust" ++ p
|
|
convertPkgFlag (DF.DistrustPackage p) = "-distrust" ++ p
|
|
#endif
|
|
#if __GLASGOW_HASKELL__ >= 800
|
|
convertPkgFlag (DF.ExposePackage _ (DF.PackageArg p) _) = "-package" ++ p
|
|
convertPkgFlag (DF.ExposePackage _ (DF.UnitIdArg p) _) = "-package-id" ++ p
|
|
#elif __GLASGOW_HASKELL__ == 710
|
|
convertPkgFlag (DF.ExposePackage (DF.PackageArg p) _) = "-package" ++ p
|
|
convertPkgFlag (DF.ExposePackage (DF.PackageIdArg p) _) = "-package-id" ++ p
|
|
convertPkgFlag (DF.ExposePackage (DF.PackageKeyArg p) _) = "-package-key" ++ p
|
|
#else
|
|
convertPkgFlag (DF.ExposePackage p) = "-package" ++ p
|
|
convertPkgFlag (DF.ExposePackageId p) = "-package-id" ++ p
|
|
#endif
|
|
convertPkgFlag (DF.HidePackage p) = "-hide-package" ++ p
|
|
#if __GLASGOW_HASKELL__ >= 800
|
|
-- See: https://github.com/yesodweb/yesod/issues/1284
|
|
packageString _flags = []
|
|
--packageString flags = "-package-id" ++ Module.unitIdString flags
|
|
#elif __GLASGOW_HASKELL__ == 710
|
|
packageString flags = ["-package-key" ++ Module.packageKeyString flags]
|
|
#else
|
|
packageString flags = ["-package-id" ++ Module.packageIdString flags ++ "-inplace"]
|
|
#endif
|
|
#if __GLASGOW_HASKELL__ >= 705
|
|
extra df = inplaceConf ++ extra'
|
|
where
|
|
extra' = concatMap convertExtra (extraConfs df)
|
|
-- old cabal-install sometimes misses the .inplace db, fix it here
|
|
inplaceConf
|
|
| any (".inplace" `isSuffixOf`) extra' = []
|
|
| otherwise = ["-package-db" ++ fromMaybe "dist" buildDir
|
|
++ "/package.conf.inplace"]
|
|
extraConfs df = GHC.extraPkgConfs df []
|
|
convertExtra DF.GlobalPkgConf = [ ]
|
|
convertExtra DF.UserPkgConf = [ ]
|
|
convertExtra (DF.PkgConfFile file) = [ "-package-db" ++ file ]
|
|
#else
|
|
extra df = inplaceConf ++ extra'
|
|
where
|
|
extra' = map ("-package-conf"++) (GHC.extraPkgConfs df)
|
|
-- old cabal-install sometimes misses the .inplace db, fix it here
|
|
inplaceConf
|
|
| any (".inplace" `isSuffixOf`) extra' = []
|
|
| otherwise = ["-package-conf" ++ fromMaybe "dist" buildDir
|
|
++ "/package.conf.inplace"]
|
|
#endif
|
|
|
|
#if __GLASGOW_HASKELL__ >= 707
|
|
gopt = DF.gopt
|
|
#else
|
|
gopt = DF.dopt
|
|
#endif
|
|
|
|
|
|
buildPackage :: [Located String] -> FilePath -> FilePath -> IO Bool
|
|
buildPackage a ld ar = buildPackage' a ld ar `Ex.catch` \e -> do
|
|
putStrLn ("exception building package: " ++ show (e :: Ex.SomeException))
|
|
return False
|
|
|
|
buildPackage' :: [Located String] -> FilePath -> FilePath -> IO Bool
|
|
buildPackage' argv2 ld ar = do
|
|
(mode, argv3, modeFlagWarnings) <- parseModeFlags argv2
|
|
GHC.runGhc (Just libdir) $ do
|
|
dflags0 <- GHC.getSessionDynFlags
|
|
(dflags1, _, _) <- GHC.parseDynamicFlags dflags0 argv3
|
|
let dflags2 = dflags1 { GHC.ghcMode = GHC.CompManager
|
|
, GHC.hscTarget = GHC.hscTarget dflags1
|
|
, GHC.ghcLink = GHC.LinkBinary
|
|
, GHC.verbosity = 1
|
|
}
|
|
(dflags3, fileish_args, _) <- GHC.parseDynamicFlags dflags2 argv3
|
|
GHC.setSessionDynFlags dflags3
|
|
let normal_fileish_paths = map (normalise . GHC.unLoc) fileish_args
|
|
(srcs, objs) = partition_args normal_fileish_paths [] []
|
|
(hs_srcs, non_hs_srcs) = partition haskellish srcs
|
|
haskellish (f,Nothing) =
|
|
looksLikeModuleName f || isHaskellSrcFilename f || '.' `notElem` f
|
|
haskellish (_,Just phase) =
|
|
#if MIN_VERSION_ghc(8,0,0)
|
|
phase `notElem` [As True, As False, Cc, Cobjc, Cobjcxx, CmmCpp, Cmm, StopLn]
|
|
#elif MIN_VERSION_ghc(7,8,3)
|
|
phase `notElem` [As True, As False, Cc, Cobjc, Cobjcpp, CmmCpp, Cmm, StopLn]
|
|
#elif MIN_VERSION_ghc(7,4,0)
|
|
phase `notElem` [As, Cc, Cobjc, Cobjcpp, CmmCpp, Cmm, StopLn]
|
|
#else
|
|
phase `notElem` [As, Cc, CmmCpp, Cmm, StopLn]
|
|
#endif
|
|
hsc_env <- GHC.getSession
|
|
-- if (null hs_srcs)
|
|
-- then liftIO (oneShot hsc_env StopLn srcs)
|
|
-- else do
|
|
#if MIN_VERSION_ghc(7,2,0)
|
|
o_files <- mapM (\x -> liftIO $ compileFile hsc_env StopLn x)
|
|
#else
|
|
o_files <- mapM (\x -> compileFile hsc_env StopLn x)
|
|
#endif
|
|
non_hs_srcs
|
|
#if __GLASGOW_HASKELL__ >= 707
|
|
let dflags4 = dflags3
|
|
{ ldInputs = map (DF.FileOption "") (reverse o_files)
|
|
++ ldInputs dflags3
|
|
}
|
|
GHC.setSessionDynFlags dflags4
|
|
#else
|
|
liftIO $ mapM_ (consIORef v_Ld_inputs) (reverse o_files)
|
|
#endif
|
|
targets <- mapM (uncurry GHC.guessTarget) hs_srcs
|
|
GHC.setTargets targets
|
|
ok_flag <- GHC.load GHC.LoadAllTargets
|
|
if GHC.failed ok_flag
|
|
then return False
|
|
else liftIO (linkPkg ld ar) >> return True
|
|
|
|
linkPkg :: FilePath -> FilePath -> IO ()
|
|
linkPkg ld ar = do
|
|
arargs <- fmap read $ readFile "yesod-devel/arargs.txt"
|
|
rawSystem ar arargs
|
|
ldargs <- fmap read $ readFile "yesod-devel/ldargs.txt"
|
|
rawSystem ld ldargs
|
|
return ()
|
|
|
|
--------------------------------------------------------------------------------------------
|
|
-- stuff below copied from ghc main.hs
|
|
--------------------------------------------------------------------------------------------
|
|
|
|
partition_args :: [String] -> [(String, Maybe Phase)] -> [String]
|
|
-> ([(String, Maybe Phase)], [String])
|
|
partition_args [] srcs objs = (reverse srcs, reverse objs)
|
|
partition_args ("-x":suff:args) srcs objs
|
|
| "none" <- suff = partition_args args srcs objs
|
|
| StopLn <- phase = partition_args args srcs (slurp ++ objs)
|
|
| otherwise = partition_args rest (these_srcs ++ srcs) objs
|
|
where phase = startPhase suff
|
|
(slurp,rest) = break (== "-x") args
|
|
these_srcs = zip slurp (repeat (Just phase))
|
|
partition_args (arg:args) srcs objs
|
|
| looks_like_an_input arg = partition_args args ((arg,Nothing):srcs) objs
|
|
| otherwise = partition_args args srcs (arg:objs)
|
|
|
|
{-
|
|
We split out the object files (.o, .dll) and add them
|
|
to v_Ld_inputs for use by the linker.
|
|
|
|
The following things should be considered compilation manager inputs:
|
|
|
|
- haskell source files (strings ending in .hs, .lhs or other
|
|
haskellish extension),
|
|
|
|
- module names (not forgetting hierarchical module names),
|
|
|
|
- and finally we consider everything not containing a '.' to be
|
|
a comp manager input, as shorthand for a .hs or .lhs filename.
|
|
|
|
Everything else is considered to be a linker object, and passed
|
|
straight through to the linker.
|
|
-}
|
|
looks_like_an_input :: String -> Bool
|
|
looks_like_an_input m = isSourceFilename m
|
|
|| looksLikeModuleName m
|
|
|| '.' `notElem` m
|
|
|
|
|
|
|
|
-- Parsing the mode flag
|
|
|
|
parseModeFlags :: [Located String]
|
|
-> IO (Mode,
|
|
[Located String],
|
|
[Located String])
|
|
parseModeFlags args = do
|
|
let ((leftover, errs1, warns), (mModeFlag, errs2, flags')) =
|
|
runCmdLine (processArgs mode_flags args)
|
|
(Nothing, [], [])
|
|
mode = case mModeFlag of
|
|
Nothing -> doMakeMode
|
|
Just (m, _) -> m
|
|
errs = errs1 ++ map (mkGeneralLocated "on the commandline") errs2
|
|
#if __GLASGOW_HASKELL__ >= 710
|
|
errorsToGhcException' = errorsToGhcException . map (\(GHC.L _ e) -> ("on the commandline", e))
|
|
#else
|
|
errorsToGhcException' = errorsToGhcException
|
|
#endif
|
|
|
|
when (not (null errs)) $ throwGhcException $ errorsToGhcException' errs
|
|
return (mode, flags' ++ leftover, warns)
|
|
|
|
type ModeM = CmdLineP (Maybe (Mode, String), [String], [Located String])
|
|
-- mode flags sometimes give rise to new DynFlags (eg. -C, see below)
|
|
-- so we collect the new ones and return them.
|
|
|
|
mode_flags :: [Flag ModeM]
|
|
mode_flags =
|
|
[ ------- help / version ----------------------------------------------
|
|
mkFlag "?" (PassFlag (setMode showGhcUsageMode))
|
|
, mkFlag "-help" (PassFlag (setMode showGhcUsageMode))
|
|
, mkFlag "V" (PassFlag (setMode showVersionMode))
|
|
, mkFlag "-version" (PassFlag (setMode showVersionMode))
|
|
, mkFlag "-numeric-version" (PassFlag (setMode showNumVersionMode))
|
|
, mkFlag "-info" (PassFlag (setMode showInfoMode))
|
|
, mkFlag "-supported-languages" (PassFlag (setMode showSupportedExtensionsMode))
|
|
, mkFlag "-supported-extensions" (PassFlag (setMode showSupportedExtensionsMode))
|
|
] ++
|
|
[ mkFlag k' (PassFlag (setMode (printSetting k)))
|
|
| k <- ["Project version",
|
|
"Booter version",
|
|
"Stage",
|
|
"Build platform",
|
|
"Host platform",
|
|
"Target platform",
|
|
"Have interpreter",
|
|
"Object splitting supported",
|
|
"Have native code generator",
|
|
"Support SMP",
|
|
"Unregisterised",
|
|
"Tables next to code",
|
|
"RTS ways",
|
|
"Leading underscore",
|
|
"Debug on",
|
|
"LibDir",
|
|
"Global Package DB",
|
|
"C compiler flags",
|
|
"Gcc Linker flags",
|
|
"Ld Linker flags"],
|
|
let k' = "-print-" ++ map (replaceSpace . toLower) k
|
|
replaceSpace ' ' = '-'
|
|
replaceSpace c = c
|
|
] ++
|
|
------- interfaces ----------------------------------------------------
|
|
[ mkFlag "-show-iface" (HasArg (\f -> setMode (showInterfaceMode f)
|
|
"--show-iface"))
|
|
|
|
------- primary modes ------------------------------------------------
|
|
, mkFlag "c" (PassFlag (\f -> do setMode (stopBeforeMode StopLn) f
|
|
addFlag "-no-link" f))
|
|
, mkFlag "M" (PassFlag (setMode doMkDependHSMode))
|
|
, mkFlag "E" (PassFlag (setMode (stopBeforeMode anyHsc)))
|
|
, mkFlag "C" (PassFlag (\f -> do setMode (stopBeforeMode HCc) f
|
|
addFlag "-fvia-C" f))
|
|
#if MIN_VERSION_ghc(7,8,3)
|
|
, mkFlag "S" (PassFlag (setMode (stopBeforeMode (As True))))
|
|
#else
|
|
, mkFlag "S" (PassFlag (setMode (stopBeforeMode As)))
|
|
#endif
|
|
, mkFlag "-make" (PassFlag (setMode doMakeMode))
|
|
, mkFlag "-interactive" (PassFlag (setMode doInteractiveMode))
|
|
, mkFlag "-abi-hash" (PassFlag (setMode doAbiHashMode))
|
|
, mkFlag "e" (SepArg (\s -> setMode (doEvalMode s) "-e"))
|
|
]
|
|
#if MIN_VERSION_ghc(7,10,1)
|
|
where mkFlag fName fOptKind = Flag fName fOptKind AllModes
|
|
#else
|
|
where mkFlag fName fOptKind = Flag fName fOptKind
|
|
#endif
|
|
|
|
setMode :: Mode -> String -> EwM ModeM ()
|
|
setMode newMode newFlag = liftEwM $ do
|
|
(mModeFlag, errs, flags') <- getCmdLineState
|
|
let (modeFlag', errs') =
|
|
case mModeFlag of
|
|
Nothing -> ((newMode, newFlag), errs)
|
|
Just (oldMode, oldFlag) ->
|
|
case (oldMode, newMode) of
|
|
-- -c/--make are allowed together, and mean --make -no-link
|
|
_ | isStopLnMode oldMode && isDoMakeMode newMode
|
|
|| isStopLnMode newMode && isDoMakeMode oldMode ->
|
|
((doMakeMode, "--make"), [])
|
|
|
|
-- If we have both --help and --interactive then we
|
|
-- want showGhciUsage
|
|
_ | isShowGhcUsageMode oldMode &&
|
|
isDoInteractiveMode newMode ->
|
|
((showGhciUsageMode, oldFlag), [])
|
|
| isShowGhcUsageMode newMode &&
|
|
isDoInteractiveMode oldMode ->
|
|
((showGhciUsageMode, newFlag), [])
|
|
-- Otherwise, --help/--version/--numeric-version always win
|
|
| isDominantFlag oldMode -> ((oldMode, oldFlag), [])
|
|
| isDominantFlag newMode -> ((newMode, newFlag), [])
|
|
-- We need to accumulate eval flags like "-e foo -e bar"
|
|
(Right (Right (DoEval esOld)),
|
|
Right (Right (DoEval [eNew]))) ->
|
|
((Right (Right (DoEval (eNew : esOld))), oldFlag),
|
|
errs)
|
|
-- Saying e.g. --interactive --interactive is OK
|
|
_ | oldFlag == newFlag -> ((oldMode, oldFlag), errs)
|
|
-- Otherwise, complain
|
|
_ -> let err = flagMismatchErr oldFlag newFlag
|
|
in ((oldMode, oldFlag), err : errs)
|
|
putCmdLineState (Just modeFlag', errs', flags')
|
|
where isDominantFlag f = isShowGhcUsageMode f ||
|
|
isShowGhciUsageMode f ||
|
|
isShowVersionMode f ||
|
|
isShowNumVersionMode f
|
|
|
|
flagMismatchErr :: String -> String -> String
|
|
flagMismatchErr oldFlag newFlag
|
|
= "cannot use `" ++ oldFlag ++ "' with `" ++ newFlag ++ "'"
|
|
|
|
addFlag :: String -> String -> EwM ModeM ()
|
|
addFlag s flag = liftEwM $ do
|
|
(m, e, flags') <- getCmdLineState
|
|
putCmdLineState (m, e, mkGeneralLocated loc s : flags')
|
|
where loc = "addFlag by " ++ flag ++ " on the commandline"
|
|
|
|
type Mode = Either PreStartupMode PostStartupMode
|
|
type PostStartupMode = Either PreLoadMode PostLoadMode
|
|
|
|
data PreStartupMode
|
|
= ShowVersion -- ghc -V/--version
|
|
| ShowNumVersion -- ghc --numeric-version
|
|
| ShowSupportedExtensions -- ghc --supported-extensions
|
|
| Print String -- ghc --print-foo
|
|
|
|
showVersionMode, showNumVersionMode, showSupportedExtensionsMode :: Mode
|
|
showVersionMode = mkPreStartupMode ShowVersion
|
|
showNumVersionMode = mkPreStartupMode ShowNumVersion
|
|
showSupportedExtensionsMode = mkPreStartupMode ShowSupportedExtensions
|
|
|
|
mkPreStartupMode :: PreStartupMode -> Mode
|
|
mkPreStartupMode = Left
|
|
|
|
isShowVersionMode :: Mode -> Bool
|
|
isShowVersionMode (Left ShowVersion) = True
|
|
isShowVersionMode _ = False
|
|
|
|
isShowNumVersionMode :: Mode -> Bool
|
|
isShowNumVersionMode (Left ShowNumVersion) = True
|
|
isShowNumVersionMode _ = False
|
|
|
|
data PreLoadMode
|
|
= ShowGhcUsage -- ghc -?
|
|
| ShowGhciUsage -- ghci -?
|
|
| ShowInfo -- ghc --info
|
|
| PrintWithDynFlags (DynFlags -> String) -- ghc --print-foo
|
|
|
|
showGhcUsageMode, showGhciUsageMode, showInfoMode :: Mode
|
|
showGhcUsageMode = mkPreLoadMode ShowGhcUsage
|
|
showGhciUsageMode = mkPreLoadMode ShowGhciUsage
|
|
showInfoMode = mkPreLoadMode ShowInfo
|
|
|
|
printSetting :: String -> Mode
|
|
printSetting k = mkPreLoadMode (PrintWithDynFlags f)
|
|
where f dflags = fromMaybe (panic ("Setting not found: " ++ show k))
|
|
#if MIN_VERSION_ghc(7,2,0)
|
|
$ lookup k (compilerInfo dflags)
|
|
#else
|
|
$ fmap convertPrintable (lookup k compilerInfo)
|
|
where
|
|
convertPrintable (DynFlags.String s) = s
|
|
convertPrintable (DynFlags.FromDynFlags f) = f dflags
|
|
#endif
|
|
|
|
mkPreLoadMode :: PreLoadMode -> Mode
|
|
mkPreLoadMode = Right . Left
|
|
|
|
isShowGhcUsageMode :: Mode -> Bool
|
|
isShowGhcUsageMode (Right (Left ShowGhcUsage)) = True
|
|
isShowGhcUsageMode _ = False
|
|
|
|
isShowGhciUsageMode :: Mode -> Bool
|
|
isShowGhciUsageMode (Right (Left ShowGhciUsage)) = True
|
|
isShowGhciUsageMode _ = False
|
|
|
|
data PostLoadMode
|
|
= ShowInterface FilePath -- ghc --show-iface
|
|
| DoMkDependHS -- ghc -M
|
|
| StopBefore Phase -- ghc -E | -C | -S
|
|
-- StopBefore StopLn is the default
|
|
| DoMake -- ghc --make
|
|
| DoInteractive -- ghc --interactive
|
|
| DoEval [String] -- ghc -e foo -e bar => DoEval ["bar", "foo"]
|
|
| DoAbiHash -- ghc --abi-hash
|
|
|
|
doMkDependHSMode, doMakeMode, doInteractiveMode, doAbiHashMode :: Mode
|
|
doMkDependHSMode = mkPostLoadMode DoMkDependHS
|
|
doMakeMode = mkPostLoadMode DoMake
|
|
doInteractiveMode = mkPostLoadMode DoInteractive
|
|
doAbiHashMode = mkPostLoadMode DoAbiHash
|
|
|
|
|
|
showInterfaceMode :: FilePath -> Mode
|
|
showInterfaceMode fp = mkPostLoadMode (ShowInterface fp)
|
|
|
|
stopBeforeMode :: Phase -> Mode
|
|
stopBeforeMode phase = mkPostLoadMode (StopBefore phase)
|
|
|
|
doEvalMode :: String -> Mode
|
|
doEvalMode str = mkPostLoadMode (DoEval [str])
|
|
|
|
mkPostLoadMode :: PostLoadMode -> Mode
|
|
mkPostLoadMode = Right . Right
|
|
|
|
isDoInteractiveMode :: Mode -> Bool
|
|
isDoInteractiveMode (Right (Right DoInteractive)) = True
|
|
isDoInteractiveMode _ = False
|
|
|
|
isStopLnMode :: Mode -> Bool
|
|
isStopLnMode (Right (Right (StopBefore StopLn))) = True
|
|
isStopLnMode _ = False
|
|
|
|
isDoMakeMode :: Mode -> Bool
|
|
isDoMakeMode (Right (Right DoMake)) = True
|
|
isDoMakeMode _ = False
|
|
|
|
#ifdef GHCI
|
|
isInteractiveMode :: PostLoadMode -> Bool
|
|
isInteractiveMode DoInteractive = True
|
|
isInteractiveMode _ = False
|
|
#endif
|
|
|
|
-- isInterpretiveMode: byte-code compiler involved
|
|
isInterpretiveMode :: PostLoadMode -> Bool
|
|
isInterpretiveMode DoInteractive = True
|
|
isInterpretiveMode (DoEval _) = True
|
|
isInterpretiveMode _ = False
|
|
|
|
needsInputsMode :: PostLoadMode -> Bool
|
|
needsInputsMode DoMkDependHS = True
|
|
needsInputsMode (StopBefore _) = True
|
|
needsInputsMode DoMake = True
|
|
needsInputsMode _ = False
|
|
|
|
-- True if we are going to attempt to link in this mode.
|
|
-- (we might not actually link, depending on the GhcLink flag)
|
|
isLinkMode :: PostLoadMode -> Bool
|
|
isLinkMode (StopBefore StopLn) = True
|
|
isLinkMode DoMake = True
|
|
isLinkMode DoInteractive = True
|
|
isLinkMode (DoEval _) = True
|
|
isLinkMode _ = False
|
|
|
|
isCompManagerMode :: PostLoadMode -> Bool
|
|
isCompManagerMode DoMake = True
|
|
isCompManagerMode DoInteractive = True
|
|
isCompManagerMode (DoEval _) = True
|
|
isCompManagerMode _ = False
|