2 % (c) The University of Glasgow, 2000
4 \section[Finder]{Module Finder}
8 flushFinderCache, -- :: IO ()
10 findModule, -- :: ModuleName -> Bool -> IO FindResult
11 findPackageModule, -- :: ModuleName -> Bool -> IO FindResult
12 mkHomeModLocation, -- :: ModuleName -> FilePath -> IO ModLocation
13 mkHomeModLocation2, -- :: ModuleName -> FilePath -> String -> IO ModLocation
14 addHomeModuleToFinder, -- :: HscEnv -> Module -> ModLocation -> IO ()
15 uncacheModule, -- :: HscEnv -> Module -> IO ()
17 findObjectLinkableMaybe,
20 cantFindError, -- :: DynFlags -> Module -> FindResult -> SDoc
23 #include "HsVersions.h"
26 import UniqFM ( filterUFM, delFromUFM )
31 import DynFlags ( DynFlags(..), isOneShot, GhcMode(..) )
34 import DATA_IOREF ( IORef, writeIORef, readIORef )
37 import System.Directory
40 import Data.Maybe ( isNothing )
41 import Time ( ClockTime )
44 type FileExt = String -- Filename extension
45 type BaseName = String -- Basename of file
47 -- -----------------------------------------------------------------------------
50 -- The Finder provides a thin filesystem abstraction to the rest of
51 -- the compiler. For a given module, it can tell you where the
52 -- source, interface, and object files for that module live.
54 -- It does *not* know which particular package a module lives in. Use
55 -- Packages.lookupModuleInAllPackages for that.
57 -- -----------------------------------------------------------------------------
60 -- remove all the home modules from the cache; package modules are
61 -- assumed to not move around during a session.
62 flushFinderCache :: IORef FinderCache -> IO ()
63 flushFinderCache finder_cache = do
64 fm <- readIORef finder_cache
65 writeIORef finder_cache $! filterUFM (\(loc,m) -> isNothing m) fm
67 addToFinderCache :: IORef FinderCache -> Module -> FinderCacheEntry -> IO ()
68 addToFinderCache finder_cache mod_name entry = do
69 fm <- readIORef finder_cache
70 writeIORef finder_cache $! extendModuleEnv fm mod_name entry
72 removeFromFinderCache :: IORef FinderCache -> Module -> IO ()
73 removeFromFinderCache finder_cache mod_name = do
74 fm <- readIORef finder_cache
75 writeIORef finder_cache $! delFromUFM fm mod_name
77 lookupFinderCache :: IORef FinderCache -> Module -> IO (Maybe FinderCacheEntry)
78 lookupFinderCache finder_cache mod_name = do
79 fm <- readIORef finder_cache
80 return $! lookupModuleEnv fm mod_name
82 -- -----------------------------------------------------------------------------
83 -- The two external entry points
85 -- This is the main interface to the finder, which maps ModuleNames to
86 -- Modules and ModLocations.
88 -- The Module contains one crucial bit of information about a module:
89 -- whether it lives in the current ("home") package or not (see Module
92 -- The ModLocation contains the names of all the files associated with
93 -- that module: its source file, .hi file, object file, etc.
96 = Found ModLocation PackageIdH
97 -- the module was found
98 | FoundMultiple [PackageId]
99 -- *error*: both in multiple packages
100 | PackageHidden PackageId
101 -- for an explicit source import: the package containing the module is
103 | ModuleHidden PackageId
104 -- for an explicit source import: the package containing the module is
105 -- exposed, but the module itself is hidden.
106 | NotFound [FilePath]
107 -- the module was not found, the specified places were searched.
109 findModule :: HscEnv -> Module -> Bool -> IO FindResult
110 findModule = findModule' True
112 findPackageModule :: HscEnv -> Module -> Bool -> IO FindResult
113 findPackageModule = findModule' False
117 = Ok FinderCacheEntry
118 | CantFindAmongst [FilePath]
119 | MultiplePackages [PackageId]
121 findModule' :: Bool -> HscEnv -> Module -> Bool -> IO FindResult
122 findModule' home_allowed hsc_env name explicit
123 = do -- First try the cache
124 mb_entry <- lookupFinderCache cache name
126 Just old_entry -> return $! found old_entry
127 Nothing -> not_cached
130 cache = hsc_FC hsc_env
131 dflags = hsc_dflags hsc_env
133 -- We've found the module, so the remaining question is
134 -- whether it's visible or not
135 found :: FinderCacheEntry -> FindResult
137 | home_allowed = Found loc HomePackage
138 | otherwise = NotFound []
139 found (loc, Just (pkg, exposed_mod))
140 | explicit && not exposed_mod = ModuleHidden pkg_name
141 | explicit && not (exposed pkg) = PackageHidden pkg_name
143 Found loc (ExtPackage (mkPackageId (package pkg)))
145 pkg_name = packageConfigId pkg
148 addToFinderCache cache name entry
149 return $! found entry
152 | not home_allowed = do
153 j <- findPackageModule' dflags name
155 Ok entry -> found_new entry
156 MultiplePackages pkgs -> return (FoundMultiple pkgs)
157 CantFindAmongst paths -> return (NotFound paths)
160 j <- findHomeModule' dflags name
162 Ok entry -> found_new entry
163 MultiplePackages pkgs -> return (FoundMultiple pkgs)
164 CantFindAmongst home_files -> do
165 r <- findPackageModule' dflags name
167 CantFindAmongst pkg_files ->
168 return (NotFound (home_files ++ pkg_files))
169 MultiplePackages pkgs ->
170 return (FoundMultiple pkgs)
174 addHomeModuleToFinder :: HscEnv -> Module -> ModLocation -> IO ()
175 addHomeModuleToFinder hsc_env mod loc
176 = addToFinderCache (hsc_FC hsc_env) mod (loc, Nothing)
178 uncacheModule :: HscEnv -> Module -> IO ()
179 uncacheModule hsc_env mod = removeFromFinderCache (hsc_FC hsc_env) mod
181 -- -----------------------------------------------------------------------------
182 -- The internal workers
184 findHomeModule' :: DynFlags -> Module -> IO LocalFindResult
185 findHomeModule' dflags mod = do
186 let home_path = importPaths dflags
191 [ ("hs", mkHomeModLocationSearched dflags mod "hs")
192 , ("lhs", mkHomeModLocationSearched dflags mod "lhs")
195 hi_exts = [ (hisuf, mkHiOnlyModLocation dflags hisuf)
196 , (addBootSuffix hisuf, mkHiOnlyModLocation dflags hisuf)
199 -- In compilation manager modes, we look for source files in the home
200 -- package because we can compile these automatically. In one-shot
201 -- compilation mode we look for .hi and .hi-boot files only.
202 exts | isOneShot (ghcMode dflags) = hi_exts
203 | otherwise = source_exts
205 searchPathExts home_path mod exts
207 findPackageModule' :: DynFlags -> Module -> IO LocalFindResult
208 findPackageModule' dflags mod
209 = case lookupModuleInAllPackages dflags mod of
210 [] -> return (CantFindAmongst [])
211 [pkg_info] -> findPackageIface dflags mod pkg_info
212 many -> return (MultiplePackages (map (mkPackageId.package.fst) many))
214 findPackageIface :: DynFlags -> Module -> (PackageConfig,Bool) -> IO LocalFindResult
215 findPackageIface dflags mod pkg_info@(pkg_conf, _) = do
217 tag = buildTag dflags
219 -- hi-suffix for packages depends on the build tag.
220 package_hisuf | null tag = "hi"
221 | otherwise = tag ++ "_hi"
224 mkPackageModLocation dflags pkg_info package_hisuf) ]
227 [ ("hs", mkPackageModLocation dflags pkg_info package_hisuf)
228 , ("lhs", mkPackageModLocation dflags pkg_info package_hisuf)
231 -- mkdependHS needs to look for source files in packages too, so
232 -- that we can make dependencies between package before they have
235 | MkDepend <- ghcMode dflags = hi_exts ++ source_exts
236 | otherwise = hi_exts
237 -- we never look for a .hi-boot file in an external package;
238 -- .hi-boot files only make sense for the home package.
240 searchPathExts (importDirs pkg_conf) mod exts
242 -- -----------------------------------------------------------------------------
243 -- General path searching
246 :: [FilePath] -- paths to search
247 -> Module -- module name
250 FilePath -> BaseName -> IO FinderCacheEntry -- action
253 -> IO LocalFindResult
255 searchPathExts paths mod exts
256 = do result <- search to_search
258 hPutStrLn stderr (showSDoc $
259 vcat [text "Search" <+> ppr mod <+> sep (map (text. fst) exts)
260 , nest 2 (vcat (map text paths))
262 Succeeded (loc, p) -> text "Found" <+> ppr loc
263 Failed fs -> text "not found"])
268 basename = dots_to_slashes (moduleUserString mod)
270 to_search :: [(FilePath, IO FinderCacheEntry)]
271 to_search = [ (file, fn path basename)
274 let base | path == "." = basename
275 | otherwise = path `joinFileName` basename
276 file = base `joinFileExt` ext
279 search [] = return (CantFindAmongst (map fst to_search))
280 search ((file, mk_result) : rest) = do
281 b <- doesFileExist file
283 then do { res <- mk_result; return (Ok res) }
286 mkHomeModLocationSearched :: DynFlags -> Module -> FileExt
287 -> FilePath -> BaseName -> IO FinderCacheEntry
288 mkHomeModLocationSearched dflags mod suff path basename = do
289 loc <- mkHomeModLocation2 dflags mod (path `joinFileName` basename) suff
290 return (loc, Nothing)
292 mkHiOnlyModLocation :: DynFlags -> FileExt -> FilePath -> BaseName
293 -> IO FinderCacheEntry
294 mkHiOnlyModLocation dflags hisuf path basename = do
295 loc <- hiOnlyModLocation dflags path basename hisuf
296 return (loc, Nothing)
298 mkPackageModLocation :: DynFlags -> (PackageConfig, Bool) -> FileExt
299 -> FilePath -> BaseName -> IO FinderCacheEntry
300 mkPackageModLocation dflags pkg_info hisuf path basename = do
301 loc <- hiOnlyModLocation dflags path basename hisuf
302 return (loc, Just pkg_info)
304 -- -----------------------------------------------------------------------------
305 -- Constructing a home module location
307 -- This is where we construct the ModLocation for a module in the home
308 -- package, for which we have a source file. It is called from three
311 -- (a) Here in the finder, when we are searching for a module to import,
312 -- using the search path (-i option).
314 -- (b) The compilation manager, when constructing the ModLocation for
315 -- a "root" module (a source file named explicitly on the command line
316 -- or in a :load command in GHCi).
318 -- (c) The driver in one-shot mode, when we need to construct a
319 -- ModLocation for a source file named on the command-line.
324 -- The name of the module
327 -- (a): The search path component where the source file was found.
331 -- (a): dots_to_slashes (moduleNameUserString mod)
332 -- (b) and (c): The filename of the source file, minus its extension
335 -- The filename extension of the source file (usually "hs" or "lhs").
337 mkHomeModLocation :: DynFlags -> Module -> FilePath -> IO ModLocation
338 mkHomeModLocation dflags mod src_filename = do
339 let (basename,extension) = splitFilename src_filename
340 mkHomeModLocation2 dflags mod basename extension
342 mkHomeModLocation2 :: DynFlags
344 -> FilePath -- Of source module, without suffix
347 mkHomeModLocation2 dflags mod src_basename ext = do
348 let mod_basename = dots_to_slashes (moduleUserString mod)
350 obj_fn <- mkObjPath dflags src_basename mod_basename
351 hi_fn <- mkHiPath dflags src_basename mod_basename
353 return (ModLocation{ ml_hs_file = Just (src_basename `joinFileExt` ext),
355 ml_obj_file = obj_fn })
357 hiOnlyModLocation :: DynFlags -> FilePath -> String -> Suffix -> IO ModLocation
358 hiOnlyModLocation dflags path basename hisuf
359 = do let full_basename = path `joinFileName` basename
360 obj_fn <- mkObjPath dflags full_basename basename
361 return ModLocation{ ml_hs_file = Nothing,
362 ml_hi_file = full_basename `joinFileExt` hisuf,
363 -- Remove the .hi-boot suffix from
364 -- hi_file, if it had one. We always
365 -- want the name of the real .hi file
366 -- in the ml_hi_file field.
370 -- | Constructs the filename of a .o file for a given source file.
371 -- Does /not/ check whether the .o file exists
374 -> FilePath -- the filename of the source file, minus the extension
375 -> String -- the module name with dots replaced by slashes
377 mkObjPath dflags basename mod_basename
379 odir = outputDir dflags
380 osuf = objectSuf dflags
382 obj_basename | Just dir <- odir = dir `joinFileName` mod_basename
383 | otherwise = basename
385 return (obj_basename `joinFileExt` osuf)
387 -- | Constructs the filename of a .hi file for a given source file.
388 -- Does /not/ check whether the .hi file exists
391 -> FilePath -- the filename of the source file, minus the extension
392 -> String -- the module name with dots replaced by slashes
394 mkHiPath dflags basename mod_basename
399 hi_basename | Just dir <- hidir = dir `joinFileName` mod_basename
400 | otherwise = basename
402 return (hi_basename `joinFileExt` hisuf)
405 -- -----------------------------------------------------------------------------
406 -- findLinkable isn't related to the other stuff in here,
407 -- but there's no other obvious place for it
409 findObjectLinkableMaybe :: Module -> ModLocation -> IO (Maybe Linkable)
410 findObjectLinkableMaybe mod locn
411 = do let obj_fn = ml_obj_file locn
412 maybe_obj_time <- modificationTimeIfExists obj_fn
413 case maybe_obj_time of
414 Nothing -> return Nothing
415 Just obj_time -> liftM Just (findObjectLinkable mod obj_fn obj_time)
417 -- Make an object linkable when we know the object file exists, and we know
418 -- its modification time.
419 findObjectLinkable :: Module -> FilePath -> ClockTime -> IO Linkable
420 findObjectLinkable mod obj_fn obj_time = do
421 let stub_fn = case splitFilename3 obj_fn of
422 (dir, base, ext) -> dir ++ "/" ++ base ++ "_stub.o"
423 stub_exist <- doesFileExist stub_fn
425 then return (LM obj_time mod [DotO obj_fn, DotO stub_fn])
426 else return (LM obj_time mod [DotO obj_fn])
428 -- -----------------------------------------------------------------------------
431 dots_to_slashes = map (\c -> if c == '.' then '/' else c)
434 -- -----------------------------------------------------------------------------
437 cantFindError :: DynFlags -> Module -> FindResult -> SDoc
438 cantFindError dflags mod_name (FoundMultiple pkgs)
439 = hang (ptext SLIT("Cannot import") <+> quotes (ppr mod_name) <> colon) 2 (
440 sep [ptext SLIT("it was found in multiple packages:"),
441 hsep (map (text.packageIdString) pkgs)]
443 cantFindError dflags mod_name find_result
444 = hang (ptext SLIT("Could not find module") <+> quotes (ppr mod_name) <> colon)
448 = case find_result of
450 -> ptext SLIT("it is a member of package") <+> ppr pkg <> comma
451 <+> ptext SLIT("which is hidden")
454 -> ptext SLIT("it is hidden") <+> parens (ptext SLIT("in package")
459 -> ptext SLIT("it is not a module in the current program, or in any known package.")
460 | verbosity dflags < 3
461 -> ptext SLIT("use -v to see a list of the files searched for")
463 -> hang (ptext SLIT("locations searched:"))
464 2 (vcat (map text files))
466 _ -> panic "cantFindErr"