summaryrefslogtreecommitdiff
path: root/compiler/main/DriverMkDepend.hs
diff options
context:
space:
mode:
authorsimonpj@microsoft.com <unknown>2007-03-22 12:28:59 +0000
committersimonpj@microsoft.com <unknown>2007-03-22 12:28:59 +0000
commita896a832ab7306da8c638df7f44619b3548bd518 (patch)
tree832bb0cc8fc7d09b3036846899bb29881fa7239d /compiler/main/DriverMkDepend.hs
parent985916e235d53246d5a00b91349803f563377904 (diff)
downloadhaskell-a896a832ab7306da8c638df7f44619b3548bd518.tar.gz
Add -ddump-mod-cycles to -M behaviour
This patch adds a flag -ddump-mod-cycles to the "ghc -M" dependency analyser. The effect of ghc -M -ddump-mod-cycles is to dump a list of cycles foud in the module graph. The display is trimmed so that only dependencies within the cycle are shown; and the list of modules in a cycle is itself sorted into dependency order, so that it is easy to track the chain of dependencies. Open question: should the flag be "-ddump-mod-cycles" or "-optdep-dump-mod-cycles"? For this reason I have not yet added to the documentation.
Diffstat (limited to 'compiler/main/DriverMkDepend.hs')
-rw-r--r--compiler/main/DriverMkDepend.hs74
1 files changed, 69 insertions, 5 deletions
diff --git a/compiler/main/DriverMkDepend.hs b/compiler/main/DriverMkDepend.hs
index 74c8037c56..74ee4dcd1f 100644
--- a/compiler/main/DriverMkDepend.hs
+++ b/compiler/main/DriverMkDepend.hs
@@ -14,25 +14,25 @@ module DriverMkDepend (
import qualified GHC
import GHC ( Session, ModSummary(..) )
-import DynFlags ( DynFlags( verbosity, opt_dep ), getOpts )
+import DynFlags
import Util ( escapeSpaces, splitFilename, joinFileExt )
import HscTypes ( HscEnv, IsBootInterface, msObjFilePath, msHsFilePath )
import SysTools ( newTempName )
import qualified SysTools
-import Module ( ModuleName, ModLocation(..), mkModuleName,
- addBootSuffix_maybe )
+import Module
import Digraph ( SCC(..) )
import Finder ( findImportedModule, FindResult(..) )
import Util ( global, consIORef )
import Outputable
import Panic
-import SrcLoc ( unLoc )
+import SrcLoc
+import Data.List
import CmdLineParser
#if __GLASGOW_HASKELL__ <= 408
import Panic ( catchJust, ioErrors )
#endif
-import ErrUtils ( debugTraceMsg, printErrorsAndWarnings )
+import ErrUtils ( debugTraceMsg, putMsg )
import Data.IORef ( IORef, readIORef, writeIORef )
import Control.Exception
@@ -75,6 +75,9 @@ doMkDependHS session srcs
-- and complaining about cycles
; mapM (processDeps session excl_mods (mkd_tmp_hdl files)) sorted
+ -- If -ddump-mod-cycles, show cycles in the module graph
+ ; dumpModCycles dflags mod_summaries
+
-- Tidy up
; endMkDependHS dflags files }}
@@ -313,6 +316,67 @@ endMkDependHS dflags
-----------------------------------------------------------------
+-- Module cycles
+-----------------------------------------------------------------
+
+dumpModCycles :: DynFlags -> [ModSummary] -> IO ()
+dumpModCycles dflags mod_summaries
+ | not (dopt Opt_D_dump_mod_cycles dflags)
+ = return ()
+
+ | null cycles
+ = putMsg dflags (ptext SLIT("No module cycles"))
+
+ | otherwise
+ = putMsg dflags (hang (ptext SLIT("Module cycles found:")) 2 pp_cycles)
+ where
+
+ cycles :: [[ModSummary]]
+ cycles = [ c | CyclicSCC c <- GHC.topSortModuleGraph True mod_summaries Nothing ]
+
+ pp_cycles = vcat [ (ptext SLIT("---------- Cycle") <+> int n <+> ptext SLIT("----------"))
+ $$ pprCycle c $$ text ""
+ | (n,c) <- [1..] `zip` cycles ]
+
+pprCycle :: [ModSummary] -> SDoc
+-- Print a cycle, but show only the imports within the cycle
+pprCycle summaries = pp_group (CyclicSCC summaries)
+ where
+ cycle_mods :: [ModuleName] -- The modules in this cycle
+ cycle_mods = map (moduleName . ms_mod) summaries
+
+ pp_group (AcyclicSCC ms) = pp_ms ms
+ pp_group (CyclicSCC mss)
+ = ASSERT( not (null boot_only) )
+ -- The boot-only list must be non-empty, else there would
+ -- be an infinite chain of non-boot imoprts, and we've
+ -- already checked for that in processModDeps
+ pp_ms loop_breaker $$ vcat (map pp_group groups)
+ where
+ (boot_only, others) = partition is_boot_only mss
+ is_boot_only ms = not (any in_group (ms_imps ms))
+ in_group (L _ m) = m `elem` group_mods
+ group_mods = map (moduleName . ms_mod) mss
+
+ loop_breaker = head boot_only
+ all_others = tail boot_only ++ others
+ groups = GHC.topSortModuleGraph True all_others Nothing
+
+ pp_ms summary = text mod_str <> text (take (20 - length mod_str) (repeat ' '))
+ <+> (pp_imps empty (ms_imps summary) $$
+ pp_imps (ptext SLIT("{-# SOURCE #-}")) (ms_srcimps summary))
+ where
+ mod_str = moduleNameString (moduleName (ms_mod summary))
+
+ pp_imps :: SDoc -> [Located ModuleName] -> SDoc
+ pp_imps what [] = empty
+ pp_imps what lms
+ = case [m | L _ m <- lms, m `elem` cycle_mods] of
+ [] -> empty
+ ms -> what <+> ptext SLIT("imports") <+>
+ pprWithCommas ppr ms
+
+-----------------------------------------------------------------
--
-- Flags
--