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 ()
16 findLinkable, -- :: ModuleName -> ModLocation -> IO (Maybe Linkable)
18 cantFindError, -- :: DynFlags -> Module -> FindResult -> SDoc
21 #include "HsVersions.h"
24 import UniqFM ( filterUFM )
29 import DynFlags ( DynFlags(..), isOneShot, GhcMode(..) )
32 import DATA_IOREF ( IORef, writeIORef, readIORef )
35 import System.Directory
38 import Maybes ( MaybeErr(..) )
39 import Data.Maybe ( isNothing )
42 type FileExt = String -- Filename extension
43 type BaseName = String -- Basename of file
45 -- -----------------------------------------------------------------------------
48 -- The Finder provides a thin filesystem abstraction to the rest of
49 -- the compiler. For a given module, it can tell you where the
50 -- source, interface, and object files for that module live.
52 -- It does *not* know which particular package a module lives in. Use
53 -- Packages.moduleToPackageConfig for that.
55 -- -----------------------------------------------------------------------------
58 -- remove all the home modules from the cache; package modules are
59 -- assumed to not move around during a session.
60 flushFinderCache :: IORef FinderCache -> IO ()
61 flushFinderCache finder_cache = do
62 fm <- readIORef finder_cache
63 writeIORef finder_cache $! filterUFM (\(loc,m) -> isNothing m) fm
65 addToFinderCache :: IORef FinderCache -> Module -> FinderCacheEntry -> IO ()
66 addToFinderCache finder_cache mod_name entry = do
67 fm <- readIORef finder_cache
68 writeIORef finder_cache $! extendModuleEnv fm mod_name entry
70 lookupFinderCache :: IORef FinderCache -> Module -> IO (Maybe FinderCacheEntry)
71 lookupFinderCache finder_cache mod_name = do
72 fm <- readIORef finder_cache
73 return $! lookupModuleEnv fm mod_name
75 -- -----------------------------------------------------------------------------
78 -- This is the main interface to the finder, which maps ModuleNames to
79 -- Modules and ModLocations.
81 -- The Module contains one crucial bit of information about a module:
82 -- whether it lives in the current ("home") package or not (see Module
85 -- The ModLocation contains the names of all the files associated with
86 -- that module: its source file, .hi file, object file, etc.
89 = Found ModLocation PackageIdH
90 -- the module was found
91 | PackageHidden PackageId
92 -- for an explicit source import: the package containing the module is
94 | ModuleHidden PackageId
95 -- for an explicit source import: the package containing the module is
96 -- exposed, but the module itself is hidden.
98 -- the module was not found, the specified places were searched.
100 type LocalFindResult = MaybeErr [FilePath] FinderCacheEntry
101 -- LocalFindResult is used for internal functions which
102 -- return a more informative type; it's munged into
103 -- the external FindResult by 'cached'
106 -> (DynFlags -> Module -> IO LocalFindResult)
107 -> HscEnv -> Module -> Bool -> IO FindResult
108 cached home_allowed wrapped_fn hsc_env name explicit
109 = do { -- First try the cache
110 let cache = hsc_FC hsc_env
111 ; mb_entry <- lookupFinderCache cache name
113 Just old_entry -> return (found old_entry) ;
116 { -- Now try the wrapped function
117 mb_entry <- wrapped_fn (hsc_dflags hsc_env) name
119 Failed paths -> return (NotFound paths)
120 Succeeded new_entry -> do { addToFinderCache cache name new_entry
121 ; return (found new_entry) }
124 -- We've found the module, so the remaining question is
125 -- whether it's visible or not
126 found :: FinderCacheEntry -> FindResult
128 | home_allowed = Found loc HomePackage
129 | otherwise = NotFound []
130 found (loc, Just (pkg, exposed_mod))
131 | explicit && not exposed_mod = ModuleHidden pkg_name
132 | explicit && not (exposed pkg) = PackageHidden pkg_name
133 | otherwise = Found loc (ExtPackage (mkPackageId (package pkg)))
135 pkg_name = packageConfigId pkg
137 addHomeModuleToFinder :: HscEnv -> Module -> ModLocation -> IO ()
138 addHomeModuleToFinder hsc_env mod loc
139 = addToFinderCache (hsc_FC hsc_env) mod (loc, Nothing)
142 -- -----------------------------------------------------------------------------
143 -- The two external entry points
146 findModule :: HscEnv -> Module -> Bool -> IO FindResult
147 findModule = cached True findModule'
149 findPackageModule :: HscEnv -> Module -> Bool -> IO FindResult
150 findPackageModule = cached False findPackageModule'
152 -- -----------------------------------------------------------------------------
153 -- The internal workers
155 findModule' :: DynFlags -> Module -> IO LocalFindResult
156 -- Find home or package module
157 findModule' dflags name = do
158 r <- findPackageModule' dflags name
160 Failed pkg_files -> do
161 j <- findHomeModule' dflags name
164 return (Failed (home_files ++ pkg_files))
166 -> return other_result
168 -> return other_result
170 findHomeModule' :: DynFlags -> Module -> IO LocalFindResult
171 findHomeModule' dflags mod = do
172 let home_path = importPaths dflags
177 [ ("hs", mkHomeModLocationSearched dflags mod "hs")
178 , ("lhs", mkHomeModLocationSearched dflags mod "lhs")
181 hi_exts = [ (hisuf, mkHiOnlyModLocation dflags hisuf)
182 , (addBootSuffix hisuf, mkHiOnlyModLocation dflags hisuf)
185 -- In compilation manager modes, we look for source files in the home
186 -- package because we can compile these automatically. In one-shot
187 -- compilation mode we look for .hi and .hi-boot files only.
188 exts | isOneShot (ghcMode dflags) = hi_exts
189 | otherwise = source_exts
191 searchPathExts home_path mod exts
193 findPackageModule' :: DynFlags -> Module -> IO LocalFindResult
194 findPackageModule' dflags mod
195 = case moduleToPackageConfig dflags mod of
196 Nothing -> return (Failed [])
197 Just pkg_info -> findPackageIface dflags mod pkg_info
199 findPackageIface :: DynFlags -> Module -> (PackageConfig,Bool) -> IO LocalFindResult
200 findPackageIface dflags mod pkg_info@(pkg_conf, _) = do
202 tag = buildTag dflags
204 -- hi-suffix for packages depends on the build tag.
205 package_hisuf | null tag = "hi"
206 | otherwise = tag ++ "_hi"
209 mkPackageModLocation dflags pkg_info package_hisuf) ]
212 [ ("hs", mkPackageModLocation dflags pkg_info package_hisuf)
213 , ("lhs", mkPackageModLocation dflags pkg_info package_hisuf)
216 -- mkdependHS needs to look for source files in packages too, so
217 -- that we can make dependencies between package before they have
220 | MkDepend <- ghcMode dflags = hi_exts ++ source_exts
221 | otherwise = hi_exts
222 -- we never look for a .hi-boot file in an external package;
223 -- .hi-boot files only make sense for the home package.
225 searchPathExts (importDirs pkg_conf) mod exts
227 -- -----------------------------------------------------------------------------
228 -- General path searching
231 :: [FilePath] -- paths to search
232 -> Module -- module name
235 FilePath -> BaseName -> IO FinderCacheEntry -- action
238 -> IO LocalFindResult
240 searchPathExts paths mod exts
241 = do result <- search to_search
243 hPutStrLn stderr (showSDoc $
244 vcat [text "Search" <+> ppr mod <+> sep (map (text. fst) exts)
245 , nest 2 (vcat (map text paths))
247 Succeeded (loc, p) -> text "Found" <+> ppr loc
248 Failed fs -> text "not found"])
253 basename = dots_to_slashes (moduleUserString mod)
255 to_search :: [(FilePath, IO FinderCacheEntry)]
256 to_search = [ (file, fn path basename)
259 let base | path == "." = basename
260 | otherwise = path ++ '/':basename
261 file = base ++ '.':ext
264 search [] = return (Failed (map fst to_search))
265 search ((file, mk_result) : rest) = do
266 b <- doesFileExist file
268 then do { res <- mk_result; return (Succeeded res) }
271 mkHomeModLocationSearched :: DynFlags -> Module -> FileExt
272 -> FilePath -> BaseName -> IO FinderCacheEntry
273 mkHomeModLocationSearched dflags mod suff path basename = do
274 loc <- mkHomeModLocation2 dflags mod (path ++ '/':basename) suff
275 return (loc, Nothing)
277 mkHiOnlyModLocation :: DynFlags -> FileExt -> FilePath -> BaseName
278 -> IO FinderCacheEntry
279 mkHiOnlyModLocation dflags hisuf path basename = do
280 loc <- hiOnlyModLocation dflags path basename hisuf
281 return (loc, Nothing)
283 mkPackageModLocation :: DynFlags -> (PackageConfig, Bool) -> FileExt
284 -> FilePath -> BaseName -> IO FinderCacheEntry
285 mkPackageModLocation dflags pkg_info hisuf path basename = do
286 loc <- hiOnlyModLocation dflags path basename hisuf
287 return (loc, Just pkg_info)
289 -- -----------------------------------------------------------------------------
290 -- Constructing a home module location
292 -- This is where we construct the ModLocation for a module in the home
293 -- package, for which we have a source file. It is called from three
296 -- (a) Here in the finder, when we are searching for a module to import,
297 -- using the search path (-i option).
299 -- (b) The compilation manager, when constructing the ModLocation for
300 -- a "root" module (a source file named explicitly on the command line
301 -- or in a :load command in GHCi).
303 -- (c) The driver in one-shot mode, when we need to construct a
304 -- ModLocation for a source file named on the command-line.
309 -- The name of the module
312 -- (a): The search path component where the source file was found.
316 -- (a): dots_to_slashes (moduleNameUserString mod)
317 -- (b) and (c): The filename of the source file, minus its extension
320 -- The filename extension of the source file (usually "hs" or "lhs").
322 mkHomeModLocation :: DynFlags -> Module -> FilePath -> IO ModLocation
323 mkHomeModLocation dflags mod src_filename = do
324 let (basename,extension) = splitFilename src_filename
325 mkHomeModLocation2 dflags mod basename extension
327 mkHomeModLocation2 :: DynFlags
329 -> FilePath -- Of source module, without suffix
332 mkHomeModLocation2 dflags mod src_basename ext = do
333 let mod_basename = dots_to_slashes (moduleUserString mod)
335 obj_fn <- mkObjPath dflags src_basename mod_basename
336 hi_fn <- mkHiPath dflags src_basename mod_basename
338 return (ModLocation{ ml_hs_file = Just (src_basename ++ '.':ext),
340 ml_obj_file = obj_fn })
342 hiOnlyModLocation :: DynFlags -> FilePath -> String -> Suffix -> IO ModLocation
343 hiOnlyModLocation dflags path basename hisuf
344 = do let full_basename = path++'/':basename
345 obj_fn <- mkObjPath dflags full_basename basename
346 return ModLocation{ ml_hs_file = Nothing,
347 ml_hi_file = full_basename ++ '.':hisuf,
348 -- Remove the .hi-boot suffix from
349 -- hi_file, if it had one. We always
350 -- want the name of the real .hi file
351 -- in the ml_hi_file field.
355 -- | Constructs the filename of a .o file for a given source file.
356 -- Does /not/ check whether the .o file exists
359 -> FilePath -- the filename of the source file, minus the extension
360 -> String -- the module name with dots replaced by slashes
362 mkObjPath dflags basename mod_basename
364 odir = outputDir dflags
365 osuf = objectSuf dflags
367 obj_basename | Just dir <- odir = dir ++ '/':mod_basename
368 | otherwise = basename
370 return (obj_basename ++ '.':osuf)
372 -- | Constructs the filename of a .hi file for a given source file.
373 -- Does /not/ check whether the .hi file exists
376 -> FilePath -- the filename of the source file, minus the extension
377 -> String -- the module name with dots replaced by slashes
379 mkHiPath dflags basename mod_basename
384 hi_basename | Just dir <- hidir = dir ++ '/':mod_basename
385 | otherwise = basename
387 return (hi_basename ++ '.':hisuf)
390 -- -----------------------------------------------------------------------------
391 -- findLinkable isn't related to the other stuff in here,
392 -- but there's no other obvious place for it
394 findLinkable :: Module -> ModLocation -> IO (Maybe Linkable)
395 findLinkable mod locn
396 = do let obj_fn = ml_obj_file locn
397 obj_exist <- doesFileExist obj_fn
401 do let stub_fn = case splitFilename3 obj_fn of
402 (dir, base, ext) -> dir ++ "/" ++ base ++ "_stub.o"
403 stub_exist <- doesFileExist stub_fn
404 obj_time <- getModificationTime obj_fn
406 then return (Just (LM obj_time mod [DotO obj_fn, DotO stub_fn]))
407 else return (Just (LM obj_time mod [DotO obj_fn]))
409 -- -----------------------------------------------------------------------------
412 dots_to_slashes = map (\c -> if c == '.' then '/' else c)
415 -- -----------------------------------------------------------------------------
418 cantFindError :: DynFlags -> Module -> FindResult -> SDoc
419 cantFindError dflags mod_name find_result
420 = hang (ptext SLIT("Could not find module") <+> quotes (ppr mod_name) <> colon)
424 = case find_result of
426 -> ptext SLIT("it is a member of package") <+> ppr pkg <> comma
427 <+> ptext SLIT("which is hidden")
430 -> ptext SLIT("it is hidden") <+> parens (ptext SLIT("in package")
435 -> ptext SLIT("it is not a module in the current program, or in any known package.")
436 | verbosity dflags < 3
437 -> ptext SLIT("use -v to see a list of the files searched for")
439 -> hang (ptext SLIT("locations searched:"))
440 2 (vcat (map text files))
442 Found _ _ -> panic "cantFindErr"