1 -----------------------------------------------------------------------------
2 -- $Id: DriverMkDepend.hs,v 1.35 2005/01/14 17:57:46 simonmar Exp $
6 -- (c) Simon Marlow 2000
8 -----------------------------------------------------------------------------
10 module DriverMkDepend (
11 doMkDependHSPhase, beginMkDependHS, endMkDependHS
14 #include "HsVersions.h"
16 import HscTypes ( IfacePackage(..) )
17 import GetImports ( getImportsFromFile )
18 import CmdLineOpts ( DynFlags )
22 import SysTools ( newTempName )
23 import qualified SysTools
24 import Module ( Module, ModLocation(..), moduleUserString)
25 import Finder ( findModule, hiBootExt, hiBootVerExt,
26 mkHomeModLocation, FindResult(..) )
27 import Util ( global, maybePrefixMatch )
30 import DATA_IOREF ( IORef, readIORef, writeIORef )
36 import Maybe ( isJust )
38 #if __GLASGOW_HASKELL__ <= 408
39 import Panic ( catchJust, ioErrors )
42 -------------------------------------------------------------------------------
46 GLOBAL_VAR(v_Dep_makefile, "Makefile", String);
47 GLOBAL_VAR(v_Dep_include_prelude, False, Bool);
48 GLOBAL_VAR(v_Dep_exclude_mods, ["GHC.Prim"], [String]);
49 GLOBAL_VAR(v_Dep_suffixes, [], [String]);
50 GLOBAL_VAR(v_Dep_warnings, True, Bool);
53 GLOBAL_VAR(v_Dep_makefile_hdl, error "dep_makefile_hdl", Maybe Handle);
54 GLOBAL_VAR(v_Dep_tmp_file, error "dep_tmp_file", String);
55 GLOBAL_VAR(v_Dep_tmp_hdl, error "dep_tmp_hdl", Handle);
57 depStartMarker = "# DO NOT DELETE: Beginning of Haskell dependencies"
58 depEndMarker = "# DO NOT DELETE: End of Haskell dependencies"
60 -- for compatibility with the old mkDependHS, we accept options of the form
61 -- -optdep-f -optdep.depend, etc.
63 [ ( "s", SepArg (add v_Dep_suffixes) )
64 , ( "f", SepArg (writeIORef v_Dep_makefile) )
65 , ( "w", NoArg (writeIORef v_Dep_warnings False) )
66 , ( "-include-prelude", NoArg (writeIORef v_Dep_include_prelude True) )
67 , ( "-exclude-module=", Prefix (add v_Dep_exclude_mods) )
68 , ( "x", Prefix (add v_Dep_exclude_mods) )
71 beginMkDependHS :: IO ()
74 -- slurp in the mkdependHS-style options
75 flags <- getStaticOpts v_Opt_dep
76 _ <- processArgs dep_opts flags []
78 -- open a new temp file in which to stuff the dependency info
80 dep_file <- newTempName "dep"
81 writeIORef v_Dep_tmp_file dep_file
82 tmp_hdl <- openFile dep_file WriteMode
83 writeIORef v_Dep_tmp_hdl tmp_hdl
86 makefile <- readIORef v_Dep_makefile
87 exists <- doesFileExist makefile
90 writeIORef v_Dep_makefile_hdl Nothing
94 makefile_hdl <- openFile makefile ReadMode
95 writeIORef v_Dep_makefile_hdl (Just makefile_hdl)
97 -- slurp through until we get the magic start string,
98 -- copying the contents into dep_makefile
100 l <- hGetLine makefile_hdl
101 if (l == depStartMarker)
103 else do hPutStrLn tmp_hdl l; slurp
105 -- slurp through until we get the magic end marker,
106 -- throwing away the contents
108 l <- hGetLine makefile_hdl
109 if (l == depEndMarker)
113 catchJust ioErrors slurp
114 (\e -> if isEOFError e then return () else ioError e)
115 catchJust ioErrors chuck
116 (\e -> if isEOFError e then return () else ioError e)
119 -- write the magic marker into the tmp file
120 hPutStrLn tmp_hdl depStartMarker
125 doMkDependHSPhase dflags basename suff input_fn
126 = do (import_sources, import_normals, mod_name)
127 <- getImportsFromFile dflags input_fn
128 let orig_fn = basename ++ '.':suff
129 location' <- mkHomeModLocation mod_name orig_fn
131 -- take -ohi into account if present
132 ohi <- readIORef v_Output_hi
133 let location | Just fn <- ohi = location'{ ml_hi_file = fn }
134 | otherwise = location'
136 deps_sources <- mapM (findDependency dflags True orig_fn) import_sources
137 deps_normals <- mapM (findDependency dflags False orig_fn) import_normals
138 let deps = deps_sources ++ deps_normals
140 osuf <- readIORef v_Object_suf
141 extra_suffixes <- readIORef v_Dep_suffixes
142 let suffixes = map (++ ('_':osuf)) extra_suffixes
143 obj_file = ml_obj_file location
144 objs = obj_file : map (replaceFilenameSuffix obj_file) suffixes
146 -- Handle for file that accumulates dependencies
147 hdl <- readIORef v_Dep_tmp_hdl
149 -- std dependency of the object(s) on the source file
150 hPutStrLn hdl (unwords (map escapeSpaces objs) ++ " : " ++
151 escapeSpaces (basename ++ '.':suff))
153 let genDep (dep, False {- not an hi file -}) =
154 hPutStrLn hdl (unwords (map escapeSpaces objs) ++ " : " ++
156 genDep (dep, True {- is an hi file -}) = do
157 hisuf <- readIORef v_Hi_suf
159 -- In order to construct hi files with alternate suffixes, we
160 -- now have to find the "basename" of the hi file. This is
161 -- difficult because we can't just split the hi filename
162 -- at the last dot - the hisuf might have dots in it. So we
163 -- check whether the hi filename ends in hisuf, and if it does,
164 -- we strip off hisuf, otherwise we strip everything after the
167 | Just rest <- maybePrefixMatch rev_hisuf rev_dep
170 = remove_suffix '.' dep
172 rev_hisuf = reverse hisuf
173 rev_dep = reverse dep
175 deps = dep : map (\suf -> dep_base ++ suf ++ '_':hisuf)
177 -- length objs should be == length deps
178 sequence_ (zipWith (\o d -> hPutStrLn hdl (escapeSpaces o ++ " : " ++ escapeSpaces d)) objs deps)
180 sequence_ (map genDep [ d | Just d <- deps ])
183 -- add the lines to dep_makefile:
187 -- if the dependency is on something other than a .hi file:
188 -- this.o this.p_o ... : dep
190 -- if the import is {-# SOURCE #-}
191 -- this.o this.p_o ... : dep.hi-boot[-$vers]
194 -- this.o ... : dep.hi
195 -- this.p_o ... : dep.p_hi
198 -- (where .o is $osuf, and the other suffixes come from
199 -- the cmdline -s options).
203 endMkDependHS :: DynFlags -> IO ()
204 endMkDependHS dflags = do
205 makefile <- readIORef v_Dep_makefile
206 makefile_hdl <- readIORef v_Dep_makefile_hdl
207 tmp_file <- readIORef v_Dep_tmp_file
208 tmp_hdl <- readIORef v_Dep_tmp_hdl
210 -- write the magic marker into the tmp file
211 hPutStrLn tmp_hdl depEndMarker
217 -- slurp the rest of the original makefile and copy it into the output
223 catchJust ioErrors slurp
224 (\e -> if isEOFError e then return () else ioError e)
228 hClose tmp_hdl -- make sure it's flushed
230 -- Create a backup of the original makefile
231 when (isJust makefile_hdl)
232 (SysTools.copy dflags ("Backing up " ++ makefile)
233 makefile (makefile++".bak"))
235 -- Copy the new makefile in place
236 SysTools.copy dflags "Installing new makefile" tmp_file makefile
239 findDependency :: DynFlags -> Bool -> FilePath -> Module -> IO (Maybe (String, Bool))
240 findDependency dflags is_source src imp = do
241 excl_mods <- readIORef v_Dep_exclude_mods
242 include_prelude <- readIORef v_Dep_include_prelude
243 let imp_mod = moduleUserString imp
244 if imp_mod `elem` excl_mods
247 r <- findModule dflags imp True{-explicit-}
250 -- not in this package: we don't need a dependency
251 | ExternalPackage _ <- pkg, not include_prelude
254 -- normal import: just depend on the .hi file
256 -> return (Just (ml_hi_file loc, not is_source))
258 -- if it's a source import, we want to generate a dependency
259 -- on the .hi-boot file, not the .hi file
261 -> let hi_file = ml_hi_file loc
262 boot_hi_file = replaceFilenameSuffix hi_file hiBootExt
263 boot_ver_hi_file = replaceFilenameSuffix hi_file hiBootVerExt
265 b <- doesFileExist boot_ver_hi_file
267 then return (Just (boot_ver_hi_file, not is_source))
269 b <- doesFileExist boot_hi_file
271 then return (Just (boot_hi_file, not is_source))
272 else return (Just (hi_file, not is_source))
274 _ -> throwDyn (ProgramError
275 (src ++ ": " ++ "can't locate import `" ++ imp_mod ++ "'" ++
276 if is_source then " (SOURCE import)" else ""))