(F)SLIT -> (f)sLit in DriverMkDepend
[ghc-hetmet.git] / compiler / main / DriverMkDepend.hs
index 56f57f0..95587cd 100644 (file)
@@ -1,3 +1,10 @@
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
 -----------------------------------------------------------------------------
 --
 -- Makefile Dependency Generation
@@ -14,34 +21,33 @@ module DriverMkDepend (
 
 import qualified GHC
 import GHC             ( Session, ModSummary(..) )
-import DynFlags                ( DynFlags( verbosity, opt_dep ), getOpts )
-import Util            ( escapeSpaces, splitFilename, joinFileExt )
+import DynFlags
+import Util
 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
+import FastString
 
-#if __GLASGOW_HASKELL__ <= 408
-import Panic           ( catchJust, ioErrors )
-#endif
-import ErrUtils         ( debugTraceMsg, printErrorsAndWarnings )
-
-import DATA_IOREF      ( IORef, readIORef, writeIORef )
-import EXCEPTION
+import ErrUtils         ( debugTraceMsg, putMsg )
 
-import System          ( ExitCode(..), exitWith )
-import Directory
-import IO
-import Monad            ( when )
-import Maybe            ( isJust )
+import Data.IORef      ( IORef, readIORef, writeIORef )
+import Control.Exception
+import System.Exit     ( ExitCode(..), exitWith )
+import System.Directory
+import System.FilePath
+import System.IO
+import SYSTEM_IO_ERROR  ( isEOFError )
+import Control.Monad    ( when )
+import Data.Maybe       ( isJust )
 
 -----------------------------------------------------------------
 --
@@ -75,6 +81,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 }}
 
@@ -240,10 +249,10 @@ findDependency hsc_env src imp is_boot include_pkg_deps
 -----------------------------
 writeDependency :: Handle -> [FilePath] -> FilePath -> IO ()
 -- (writeDependency h [t1,t2] dep) writes to handle h the dependency
---     t1 t2 : dep
+--      t1 t2 : dep
 writeDependency hdl targets dep
-  = hPutStrLn hdl (unwords (map escapeSpaces targets) ++ " : "
-                  ++ escapeSpaces dep)
+  = hPutStrLn hdl (unwords (map forOutput targets) ++ " : " ++ forOutput dep)
+    where forOutput = escapeSpaces . reslash Forwards . normalise
 
 -----------------------------
 insertSuffixes 
@@ -265,9 +274,11 @@ insertSuffixes
        -- Lots of other things will break first!
 
 insertSuffixes file_name extras
-  = file_name : [ basename `joinFileExt` (extra ++ "_" ++ suffix) | extra <- extras ]
+  = file_name : [ basename <.> (extra ++ "_" ++ suffix) | extra <- extras ]
   where
-    (basename, suffix) = splitFilename file_name
+    (basename, suffix) = case splitExtension file_name of
+                         -- Drop the "." from the extension
+                         (b, s) -> (b, drop 1 s)
 
 
 -----------------------------------------------------------------
@@ -313,6 +324,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
 --
@@ -334,7 +406,11 @@ dep_opts =
    [ (  "s",                   SepArg (consIORef v_Dep_suffixes) )
    , (  "f",                   SepArg (writeIORef v_Dep_makefile) )
    , (  "w",                   NoArg (writeIORef v_Dep_warnings False) )
+
    , (  "-include-prelude",    NoArg (writeIORef v_Dep_include_pkg_deps True) )
+       -- -include-prelude is the old name for -include-pkg-deps, kept around
+       -- for backward compatibility, but undocumented
+
    , (  "-include-pkg-deps",   NoArg (writeIORef v_Dep_include_pkg_deps True) )
    , (  "-exclude-module=",     Prefix (consIORef v_Dep_exclude_mods . mkModuleName) )
    , (  "x",                    Prefix (consIORef v_Dep_exclude_mods . mkModuleName) )