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 ()
18 findObjectLinkableMaybe,
21 cantFindError, -- :: DynFlags -> Module -> FindResult -> SDoc
24 #include "HsVersions.h"
27 import UniqFM ( filterUFM, delFromUFM )
32 import DynFlags ( DynFlags(..), isOneShot, GhcMode(..) )
34 import Maybes ( expectJust )
36 import DATA_IOREF ( IORef, writeIORef, readIORef )
39 import System.Directory
42 import Data.Maybe ( isNothing )
43 import Time ( ClockTime )
46 type FileExt = String -- Filename extension
47 type BaseName = String -- Basename of file
49 -- -----------------------------------------------------------------------------
52 -- The Finder provides a thin filesystem abstraction to the rest of
53 -- the compiler. For a given module, it can tell you where the
54 -- source, interface, and object files for that module live.
56 -- It does *not* know which particular package a module lives in. Use
57 -- Packages.lookupModuleInAllPackages for that.
59 -- -----------------------------------------------------------------------------
62 -- remove all the home modules from the cache; package modules are
63 -- assumed to not move around during a session.
64 flushFinderCache :: IORef FinderCache -> IO ()
65 flushFinderCache finder_cache = do
66 fm <- readIORef finder_cache
67 writeIORef finder_cache $! filterUFM (\(loc,m) -> isNothing m) fm
69 addToFinderCache :: IORef FinderCache -> Module -> FinderCacheEntry -> IO ()
70 addToFinderCache finder_cache mod_name entry = do
71 fm <- readIORef finder_cache
72 writeIORef finder_cache $! extendModuleEnv fm mod_name entry
74 removeFromFinderCache :: IORef FinderCache -> Module -> IO ()
75 removeFromFinderCache finder_cache mod_name = do
76 fm <- readIORef finder_cache
77 writeIORef finder_cache $! delFromUFM fm mod_name
79 lookupFinderCache :: IORef FinderCache -> Module -> IO (Maybe FinderCacheEntry)
80 lookupFinderCache finder_cache mod_name = do
81 fm <- readIORef finder_cache
82 return $! lookupModuleEnv fm mod_name
84 -- -----------------------------------------------------------------------------
85 -- The two external entry points
87 -- This is the main interface to the finder, which maps ModuleNames to
88 -- Modules and ModLocations.
90 -- The Module contains one crucial bit of information about a module:
91 -- whether it lives in the current ("home") package or not (see Module
94 -- The ModLocation contains the names of all the files associated with
95 -- that module: its source file, .hi file, object file, etc.
98 = Found ModLocation PackageIdH
99 -- the module was found
100 | FoundMultiple [PackageId]
101 -- *error*: both in multiple packages
102 | PackageHidden PackageId
103 -- for an explicit source import: the package containing the module is
105 | ModuleHidden PackageId
106 -- for an explicit source import: the package containing the module is
107 -- exposed, but the module itself is hidden.
108 | NotFound [FilePath]
109 -- the module was not found, the specified places were searched.
111 findModule :: HscEnv -> Module -> Bool -> IO FindResult
112 findModule = findModule' True
114 findPackageModule :: HscEnv -> Module -> Bool -> IO FindResult
115 findPackageModule = findModule' False
119 = Ok FinderCacheEntry
120 | CantFindAmongst [FilePath]
121 | MultiplePackages [PackageId]
123 findModule' :: Bool -> HscEnv -> Module -> Bool -> IO FindResult
124 findModule' home_allowed hsc_env name explicit
125 = do -- First try the cache
126 mb_entry <- lookupFinderCache cache name
128 Just old_entry -> return $! found old_entry
129 Nothing -> not_cached
132 cache = hsc_FC hsc_env
133 dflags = hsc_dflags hsc_env
135 -- We've found the module, so the remaining question is
136 -- whether it's visible or not
137 found :: FinderCacheEntry -> FindResult
139 | home_allowed = Found loc HomePackage
140 | otherwise = NotFound []
141 found (loc, Just (pkg, exposed_mod))
142 | explicit && not exposed_mod = ModuleHidden pkg_name
143 | explicit && not (exposed pkg) = PackageHidden pkg_name
145 Found loc (ExtPackage (mkPackageId (package pkg)))
147 pkg_name = packageConfigId pkg
150 addToFinderCache cache name entry
151 return $! found entry
154 | not home_allowed = do
155 j <- findPackageModule' dflags name
157 Ok entry -> found_new entry
158 MultiplePackages pkgs -> return (FoundMultiple pkgs)
159 CantFindAmongst paths -> return (NotFound paths)
162 j <- findHomeModule' dflags name
164 Ok entry -> found_new entry
165 MultiplePackages pkgs -> return (FoundMultiple pkgs)
166 CantFindAmongst home_files -> do
167 r <- findPackageModule' dflags name
169 CantFindAmongst pkg_files ->
170 return (NotFound (home_files ++ pkg_files))
171 MultiplePackages pkgs ->
172 return (FoundMultiple pkgs)
176 addHomeModuleToFinder :: HscEnv -> Module -> ModLocation -> IO ()
177 addHomeModuleToFinder hsc_env mod loc
178 = addToFinderCache (hsc_FC hsc_env) mod (loc, Nothing)
180 uncacheModule :: HscEnv -> Module -> IO ()
181 uncacheModule hsc_env mod = removeFromFinderCache (hsc_FC hsc_env) mod
183 -- -----------------------------------------------------------------------------
184 -- The internal workers
186 findHomeModule' :: DynFlags -> Module -> IO LocalFindResult
187 findHomeModule' dflags mod = do
188 let home_path = importPaths dflags
193 [ ("hs", mkHomeModLocationSearched dflags mod "hs")
194 , ("lhs", mkHomeModLocationSearched dflags mod "lhs")
197 hi_exts = [ (hisuf, mkHiOnlyModLocation dflags hisuf)
198 , (addBootSuffix hisuf, mkHiOnlyModLocation dflags hisuf)
201 -- In compilation manager modes, we look for source files in the home
202 -- package because we can compile these automatically. In one-shot
203 -- compilation mode we look for .hi and .hi-boot files only.
204 exts | isOneShot (ghcMode dflags) = hi_exts
205 | otherwise = source_exts
207 searchPathExts home_path mod exts
209 findPackageModule' :: DynFlags -> Module -> IO LocalFindResult
210 findPackageModule' dflags mod
211 = case lookupModuleInAllPackages dflags mod of
212 [] -> return (CantFindAmongst [])
213 [pkg_info] -> findPackageIface dflags mod pkg_info
214 many -> return (MultiplePackages (map (mkPackageId.package.fst) many))
216 findPackageIface :: DynFlags -> Module -> (PackageConfig,Bool) -> IO LocalFindResult
217 findPackageIface dflags mod pkg_info@(pkg_conf, _) = do
219 tag = buildTag dflags
221 -- hi-suffix for packages depends on the build tag.
222 package_hisuf | null tag = "hi"
223 | otherwise = tag ++ "_hi"
226 mkPackageModLocation dflags pkg_info package_hisuf) ]
229 [ ("hs", mkPackageModLocation dflags pkg_info package_hisuf)
230 , ("lhs", mkPackageModLocation dflags pkg_info package_hisuf)
233 -- mkdependHS needs to look for source files in packages too, so
234 -- that we can make dependencies between package before they have
237 | MkDepend <- ghcMode dflags = hi_exts ++ source_exts
238 | otherwise = hi_exts
239 -- we never look for a .hi-boot file in an external package;
240 -- .hi-boot files only make sense for the home package.
242 searchPathExts (importDirs pkg_conf) mod exts
244 -- -----------------------------------------------------------------------------
245 -- General path searching
248 :: [FilePath] -- paths to search
249 -> Module -- module name
252 FilePath -> BaseName -> IO FinderCacheEntry -- action
255 -> IO LocalFindResult
257 searchPathExts paths mod exts
258 = do result <- search to_search
260 hPutStrLn stderr (showSDoc $
261 vcat [text "Search" <+> ppr mod <+> sep (map (text. fst) exts)
262 , nest 2 (vcat (map text paths))
264 Succeeded (loc, p) -> text "Found" <+> ppr loc
265 Failed fs -> text "not found"])
270 basename = dots_to_slashes (moduleString mod)
272 to_search :: [(FilePath, IO FinderCacheEntry)]
273 to_search = [ (file, fn path basename)
276 let base | path == "." = basename
277 | otherwise = path `joinFileName` basename
278 file = base `joinFileExt` ext
281 search [] = return (CantFindAmongst (map fst to_search))
282 search ((file, mk_result) : rest) = do
283 b <- doesFileExist file
285 then do { res <- mk_result; return (Ok res) }
288 mkHomeModLocationSearched :: DynFlags -> Module -> FileExt
289 -> FilePath -> BaseName -> IO FinderCacheEntry
290 mkHomeModLocationSearched dflags mod suff path basename = do
291 loc <- mkHomeModLocation2 dflags mod (path `joinFileName` basename) suff
292 return (loc, Nothing)
294 mkHiOnlyModLocation :: DynFlags -> FileExt -> FilePath -> BaseName
295 -> IO FinderCacheEntry
296 mkHiOnlyModLocation dflags hisuf path basename = do
297 loc <- hiOnlyModLocation dflags path basename hisuf
298 return (loc, Nothing)
300 mkPackageModLocation :: DynFlags -> (PackageConfig, Bool) -> FileExt
301 -> FilePath -> BaseName -> IO FinderCacheEntry
302 mkPackageModLocation dflags pkg_info hisuf path basename = do
303 loc <- hiOnlyModLocation dflags path basename hisuf
304 return (loc, Just pkg_info)
306 -- -----------------------------------------------------------------------------
307 -- Constructing a home module location
309 -- This is where we construct the ModLocation for a module in the home
310 -- package, for which we have a source file. It is called from three
313 -- (a) Here in the finder, when we are searching for a module to import,
314 -- using the search path (-i option).
316 -- (b) The compilation manager, when constructing the ModLocation for
317 -- a "root" module (a source file named explicitly on the command line
318 -- or in a :load command in GHCi).
320 -- (c) The driver in one-shot mode, when we need to construct a
321 -- ModLocation for a source file named on the command-line.
326 -- The name of the module
329 -- (a): The search path component where the source file was found.
333 -- (a): dots_to_slashes (moduleNameUserString mod)
334 -- (b) and (c): The filename of the source file, minus its extension
337 -- The filename extension of the source file (usually "hs" or "lhs").
339 mkHomeModLocation :: DynFlags -> Module -> FilePath -> IO ModLocation
340 mkHomeModLocation dflags mod src_filename = do
341 let (basename,extension) = splitFilename src_filename
342 mkHomeModLocation2 dflags mod basename extension
344 mkHomeModLocation2 :: DynFlags
346 -> FilePath -- Of source module, without suffix
349 mkHomeModLocation2 dflags mod src_basename ext = do
350 let mod_basename = dots_to_slashes (moduleString mod)
352 obj_fn <- mkObjPath dflags src_basename mod_basename
353 hi_fn <- mkHiPath dflags src_basename mod_basename
355 return (ModLocation{ ml_hs_file = Just (src_basename `joinFileExt` ext),
357 ml_obj_file = obj_fn })
359 hiOnlyModLocation :: DynFlags -> FilePath -> String -> Suffix -> IO ModLocation
360 hiOnlyModLocation dflags path basename hisuf
361 = do let full_basename = path `joinFileName` basename
362 obj_fn <- mkObjPath dflags full_basename basename
363 return ModLocation{ ml_hs_file = Nothing,
364 ml_hi_file = full_basename `joinFileExt` hisuf,
365 -- Remove the .hi-boot suffix from
366 -- hi_file, if it had one. We always
367 -- want the name of the real .hi file
368 -- in the ml_hi_file field.
372 -- | Constructs the filename of a .o file for a given source file.
373 -- Does /not/ check whether the .o file exists
376 -> FilePath -- the filename of the source file, minus the extension
377 -> String -- the module name with dots replaced by slashes
379 mkObjPath dflags basename mod_basename
381 odir = objectDir dflags
382 osuf = objectSuf dflags
384 obj_basename | Just dir <- odir = dir `joinFileName` mod_basename
385 | otherwise = basename
387 return (obj_basename `joinFileExt` osuf)
389 -- | Constructs the filename of a .hi file for a given source file.
390 -- Does /not/ check whether the .hi file exists
393 -> FilePath -- the filename of the source file, minus the extension
394 -> String -- the module name with dots replaced by slashes
396 mkHiPath dflags basename mod_basename
401 hi_basename | Just dir <- hidir = dir `joinFileName` mod_basename
402 | otherwise = basename
404 return (hi_basename `joinFileExt` hisuf)
407 -- -----------------------------------------------------------------------------
408 -- Filenames of the stub files
410 -- We don't have to store these in ModLocations, because they can be derived
411 -- from other available information, and they're only rarely needed.
417 -> (FilePath,FilePath)
419 mkStubPaths dflags mod location
421 stubdir = stubDir dflags
423 mod_basename = dots_to_slashes (moduleString mod)
424 src_basename = basenameOf (expectJust "mkStubPaths"
425 (ml_hs_file location))
428 | Just dir <- stubdir = dir `joinFileName` mod_basename
429 | otherwise = src_basename
431 stub_basename = stub_basename0 ++ "_stub"
433 (stub_basename `joinFileExt` "c",
434 stub_basename `joinFileExt` "h")
435 -- the _stub.o filename is derived from the ml_obj_file.
437 -- -----------------------------------------------------------------------------
438 -- findLinkable isn't related to the other stuff in here,
439 -- but there's no other obvious place for it
441 findObjectLinkableMaybe :: Module -> ModLocation -> IO (Maybe Linkable)
442 findObjectLinkableMaybe mod locn
443 = do let obj_fn = ml_obj_file locn
444 maybe_obj_time <- modificationTimeIfExists obj_fn
445 case maybe_obj_time of
446 Nothing -> return Nothing
447 Just obj_time -> liftM Just (findObjectLinkable mod obj_fn obj_time)
449 -- Make an object linkable when we know the object file exists, and we know
450 -- its modification time.
451 findObjectLinkable :: Module -> FilePath -> ClockTime -> IO Linkable
452 findObjectLinkable mod obj_fn obj_time = do
453 let stub_fn = case splitFilename3 obj_fn of
454 (dir, base, ext) -> dir ++ "/" ++ base ++ "_stub.o"
455 stub_exist <- doesFileExist stub_fn
457 then return (LM obj_time mod [DotO obj_fn, DotO stub_fn])
458 else return (LM obj_time mod [DotO obj_fn])
460 -- -----------------------------------------------------------------------------
463 dots_to_slashes = map (\c -> if c == '.' then '/' else c)
466 -- -----------------------------------------------------------------------------
469 cantFindError :: DynFlags -> Module -> FindResult -> SDoc
470 cantFindError dflags mod_name (FoundMultiple pkgs)
471 = hang (ptext SLIT("Cannot import") <+> quotes (ppr mod_name) <> colon) 2 (
472 sep [ptext SLIT("it was found in multiple packages:"),
473 hsep (map (text.packageIdString) pkgs)]
475 cantFindError dflags mod_name find_result
476 = hang (ptext SLIT("Could not find module") <+> quotes (ppr mod_name) <> colon)
480 = case find_result of
482 -> ptext SLIT("it is a member of package") <+> ppr pkg <> comma
483 <+> ptext SLIT("which is hidden")
486 -> ptext SLIT("it is hidden") <+> parens (ptext SLIT("in package")
491 -> ptext SLIT("it is not a module in the current program, or in any known package.")
492 | verbosity dflags < 3
493 -> ptext SLIT("use -v to see a list of the files searched for")
495 -> hang (ptext SLIT("locations searched:"))
496 2 (vcat (map text files))
498 _ -> panic "cantFindErr"