2 % (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
4 \section[Module]{The @Module@ module.}
6 Representing modules and their flavours.
11 Module -- abstract, instance of Eq, Ord, Outputable
14 , moduleNameString -- :: ModuleName -> EncodedString
15 , moduleNameUserString -- :: ModuleName -> UserString
17 , moduleString -- :: Module -> EncodedString
18 , moduleUserString -- :: Module -> UserString
19 , moduleName -- :: Module -> ModuleName
21 , mkVanillaModule -- :: ModuleName -> Module
22 , mkThisModule -- :: ModuleName -> Module
23 , mkPrelModule -- :: UserString -> Module
24 , mkModule -- :: ModuleName -> PackageName -> Module
26 , isLocalModule -- :: Module -> Bool
30 , mkSrcModuleFS -- :: UserFS -> ModuleName
31 , mkSysModuleFS -- :: EncodedFS -> ModuleName
33 , pprModule, pprModuleName
37 -- Where to find a .hi file
38 , WhereFrom(..), SearchPath, mkSearchPath
39 , ModuleHiMap, mkModuleHiMaps
43 #include "HsVersions.h"
47 import CmdLineOpts ( opt_Static, opt_InPackage, opt_WarnHiShadows, opt_HiMapSep )
48 import Constants ( interfaceFileFormatVersion )
49 import Maybes ( seqMaybe )
50 import Maybe ( fromMaybe )
51 import Directory ( doesFileExist )
52 import DirUtils ( getDirectoryContents )
53 import List ( intersperse )
54 import Monad ( foldM )
55 import IO ( hPutStrLn, stderr, isDoesNotExistError )
56 import FastString ( FastString )
60 %************************************************************************
62 \subsection{Interface file flavour}
64 %************************************************************************
66 A further twist to the tale is the support for dynamically linked libraries under
67 Win32. Here, dealing with the use of global variables that's residing in a DLL
68 requires special handling at the point of use (there's an extra level of indirection,
69 i.e., (**v) to get at v's value, rather than just (*v) .) When slurping in an
70 interface file we then record whether it's coming from a .hi corresponding to a
71 module that's packaged up in a DLL or not, so that we later can emit the
74 The logic for how an interface file is marked as corresponding to a module that's
75 hiding in a DLL is explained elsewhere (ToDo: give renamer href here.)
78 data PackageInfo = ThisPackage -- A module from the same package
79 -- as the one being compiled
80 | AnotherPackage PackageName -- A module from a different package
82 type PackageName = FastString -- No encoding at all
84 preludePackage :: PackageName
85 preludePackage = SLIT("std")
87 instance Show PackageInfo where -- Just used in debug prints of lex tokens
89 showsPrec n ThisPackage s = "<THIS>" ++ s
90 showsPrec n (AnotherPackage p) s = (_UNPK_ p) ++ s
94 %************************************************************************
96 \subsection{System/user module}
98 %************************************************************************
100 We also track whether an imported module is from a 'system-ish' place. In this case
101 we don't record the fact that this module depends on it, nor usages of things
104 Apr 00: We want to record dependencies on all modules other than
105 prelude modules else STG Hugs gets confused because it uses this
106 info to know what modules to link. (Compiled GHC uses command line
107 options to specify this.)
110 data ModFlavour = PrelMod -- A Prelude module
111 | UserMod -- Not library-ish
115 %************************************************************************
117 \subsection{Where from}
119 %************************************************************************
121 The @WhereFrom@ type controls where the renamer looks for an interface file
124 data WhereFrom = ImportByUser -- Ordinary user import: look for M.hi
125 | ImportByUserSource -- User {- SOURCE -}: look for M.hi-boot
126 | ImportBySystem -- Non user import. Look for M.hi if M is in
127 -- the module this module depends on, or is a system-ish module;
128 -- M.hi-boot otherwise
130 instance Outputable WhereFrom where
131 ppr ImportByUser = empty
132 ppr ImportByUserSource = ptext SLIT("{- SOURCE -}")
133 ppr ImportBySystem = ptext SLIT("{- SYSTEM IMPORT -}")
137 %************************************************************************
139 \subsection{The name of a module}
141 %************************************************************************
144 type ModuleName = EncodedFS
145 -- Haskell module names can include the quote character ',
146 -- so the module names have the z-encoding applied to them
148 pprModuleName :: ModuleName -> SDoc
149 pprModuleName nm = pprEncodedFS nm
151 moduleNameString :: ModuleName -> EncodedString
152 moduleNameString mod = _UNPK_ mod
154 moduleNameUserString :: ModuleName -> UserString
155 moduleNameUserString mod = decode (_UNPK_ mod)
157 mkSrcModule :: UserString -> ModuleName
158 mkSrcModule s = _PK_ (encode s)
160 mkSrcModuleFS :: UserFS -> ModuleName
161 mkSrcModuleFS s = encodeFS s
163 mkSysModuleFS :: EncodedFS -> ModuleName
168 data Module = Module ModuleName PackageInfo
172 instance Outputable Module where
175 instance Eq Module where
176 (Module m1 _) == (Module m2 _) = m1 == m2
178 instance Ord Module where
179 (Module m1 _) `compare` (Module m2 _) = m1 `compare` m2
184 pprModule :: Module -> SDoc
185 pprModule (Module mod p) = getPprStyle $ \ sty ->
186 if userStyle sty then
187 text (moduleNameUserString mod)
188 else if debugStyle sty then
189 -- Print the package too
190 text (show p) <> dot <> pprModuleName mod
197 mkModule :: ModuleName -- Name of the module
200 mkModule mod_nm pack_name
201 = Module mod_nm pack_info
203 pack_info | pack_name == opt_InPackage = ThisPackage
204 | otherwise = AnotherPackage pack_name
206 mkVanillaModule :: ModuleName -> Module
207 mkVanillaModule name = Module name ThisPackage
208 -- Used temporarily when we first come across Foo.x in an interface
209 -- file, but before we've opened Foo.hi.
210 -- (Until we've opened Foo.hi we don't know what the PackageInfo is.)
212 mkThisModule :: ModuleName -> Module -- The module being compiled
213 mkThisModule name = Module name ThisPackage
215 mkPrelModule :: ModuleName -> Module
216 mkPrelModule name = mkModule name preludePackage
218 moduleString :: Module -> EncodedString
219 moduleString (Module mod _) = _UNPK_ mod
221 moduleName :: Module -> ModuleName
222 moduleName (Module mod _) = mod
224 moduleUserString :: Module -> UserString
225 moduleUserString (Module mod _) = moduleNameUserString mod
229 isLocalModule :: Module -> Bool
230 isLocalModule (Module _ ThisPackage) = True
231 isLocalModule _ = False
235 %************************************************************************
237 \subsection{Finding modules in the file system
239 %************************************************************************
242 type ModuleHiMap = FiniteMap ModuleName String
243 -- Mapping from module name to
244 -- * the file path of its corresponding interface file,
248 (We allege that) it is quicker to build up a mapping from module names
249 to the paths to their corresponding interface files once, than to search
250 along the import part every time we slurp in a new module (which we
254 type SearchPath = [(String,String)] -- List of (directory,suffix) pairs to search
255 -- for interface files.
257 mkModuleHiMaps :: SearchPath -> IO (SearchPath, ModuleHiMap, ModuleHiMap)
258 mkModuleHiMaps dirs = do (hi,hi_boot) <- foldM (getAllFilesMatching dirs) (env,env) dirs
259 return (dirs, hi, hi_boot)
263 getAllFilesMatching :: SearchPath
264 -> (ModuleHiMap, ModuleHiMap)
265 -> (FilePath, String)
266 -> IO (ModuleHiMap, ModuleHiMap)
267 getAllFilesMatching dirs hims (dir_path, suffix) = ( do
268 -- fpaths entries do not have dir_path prepended
269 fpaths <- getDirectoryContents dir_path
270 return (foldl addModules hims fpaths))
275 ("Import path element `" ++ dir_path ++
276 if (isDoesNotExistError err) then
277 "' does not exist, ignoring."
279 "' couldn't read, ignoring.")
284 xiffus = reverse dotted_suffix
285 dotted_suffix = case suffix of
290 hi_boot_version_xiffus =
291 reverse (show interfaceFileFormatVersion) ++ '-':hi_boot_xiffus
292 hi_boot_xiffus = "toob-ih." -- .hi-boot reversed!
294 addModules his@(hi_env, hib_env) filename = fromMaybe his $
295 FMAP add_hi (go xiffus rev_fname) `seqMaybe`
297 FMAP add_vhib (go hi_boot_version_xiffus rev_fname) `seqMaybe`
298 -- If there's a Foo.hi-boot-N file then override any Foo.hi-boot
300 FMAP add_hib (go hi_boot_xiffus rev_fname)
302 rev_fname = reverse filename
303 path = dir_path ++ '/':filename
305 -- In these functions file_nm is the base of the filename,
306 -- with the path and suffix both stripped off. The filename
307 -- is the *unencoded* module name (else 'make' gets confused).
308 -- But the domain of the HiMaps is ModuleName which is encoded.
309 add_hi file_nm = (add_to_map addNewOne hi_env file_nm, hib_env)
310 add_vhib file_nm = (hi_env, add_to_map overrideNew hib_env file_nm)
311 add_hib file_nm = (hi_env, add_to_map addNewOne hib_env file_nm)
313 add_to_map combiner env file_nm
314 = addToFM_C combiner env mod_nm path
316 mod_nm = mkSrcModuleFS file_nm
318 -- go prefix (prefix ++ stuff) == Just (reverse stuff)
319 go [] xs = Just (_PK_ (reverse xs))
321 go (x:xs) (y:ys) | x == y = go xs ys
322 | otherwise = Nothing
324 addNewOne | opt_WarnHiShadows = conflict
325 | otherwise = stickWithOld
327 stickWithOld old new = old
328 overrideNew old new = new
330 conflict old_path new_path
331 | old_path /= new_path =
332 pprTrace "Warning: " (text "Identically named interface files present on the import path, " $$
333 text (show old_path) <+> text "shadows" $$
334 text (show new_path) $$
335 text "on the import path: " <+>
336 text (concat (intersperse ":" (map fst dirs))))
338 | otherwise = old_path -- don't warn about innocous shadowings.
342 %*********************************************************
344 \subsection{Making a search path}
346 %*********************************************************
348 @mkSearchPath@ takes a string consisting of a colon-separated list
349 of directories and corresponding suffixes, and turns it into a list
350 of (directory, suffix) pairs. For example:
353 mkSearchPath "foo%.hi:.%.p_hi:baz%.mc_hi"
354 = [("foo",".hi"),( ".", ".p_hi"), ("baz",".mc_hi")]
358 mkSearchPath :: Maybe String -> SearchPath
359 mkSearchPath Nothing = [(".",".hi")] -- ToDo: default should be to look in
360 -- the directory the module we're compiling
362 mkSearchPath (Just s) = go s
366 case span (/= '%') s of
368 case span (/= opt_HiMapSep) rs of
369 (hisuf,_:rest) -> (dir,hisuf):go rest
370 (hisuf,[]) -> [(dir,hisuf)]