2015-03-03 19:28:34 +00:00
-- ghc-mod: Making Haskell development *more* fun
-- Copyright (C) 2015 Daniel Gröber <dxld ÄT darkboxed DOT org>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
2014-07-18 05:05:20 +00:00
2015-03-03 20:12:43 +00:00
{- # LANGUAGE CPP, ViewPatterns, NamedFieldPuns, RankNTypes # -}
module Language.Haskell.GhcMod.Target where
import Control.Arrow
2015-08-03 01:09:56 +00:00
import Control.Applicative
2015-08-11 04:35:14 +00:00
import Control.Category ( ( . ) )
2015-03-03 20:12:43 +00:00
import GHC
2016-02-04 18:54:55 +00:00
# if __GLASGOW_HASKELL__ >= 800
import GHC.LanguageExtensions
# endif
2015-03-03 20:12:43 +00:00
import GHC.Paths ( libdir )
import SysTools
import DynFlags
2016-07-16 01:42:59 +00:00
import HscTypes
2016-12-13 00:40:05 +00:00
import Pretty
2015-03-03 20:12:43 +00:00
2014-07-18 05:05:20 +00:00
import Language.Haskell.GhcMod.DynFlags
2015-03-03 20:12:43 +00:00
import Language.Haskell.GhcMod.Monad.Types
import Language.Haskell.GhcMod.CabalHelper
import Language.Haskell.GhcMod.HomeModuleGraph
2015-03-28 01:30:51 +00:00
import Language.Haskell.GhcMod.PathsAndFiles
2015-03-03 20:12:43 +00:00
import Language.Haskell.GhcMod.GhcPkg
import Language.Haskell.GhcMod.Error
import Language.Haskell.GhcMod.Logging
import Language.Haskell.GhcMod.Types
2015-08-07 04:47:34 +00:00
import Language.Haskell.GhcMod.Utils as U
2015-05-31 08:32:46 +00:00
import Language.Haskell.GhcMod.FileMapping
2015-08-18 05:41:08 +00:00
import Language.Haskell.GhcMod.LightGhc
2015-09-07 01:49:12 +00:00
import Language.Haskell.GhcMod.CustomPackageDb
2015-09-08 04:44:02 +00:00
import Language.Haskell.GhcMod.Output
2015-06-19 15:15:14 +00:00
2016-01-13 03:49:38 +00:00
import Safe
2015-03-03 20:12:43 +00:00
import Data.Maybe
2015-08-03 01:09:56 +00:00
import Data.Monoid as Monoid
2015-03-03 20:12:43 +00:00
import Data.Either
2015-08-05 04:15:44 +00:00
import Data.Foldable as Foldable ( foldrM )
import qualified Data.Foldable as Foldable
2015-08-03 05:51:23 +00:00
import Data.Traversable hiding ( mapM , forM )
2015-03-03 20:12:43 +00:00
import Data.IORef
2015-08-05 02:06:22 +00:00
import Data.List
2015-03-05 15:50:06 +00:00
import Data.Map ( Map )
import qualified Data.Map as Map
2015-03-03 20:12:43 +00:00
import Data.Set ( Set )
import qualified Data.Set as Set
2015-06-16 08:28:46 +00:00
import Data.Function ( on )
2015-03-15 19:48:55 +00:00
import Distribution.Helper
2015-08-11 04:35:14 +00:00
import Prelude hiding ( ( . ) )
2015-03-03 20:12:43 +00:00
import System.Directory
import System.FilePath
2015-09-01 08:27:12 +00:00
runGmPkgGhc :: ( IOish m , Gm m ) => LightGhc a -> m a
2015-03-03 20:12:43 +00:00
runGmPkgGhc action = do
pkgOpts <- packageGhcOptions
withLightHscEnv pkgOpts $ \ env -> liftIO $ runLightGhc env action
initSession :: IOish m
2016-07-16 01:42:59 +00:00
=> [ GHCOption ]
-> ( forall gm . GhcMonad gm => DynFlags -> gm DynFlags )
-> GhcModT m ()
2015-03-03 20:12:43 +00:00
initSession opts mdf = do
s <- gmsGet
case gmGhcSession s of
2015-09-11 07:53:24 +00:00
Nothing -> do
gmLog GmDebug " initSession " $ text " Session not initialized, creating new one "
putNewSession s
2016-07-16 01:42:59 +00:00
Just ( GmGhcSession hsc_env_ref ) -> do
2016-02-14 07:41:11 +00:00
crdl <- cradle
2016-07-16 01:42:59 +00:00
df <- liftIO $ hsc_dflags <$> readIORef hsc_env_ref
changed <-
withLightHscEnv' ( initDF crdl ) $ \ hsc_env ->
2016-07-17 20:42:26 +00:00
return $ not $ hsc_dflags hsc_env ` eqDynFlags ` df
2015-03-03 20:12:43 +00:00
2016-02-14 07:41:11 +00:00
if changed
2016-07-16 01:42:59 +00:00
then do
gmLog GmDebug " initSession " $ text " Flags changed, creating new session "
teardownSession hsc_env_ref
putNewSession s
else
gmLog GmDebug " initSession " $ text " Session already initialized "
2015-04-29 16:44:21 +00:00
where
2016-07-16 01:42:59 +00:00
initDF Cradle { cradleTempDir } df =
setTmpDir cradleTempDir <$> ( mdf =<< addCmdOpts opts df )
2016-02-14 07:41:11 +00:00
2016-07-16 01:42:59 +00:00
teardownSession hsc_env_ref = do
hsc_env <- liftIO $ readIORef hsc_env_ref
teardownLightEnv hsc_env
2015-04-29 16:44:21 +00:00
2016-07-16 01:42:59 +00:00
putNewSession :: IOish m => GhcModState -> GhcModT m ()
putNewSession s = do
2016-02-14 07:41:11 +00:00
crdl <- cradle
2016-07-16 01:42:59 +00:00
nhsc_env_ref <- liftIO . newIORef =<< newLightEnv ( initDF crdl )
runLightGhc' nhsc_env_ref $ setSessionDynFlags =<< getSessionDynFlags
gmsPut s { gmGhcSession = Just $ GmGhcSession nhsc_env_ref }
2015-04-29 16:44:21 +00:00
2016-02-14 07:41:11 +00:00
2015-08-05 06:52:52 +00:00
-- | Drop the currently active GHC session, the next that requires a GHC session
-- will initialize a new one.
2015-04-29 16:44:21 +00:00
dropSession :: IOish m => GhcModT m ()
dropSession = do
s <- gmsGet
case gmGhcSession s of
2016-07-16 01:42:59 +00:00
Just ( GmGhcSession ref ) -> do
2015-04-29 16:44:21 +00:00
-- TODO: This is still not enough, there seem to still be references to
-- GHC's state around afterwards.
liftIO $ writeIORef ref ( error " HscEnv: session was dropped " )
2015-05-07 22:06:08 +00:00
-- Not available on ghc<7.8; didn't really help anyways
-- liftIO $ setUnsafeGlobalDynFlags (error "DynFlags: session was dropped")
2015-08-05 06:52:52 +00:00
gmsPut s { gmGhcSession = Nothing }
2015-04-29 16:44:21 +00:00
Nothing -> return ()
2015-08-05 06:52:52 +00:00
2016-01-12 17:23:51 +00:00
-- | Run a GmlT action (i.e. a function in the GhcMonad) in the context
-- of certain files or modules
2015-03-09 21:04:04 +00:00
runGmlT :: IOish m => [ Either FilePath ModuleName ] -> GmlT m a -> GhcModT m a
runGmlT fns action = runGmlT' fns return action
2015-03-03 20:12:43 +00:00
2016-01-12 17:23:51 +00:00
-- | Run a GmlT action (i.e. a function in the GhcMonad) in the context
-- of certain files or modules, with updated GHC flags
2015-03-09 21:04:04 +00:00
runGmlT' :: IOish m
2015-03-03 20:12:43 +00:00
=> [ Either FilePath ModuleName ]
2016-02-14 07:41:11 +00:00
-> ( forall gm . GhcMonad gm => DynFlags -> gm DynFlags )
2015-03-09 21:04:04 +00:00
-> GmlT m a
2015-03-03 20:12:43 +00:00
-> GhcModT m a
2015-03-09 21:04:04 +00:00
runGmlT' fns mdf action = runGmlTWith fns mdf id action
2015-03-03 20:12:43 +00:00
2016-01-12 17:23:51 +00:00
-- | Run a GmlT action (i.e. a function in the GhcMonad) in the context
-- of certain files or modules, with updated GHC flags and a final
-- transformation
2015-03-09 21:04:04 +00:00
runGmlTWith :: IOish m
2015-03-03 20:12:43 +00:00
=> [ Either FilePath ModuleName ]
2016-02-14 07:41:11 +00:00
-> ( forall gm . GhcMonad gm => DynFlags -> gm DynFlags )
2015-03-09 21:04:04 +00:00
-> ( GmlT m a -> GmlT m b )
-> GmlT m a
2015-03-03 20:12:43 +00:00
-> GhcModT m b
2015-03-09 21:04:04 +00:00
runGmlTWith efnmns' mdf wrapper action = do
2015-03-03 20:12:43 +00:00
crdl <- cradle
2015-09-01 08:27:12 +00:00
Options { optGhcUserOptions } <- options
2015-03-03 20:12:43 +00:00
let ( fns , mns ) = partitionEithers efnmns'
ccfns = map ( cradleCurrentDir crdl </> ) fns
2015-08-16 20:20:00 +00:00
cfns <- mapM getCanonicalFileNameSafe ccfns
2015-04-11 14:41:17 +00:00
let serfnmn = Set . fromList $ map Right mns ++ map Left cfns
2015-03-03 20:12:43 +00:00
opts <- targetGhcOptions crdl serfnmn
2015-09-01 08:27:12 +00:00
let opts' = opts ++ [ " -O0 " ] ++ optGhcUserOptions
2015-03-03 20:12:43 +00:00
2015-08-03 06:09:24 +00:00
gmVomit
" session-ghc-options "
2015-08-05 02:06:22 +00:00
( text " Initializing GHC session with following options " )
( intercalate " " $ map ( ( " \ " " ++ ) . ( ++ " \ " " ) ) opts' )
2015-08-03 06:09:24 +00:00
2015-09-16 03:09:55 +00:00
GhcModLog { gmLogLevel = Just level } <- gmlHistory
2015-09-08 04:44:02 +00:00
putErr <- gmErrStrIO
2015-09-16 03:09:55 +00:00
let setLogger | level >= GmDebug = setDebugLogger putErr
| otherwise = setEmptyLogger
2015-03-03 20:12:43 +00:00
initSession opts' $
2015-12-15 23:23:51 +00:00
setHscNothing >>> setLogger >>> mdf
2015-03-03 20:12:43 +00:00
2015-06-16 08:28:46 +00:00
mappedStrs <- getMMappedFilePaths
let targetStrs = mappedStrs ++ map moduleNameString mns ++ cfns
2015-03-09 21:04:04 +00:00
unGmlT $ wrapper $ do
2015-08-18 08:54:55 +00:00
loadTargets opts targetStrs
2015-03-03 20:12:43 +00:00
action
2015-03-28 01:30:51 +00:00
targetGhcOptions :: forall m . IOish m
2015-03-03 20:12:43 +00:00
=> Cradle
-> Set ( Either FilePath ModuleName )
-> GhcModT m [ GHCOption ]
targetGhcOptions crdl sefnmn = do
when ( Set . null sefnmn ) $ error " targetGhcOptions: no targets given "
2015-09-11 01:48:52 +00:00
case cradleProject crdl of
proj
| isCabalHelperProject proj -> cabalOpts crdl
| otherwise -> sandboxOpts crdl
2015-03-03 20:12:43 +00:00
where
zipMap f l = l ` zip ` ( f ` map ` l )
2015-03-28 01:30:51 +00:00
cabalOpts :: Cradle -> GhcModT m [ String ]
cabalOpts Cradle { .. } = do
2015-06-07 18:36:49 +00:00
mcs <- cabalResolvedComponents
2015-03-03 20:12:43 +00:00
let mdlcs = moduleComponents mcs ` zipMap ` Set . toList sefnmn
2015-04-12 00:40:39 +00:00
candidates = findCandidates $ map snd mdlcs
2015-03-03 20:12:43 +00:00
2015-03-08 16:32:17 +00:00
let noCandidates = Set . null candidates
noModuleHasAnyAssignment = all ( Set . null . snd ) mdlcs
if noCandidates && noModuleHasAnyAssignment
then do
2015-06-07 18:36:49 +00:00
-- First component should be ChLibName, if no lib will take lexically first exe.
let cns = filter ( /= ChSetupHsName ) $ Map . keys mcs
2015-08-18 02:34:39 +00:00
gmLog GmDebug " " $ strDoc $ " Could not find a component assignment, falling back to picking library component in cabal file. "
2016-01-13 03:49:38 +00:00
return $ gmcGhcOpts $ fromJustNote " targetGhcOptions, no-assignment " $ Map . lookup ( head cns ) mcs
2015-03-08 16:32:17 +00:00
else do
when noCandidates $
throwError $ GMECabalCompAssignment mdlcs
let cn = pickComponent candidates
2016-01-13 03:49:38 +00:00
return $ gmcGhcOpts $ fromJustNote " targetGhcOptions " $ Map . lookup cn mcs
2015-03-03 20:12:43 +00:00
2015-08-18 09:41:14 +00:00
resolvedComponentsCache :: IOish m => FilePath ->
Cached ( GhcModT m ) GhcModState
2015-08-03 01:09:56 +00:00
[ GmComponent 'GMCRaw ( Set . Set ModulePath ) ]
( Map . Map ChComponentName ( GmComponent 'GMCResolved ( Set . Set ModulePath ) ) )
2015-08-19 04:48:27 +00:00
resolvedComponentsCache distdir = Cached {
2015-08-11 04:35:14 +00:00
cacheLens = Just ( lGmcResolvedComponents . lGmCaches ) ,
2015-08-19 04:48:27 +00:00
cacheFile = resolvedComponentsCacheFile distdir ,
2015-04-12 00:39:18 +00:00
cachedAction = \ tcfs comps ma -> do
2015-03-28 01:30:51 +00:00
Cradle { .. } <- cradle
2015-11-18 20:41:19 +00:00
let iifs = invalidatingInputFiles tcfs
setupChanged =
( cradleRootDir </> setupConfigPath distdir ) ` elem ` iifs
2015-08-05 02:06:22 +00:00
mums :: Maybe [ Either FilePath ModuleName ]
2015-07-03 01:50:08 +00:00
mums =
2015-11-18 20:41:19 +00:00
let
filterOutSetupCfg =
filter ( /= cradleRootDir </> setupConfigPath distdir )
changedFiles = filterOutSetupCfg iifs
2015-11-21 16:27:31 +00:00
in if null changedFiles || setupChanged
2015-11-18 20:41:19 +00:00
then Nothing
else Just $ map Left changedFiles
2015-08-05 02:06:22 +00:00
let mdesc ( Left f ) = " file: " ++ f
mdesc ( Right mn ) = " module: " ++ moduleNameString mn
changed = map ( text . mdesc ) $ Foldable . concat mums
changedDoc | [] <- changed = text " none "
| otherwise = sep changed
2015-08-03 06:09:24 +00:00
gmLog GmDebug " resolvedComponentsCache " $
2015-08-05 02:06:22 +00:00
text " files changed " <+>: changedDoc
2015-03-28 01:30:51 +00:00
2015-11-21 16:30:18 +00:00
mcs <- resolveGmComponents ( ( , ) <$> mums <*> ma ) comps
2015-08-19 04:48:27 +00:00
return ( setupConfigPath distdir : flatten mcs , mcs )
2015-03-28 01:30:51 +00:00
}
where
flatten :: Map . Map ChComponentName ( GmComponent t ( Set . Set ModulePath ) )
-> [ FilePath ]
flatten = Map . elems
>>> map ( gmcHomeModuleGraph >>> gmgGraph
2015-08-18 02:27:02 +00:00
>>> ( Map . keysSet &&& Map . elems )
>>> uncurry insert
2015-03-28 01:30:51 +00:00
>>> map ( Set . map mpPath )
>>> Set . unions
)
>>> Set . unions
>>> Set . toList
moduleComponents :: Map ChComponentName ( GmComponent t ( Set ModulePath ) )
2015-03-03 20:12:43 +00:00
-> Either FilePath ModuleName
2015-03-15 19:48:55 +00:00
-> Set ChComponentName
2015-03-03 20:12:43 +00:00
moduleComponents m efnmn =
foldr' Set . empty m $ \ c s ->
let
memb =
case efnmn of
Left fn -> fn ` Set . member ` Set . map mpPath ( smp c )
Right mn -> mn ` Set . member ` Set . map mpModule ( smp c )
in if memb
then Set . insert ( gmcName c ) s
else s
where
smp c = Map . keysSet $ gmgGraph $ gmcHomeModuleGraph c
foldr' b as f = Map . foldr f b as
2015-04-12 00:40:39 +00:00
findCandidates :: [ Set ChComponentName ] -> Set ChComponentName
findCandidates [] = Set . empty
findCandidates scns = foldl1 Set . intersection scns
2015-03-15 19:48:55 +00:00
pickComponent :: Set ChComponentName -> ChComponentName
2015-03-03 20:12:43 +00:00
pickComponent scn = Set . findMin scn
2016-05-22 00:53:51 +00:00
packageGhcOptions :: ( IOish m , Applicative m , Gm m ) => m [ GHCOption ]
2015-03-03 20:12:43 +00:00
packageGhcOptions = do
crdl <- cradle
2015-09-11 01:48:52 +00:00
case cradleProject crdl of
proj
| isCabalHelperProject proj -> getGhcMergedPkgOptions
| otherwise -> sandboxOpts crdl
2015-03-03 20:12:43 +00:00
2015-08-12 07:25:13 +00:00
-- also works for plain projects!
2015-09-07 01:49:12 +00:00
sandboxOpts :: ( IOish m , GmEnv m ) => Cradle -> m [ String ]
2015-08-07 04:47:34 +00:00
sandboxOpts crdl = do
2015-09-07 01:49:12 +00:00
mCusPkgDb <- getCustomPkgDbStack
2015-08-19 06:46:56 +00:00
pkgDbStack <- liftIO $ getSandboxPackageDbStack
2015-09-07 01:49:12 +00:00
let pkgOpts = ghcDbStackOpts $ fromMaybe pkgDbStack mCusPkgDb
2015-03-28 01:30:51 +00:00
return $ [ " -i " ++ d | d <- [ wdir , rdir ] ] ++ pkgOpts ++ [ " -Wall " ]
2015-03-03 20:12:43 +00:00
where
( wdir , rdir ) = ( cradleCurrentDir crdl , cradleRootDir crdl )
2015-08-19 06:46:56 +00:00
getSandboxPackageDbStack :: IO [ GhcPkgDb ]
getSandboxPackageDbStack =
( [ GlobalDb ] ++ ) . maybe [ UserDb ] return <$> getSandboxDb crdl
2015-08-07 04:47:34 +00:00
2015-09-01 08:27:12 +00:00
resolveGmComponent :: ( IOish m , Gm m )
2015-06-19 15:15:14 +00:00
=> Maybe [ CompilationUnit ] -- ^ Updated modules
2015-08-03 01:09:56 +00:00
-> GmComponent 'GMCRaw ( Set ModulePath )
-> m ( GmComponent 'GMCResolved ( Set ModulePath ) )
2015-03-28 01:30:51 +00:00
resolveGmComponent mums c @ GmComponent { .. } = do
2015-08-18 09:41:14 +00:00
distDir <- cradleDistDir <$> cradle
2015-09-02 03:30:00 +00:00
gmLog GmDebug " resolveGmComponent " $ text $ show $ ghcOpts distDir
2015-08-18 09:41:14 +00:00
withLightHscEnv ( ghcOpts distDir ) $ \ env -> do
2015-03-28 01:30:51 +00:00
let srcDirs = if null gmcSourceDirs then [ " " ] else gmcSourceDirs
let mg = gmcHomeModuleGraph
let simp = gmcEntrypoints
sump <- case mums of
2015-03-03 20:12:43 +00:00
Nothing -> return simp
2015-04-12 00:36:17 +00:00
Just ums ->
Set . fromList . catMaybes <$>
mapM ( resolveModule env srcDirs ) ums
2015-03-03 20:12:43 +00:00
2015-04-11 14:41:17 +00:00
mg' <- canonicalizeModuleGraph =<< updateHomeModuleGraph env mg simp sump
2015-03-03 20:12:43 +00:00
return $ c { gmcEntrypoints = simp , gmcHomeModuleGraph = mg' }
2015-08-18 09:41:14 +00:00
where ghcOpts distDir = concat [
2015-04-12 00:36:17 +00:00
gmcGhcSrcOpts ,
gmcGhcLangOpts ,
2015-08-18 09:41:14 +00:00
[ " -optP-include " , " -optP " ++ distDir </> macrosHeaderPath ]
2015-04-12 00:36:17 +00:00
]
2015-09-01 08:27:12 +00:00
resolveEntrypoint :: ( IOish m , Gm m )
2015-03-28 01:30:51 +00:00
=> Cradle
2015-08-03 01:09:56 +00:00
-> GmComponent 'GMCRaw ChEntrypoint
-> m ( GmComponent 'GMCRaw ( Set ModulePath ) )
2015-06-19 15:15:14 +00:00
resolveEntrypoint Cradle { .. } c @ GmComponent { .. } = do
2015-09-02 03:30:00 +00:00
gmLog GmDebug " resolveEntrypoint " $ text $ show $ gmcGhcSrcOpts
2015-03-28 01:30:51 +00:00
withLightHscEnv gmcGhcSrcOpts $ \ env -> do
let srcDirs = if null gmcSourceDirs then [ " " ] else gmcSourceDirs
eps <- liftIO $ resolveChEntrypoints cradleRootDir gmcEntrypoints
rms <- resolveModule env srcDirs ` mapM ` eps
return c { gmcEntrypoints = Set . fromList $ catMaybes rms }
2015-11-26 15:31:53 +00:00
-- TODO: remember that the file from `main-is:` is always module `Main` and let
2015-06-19 15:21:17 +00:00
-- ghc do the warning about it. Right now we run that module through
-- resolveModule like any other
2015-06-19 15:15:14 +00:00
resolveChEntrypoints :: FilePath -> ChEntrypoint -> IO [ CompilationUnit ]
2015-03-15 19:48:55 +00:00
resolveChEntrypoints _ ( ChLibEntrypoint em om ) =
return $ map ( Right . chModToMod ) ( em ++ om )
resolveChEntrypoints _ ( ChExeEntrypoint main om ) =
return $ [ Left main ] ++ map ( Right . chModToMod ) om
resolveChEntrypoints srcDir ChSetupEntrypoint = do
shs <- doesFileExist ( srcDir </> " Setup.hs " )
slhs <- doesFileExist ( srcDir </> " Setup.lhs " )
return $ case ( shs , slhs ) of
( True , _ ) -> [ Left " Setup.hs " ]
( _ , True ) -> [ Left " Setup.lhs " ]
( False , False ) -> []
chModToMod :: ChModuleName -> ModuleName
chModToMod ( ChModuleName mn ) = mkModuleName mn
2015-05-31 08:32:46 +00:00
2015-09-01 08:27:12 +00:00
resolveModule :: ( IOish m , Gm m ) =>
2015-06-19 15:15:14 +00:00
HscEnv -> [ FilePath ] -> CompilationUnit -> m ( Maybe ModulePath )
resolveModule env _srcDirs ( Right mn ) =
liftIO $ traverse canonicalizeModulePath =<< findModulePath env mn
resolveModule env srcDirs ( Left fn' ) = do
mfn <- liftIO $ findFile' srcDirs fn'
case mfn of
Nothing -> return Nothing
Just fn'' -> do
fn <- liftIO $ canonicalizePath fn''
2015-06-16 10:49:53 +00:00
emn <- fileModuleName env fn
2015-06-19 15:15:14 +00:00
case emn of
Left errs -> do
gmLog GmWarning ( " resolveModule " ++ show fn ) $
2016-12-13 00:40:05 +00:00
Pretty . empty $+$ ( vcat $ map text errs )
2015-06-19 15:15:14 +00:00
return Nothing -- TODO: should expose these errors otherwise
-- modules with preprocessor/parse errors are
-- going to be missing
Right mmn -> return $ Just $
case mmn of
Nothing -> mkMainModulePath fn
Just mn -> ModulePath mn fn
where
-- needed for ghc 7.4
findFile' dirs file =
getFirst . mconcat <$> mapM ( fmap First . mightExist . ( </> file ) ) dirs
-- fileModuleName fn (dir:dirs)
-- | makeRelative dir fn /= fn
type CompilationUnit = Either FilePath ModuleName
2015-11-21 16:30:18 +00:00
type Components =
[ GmComponent 'GMCRaw ( Set ModulePath ) ]
type ResolvedComponentsMap =
Map ChComponentName ( GmComponent 'GMCResolved ( Set ModulePath ) )
2015-06-19 15:15:14 +00:00
2015-09-01 08:27:12 +00:00
resolveGmComponents :: ( IOish m , Gm m )
2015-11-21 16:30:18 +00:00
=> Maybe ( [ CompilationUnit ] , ResolvedComponentsMap )
2015-03-28 01:30:51 +00:00
-- ^ Updated modules
2015-11-21 16:30:18 +00:00
-> Components -> m ResolvedComponentsMap
resolveGmComponents mcache cs = do
let rcm = fromMaybe Map . empty $ snd <$> mcache
m' <- foldrM' rcm cs $ \ c m -> do
2015-03-03 20:12:43 +00:00
case Map . lookup ( gmcName c ) m of
Nothing -> insertUpdated m c
Just c' -> if same gmcRawEntrypoints c c' && same gmcGhcSrcOpts c c'
then return m
else insertUpdated m c
return m'
2015-05-20 10:05:22 +00:00
2015-03-03 20:12:43 +00:00
where
foldrM' b fa f = foldrM f b fa
insertUpdated m c = do
2015-11-21 16:30:18 +00:00
rc <- resolveGmComponent ( fst <$> mcache ) c
2015-03-03 20:12:43 +00:00
return $ Map . insert ( gmcName rc ) rc m
same :: Eq b
2015-03-28 01:30:51 +00:00
=> ( forall t a . GmComponent t a -> b )
-> GmComponent u c -> GmComponent v d -> Bool
2015-03-03 20:12:43 +00:00
same f a b = ( f a ) == ( f b )
2014-07-18 05:05:20 +00:00
-- | Set the files as targets and load them.
2015-08-18 08:54:55 +00:00
loadTargets :: IOish m => [ GHCOption ] -> [ FilePath ] -> GmlT m ()
loadTargets opts targetStrs = do
2015-09-10 05:48:13 +00:00
targets' <-
2015-08-18 08:54:55 +00:00
withLightHscEnv opts $ \ env ->
liftM ( nubBy ( ( == ) ` on ` targetId ) )
( mapM ( ( ` guessTarget ` Nothing ) >=> mapFile env ) targetStrs )
>>= mapM relativize
2015-09-10 05:48:13 +00:00
let targets = map ( \ t -> t { targetAllowObjCode = False } ) targets'
2015-03-03 20:12:43 +00:00
gmLog GmDebug " loadTargets " $
2015-05-31 08:32:46 +00:00
text " Loading " <+>: fsep ( map ( text . showTargetId ) targets )
2015-03-03 20:12:43 +00:00
setTargets targets
2015-12-15 23:23:51 +00:00
mg <- depanal [] False
let interp = needsHscInterpreted mg
target <- hscTarget <$> getSessionDynFlags
when ( interp && target /= HscInterpreted ) $ do
_ <- setSessionDynFlags . setHscInterpreted =<< getSessionDynFlags
gmLog GmInfo " loadTargets " $ text " Target needs interpeter, switching to LinkInMemory/HscInterpreted. Perfectly normal if anything is using TemplateHaskell, QuasiQuotes or PatternSynonyms. "
target' <- hscTarget <$> getSessionDynFlags
case target' of
HscNothing -> do
void $ load LoadAllTargets
2016-01-26 20:48:33 +00:00
forM_ mg $
2016-03-03 20:01:20 +00:00
handleSourceError ( gmLog GmDebug " loadTargets " . text . show )
2016-01-26 20:48:33 +00:00
. void . ( parseModule >=> typecheckModule >=> desugarModule )
2015-12-15 23:23:51 +00:00
HscInterpreted -> do
void $ load LoadAllTargets
_ -> error ( " loadTargets: unsupported hscTarget " )
2015-09-16 03:09:55 +00:00
gmLog GmDebug " loadTargets " $ text " Loading done "
2014-07-18 05:05:20 +00:00
where
2015-08-18 08:54:55 +00:00
relativize ( Target ( TargetFile filePath phase ) taoc src ) = do
crdl <- cradle
let tid = TargetFile relativeFilePath phase
relativeFilePath = makeRelative ( cradleRootDir crdl ) filePath
return $ Target tid taoc src
relativize tgt = return tgt
2015-05-31 08:32:46 +00:00
showTargetId ( Target ( TargetModule s ) _ _ ) = moduleNameString s
showTargetId ( Target ( TargetFile s _ ) _ _ ) = s
2015-12-15 23:23:51 +00:00
needsHscInterpreted :: ModuleGraph -> Bool
needsHscInterpreted = any $ \ ms ->
2015-03-03 20:12:43 +00:00
let df = ms_hspp_opts ms in
2016-02-04 18:54:55 +00:00
# if __GLASGOW_HASKELL__ >= 800
TemplateHaskell ` xopt ` df
|| QuasiQuotes ` xopt ` df
|| PatternSynonyms ` xopt ` df
# else
2014-09-12 01:48:22 +00:00
Opt_TemplateHaskell ` xopt ` df
|| Opt_QuasiQuotes ` xopt ` df
# if __GLASGOW_HASKELL__ >= 708
|| ( Opt_PatternSynonyms ` xopt ` df )
# endif
2016-02-04 18:54:55 +00:00
# endif
2015-06-07 18:36:49 +00:00
cabalResolvedComponents :: ( IOish m ) =>
GhcModT m ( Map ChComponentName ( GmComponent 'GMCResolved ( Set ModulePath ) ) )
2015-09-24 02:49:49 +00:00
cabalResolvedComponents = do
2015-06-07 18:36:49 +00:00
crdl @ ( Cradle { .. } ) <- cradle
comps <- mapM ( resolveEntrypoint crdl ) =<< getComponents
2015-09-24 02:49:49 +00:00
withAutogen $
cached cradleRootDir ( resolvedComponentsCache cradleDistDir ) comps