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, -- :: Module -> ModLocation -> IO ()
16 findLinkable, -- :: ModuleName -> ModLocation -> IO (Maybe Linkable)
18 cantFindError, -- :: DynFlags -> Module -> FindResult -> SDoc
21 #include "HsVersions.h"
24 import UniqFM ( filterUFM )
25 import HscTypes ( Linkable(..), Unlinked(..) )
31 import CmdLineOpts ( DynFlags(..) )
34 import DATA_IOREF ( IORef, writeIORef, readIORef )
37 import System.Directory
40 import Maybes ( MaybeErr(..) )
41 import Data.Maybe ( isNothing )
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.moduleToPackageConfig for that.
57 -- -----------------------------------------------------------------------------
60 GLOBAL_VAR(finder_cache, emptyModuleEnv, ModuleEnv FinderCacheEntry)
62 type FinderCacheEntry = (ModLocation, Maybe (PackageConfig,Bool))
64 -- remove all the home modules from the cache; package modules are
65 -- assumed to not move around during a session.
66 flushFinderCache :: IO ()
68 fm <- readIORef finder_cache
69 writeIORef finder_cache (filterUFM (\(loc,m) -> isNothing m) fm)
71 addToFinderCache :: Module -> FinderCacheEntry -> IO ()
72 addToFinderCache mod_name entry = do
73 fm <- readIORef finder_cache
74 writeIORef finder_cache (extendModuleEnv fm mod_name entry)
76 lookupFinderCache :: Module -> IO (Maybe FinderCacheEntry)
77 lookupFinderCache mod_name = do
78 fm <- readIORef finder_cache
79 return $! lookupModuleEnv fm mod_name
81 -- -----------------------------------------------------------------------------
84 -- This is the main interface to the finder, which maps ModuleNames to
85 -- Modules and ModLocations.
87 -- The Module contains one crucial bit of information about a module:
88 -- whether it lives in the current ("home") package or not (see Module
91 -- The ModLocation contains the names of all the files associated with
92 -- that module: its source file, .hi file, object file, etc.
95 = Found ModLocation PackageIdH
96 -- the module was found
97 | PackageHidden PackageId
98 -- for an explicit source import: the package containing the module is
100 | ModuleHidden PackageId
101 -- for an explicit source import: the package containing the module is
102 -- exposed, but the module itself is hidden.
103 | NotFound [FilePath]
104 -- the module was not found, the specified places were searched.
106 type LocalFindResult = MaybeErr [FilePath] FinderCacheEntry
107 -- LocalFindResult is used for internal functions which
108 -- return a more informative type; it's munged into
109 -- the external FindResult by 'cached'
111 cached :: (DynFlags -> Module -> IO LocalFindResult)
112 -> DynFlags -> Module -> Bool -> IO FindResult
113 cached wrapped_fn dflags name explicit
114 = do { -- First try the cache
115 mb_entry <- lookupFinderCache name
117 Just old_entry -> return (found old_entry) ;
120 { -- Now try the wrapped function
121 mb_entry <- wrapped_fn dflags name
123 Failed paths -> return (NotFound paths)
124 Succeeded new_entry -> do { addToFinderCache name new_entry
125 ; return (found new_entry) }
128 -- We've found the module, so the remaining question is
129 -- whether it's visible or not
130 found :: FinderCacheEntry -> FindResult
131 found (loc, Nothing) = Found loc HomePackage
132 found (loc, Just (pkg, exposed_mod))
133 | explicit && not exposed_mod = ModuleHidden pkg_name
134 | explicit && not (exposed pkg) = PackageHidden pkg_name
135 | otherwise = Found loc (ExtPackage (mkPackageId (package pkg)))
137 pkg_name = packageConfigId pkg
139 addHomeModuleToFinder :: Module -> ModLocation -> IO ()
140 addHomeModuleToFinder mod loc = addToFinderCache mod (loc, Nothing)
143 -- -----------------------------------------------------------------------------
144 -- The two external entry points
147 findModule :: DynFlags -> Module -> Bool -> IO FindResult
148 findModule = cached findModule'
150 findPackageModule :: DynFlags -> Module -> Bool -> IO FindResult
151 findPackageModule = cached findPackageModule'
153 -- -----------------------------------------------------------------------------
154 -- The internal workers
156 findModule' :: DynFlags -> Module -> IO LocalFindResult
157 -- Find home or package module
158 findModule' dflags name = do
159 r <- findPackageModule' dflags name
161 Failed pkg_files -> do
162 j <- findHomeModule' dflags name
165 return (Failed (home_files ++ pkg_files))
167 -> return other_result
169 -> return other_result
171 findHomeModule' :: DynFlags -> Module -> IO LocalFindResult
172 findHomeModule' dflags mod = do
173 let home_path = importPaths dflags
174 hisuf <- readIORef v_Hi_suf
175 mode <- readIORef v_GhcMode
179 [ ("hs", mkHomeModLocationSearched mod "hs")
180 , ("lhs", mkHomeModLocationSearched mod "lhs")
183 hi_exts = [ (hisuf, mkHiOnlyModLocation hisuf)
184 , (addBootSuffix hisuf, mkHiOnlyModLocation hisuf)
187 -- In compilation manager modes, we look for source files in the home
188 -- package because we can compile these automatically. In one-shot
189 -- compilation mode we look for .hi and .hi-boot files only.
191 | DoMkDependHS <- mode = source_exts
192 | isCompManagerMode mode = source_exts
193 | otherwise {-one-shot-} = hi_exts
195 searchPathExts home_path mod exts
197 findPackageModule' :: DynFlags -> Module -> IO LocalFindResult
198 findPackageModule' dflags mod
199 = case moduleToPackageConfig dflags mod of
200 Nothing -> return (Failed [])
201 Just pkg_info -> findPackageIface mod pkg_info
203 findPackageIface :: Module -> (PackageConfig,Bool) -> IO LocalFindResult
204 findPackageIface mod pkg_info@(pkg_conf, _) = do
205 mode <- readIORef v_GhcMode
206 tag <- readIORef v_Build_tag
208 -- hi-suffix for packages depends on the build tag.
209 package_hisuf | null tag = "hi"
210 | otherwise = tag ++ "_hi"
213 mkPackageModLocation pkg_info package_hisuf) ]
216 [ ("hs", mkPackageModLocation pkg_info package_hisuf)
217 , ("lhs", mkPackageModLocation pkg_info package_hisuf)
220 -- mkdependHS needs to look for source files in packages too, so
221 -- that we can make dependencies between package before they have
224 | DoMkDependHS <- mode = hi_exts ++ source_exts
225 | otherwise = hi_exts
226 -- we never look for a .hi-boot file in an external package;
227 -- .hi-boot files only make sense for the home package.
229 searchPathExts (importDirs pkg_conf) mod exts
231 -- -----------------------------------------------------------------------------
232 -- General path searching
235 :: [FilePath] -- paths to search
236 -> Module -- module name
239 FilePath -> BaseName -> IO FinderCacheEntry -- action
242 -> IO LocalFindResult
244 searchPathExts paths mod exts
245 = do result <- search to_search
247 hPutStrLn stderr (showSDoc $
248 vcat [text "Search" <+> ppr mod <+> sep (map (text. fst) exts)
249 , nest 2 (vcat (map text paths))
251 Succeeded (loc, p) -> text "Found" <+> ppr loc
252 Failed fs -> text "not found"])
257 basename = dots_to_slashes (moduleUserString mod)
259 to_search :: [(FilePath, IO FinderCacheEntry)]
260 to_search = [ (file, fn path basename)
263 let base | path == "." = basename
264 | otherwise = path ++ '/':basename
265 file = base ++ '.':ext
268 search [] = return (Failed (map fst to_search))
269 search ((file, mk_result) : rest) = do
270 b <- doesFileExist file
272 then do { res <- mk_result; return (Succeeded res) }
275 mkHomeModLocationSearched :: Module -> FileExt
276 -> FilePath -> BaseName -> IO FinderCacheEntry
277 mkHomeModLocationSearched mod suff path basename = do
278 loc <- mkHomeModLocation2 mod (path ++ '/':basename) suff
279 return (loc, Nothing)
281 mkHiOnlyModLocation :: FileExt -> FilePath -> BaseName -> IO FinderCacheEntry
282 mkHiOnlyModLocation hisuf path basename = do
283 loc <- hiOnlyModLocation path basename hisuf
284 return (loc, Nothing)
286 mkPackageModLocation :: (PackageConfig, Bool) -> FileExt
287 -> FilePath -> BaseName -> IO FinderCacheEntry
288 mkPackageModLocation pkg_info hisuf path basename = do
289 loc <- hiOnlyModLocation path basename hisuf
290 return (loc, Just pkg_info)
292 -- -----------------------------------------------------------------------------
293 -- Constructing a home module location
295 -- This is where we construct the ModLocation for a module in the home
296 -- package, for which we have a source file. It is called from three
299 -- (a) Here in the finder, when we are searching for a module to import,
300 -- using the search path (-i option).
302 -- (b) The compilation manager, when constructing the ModLocation for
303 -- a "root" module (a source file named explicitly on the command line
304 -- or in a :load command in GHCi).
306 -- (c) The driver in one-shot mode, when we need to construct a
307 -- ModLocation for a source file named on the command-line.
312 -- The name of the module
315 -- (a): The search path component where the source file was found.
319 -- (a): dots_to_slashes (moduleNameUserString mod)
320 -- (b) and (c): The filename of the source file, minus its extension
323 -- The filename extension of the source file (usually "hs" or "lhs").
325 mkHomeModLocation :: Module -> FilePath -> IO ModLocation
326 mkHomeModLocation mod src_filename = do
327 let (basename,extension) = splitFilename src_filename
328 mkHomeModLocation2 mod basename extension
330 mkHomeModLocation2 :: Module
331 -> FilePath -- Of source module, without suffix
334 mkHomeModLocation2 mod src_basename ext = do
335 let mod_basename = dots_to_slashes (moduleUserString mod)
337 obj_fn <- mkObjPath src_basename mod_basename
338 hi_fn <- mkHiPath src_basename mod_basename
340 return (ModLocation{ ml_hs_file = Just (src_basename ++ '.':ext),
342 ml_obj_file = obj_fn })
344 hiOnlyModLocation :: FilePath -> String -> Suffix -> IO ModLocation
345 hiOnlyModLocation path basename hisuf
346 = do let full_basename = path++'/':basename
347 obj_fn <- mkObjPath full_basename basename
348 return ModLocation{ ml_hs_file = Nothing,
349 ml_hi_file = full_basename ++ '.':hisuf,
350 -- Remove the .hi-boot suffix from
351 -- hi_file, if it had one. We always
352 -- want the name of the real .hi file
353 -- in the ml_hi_file field.
357 -- | Constructs the filename of a .o file for a given source file.
358 -- Does /not/ check whether the .o file exists
360 :: FilePath -- the filename of the source file, minus the extension
361 -> String -- the module name with dots replaced by slashes
363 mkObjPath basename mod_basename
364 = do odir <- readIORef v_Output_dir
365 osuf <- readIORef v_Object_suf
367 let 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
375 :: FilePath -- the filename of the source file, minus the extension
376 -> String -- the module name with dots replaced by slashes
378 mkHiPath basename mod_basename
379 = do hidir <- readIORef v_Hi_dir
380 hisuf <- readIORef v_Hi_suf
382 let hi_basename | Just dir <- hidir = dir ++ '/':mod_basename
383 | otherwise = basename
385 return (hi_basename ++ '.':hisuf)
388 -- -----------------------------------------------------------------------------
389 -- findLinkable isn't related to the other stuff in here,
390 -- but there's no other obvious place for it
392 findLinkable :: Module -> ModLocation -> IO (Maybe Linkable)
393 findLinkable mod locn
394 = do let obj_fn = ml_obj_file locn
395 obj_exist <- doesFileExist obj_fn
399 do let stub_fn = case splitFilename3 obj_fn of
400 (dir, base, ext) -> dir ++ "/" ++ base ++ "_stub.o"
401 stub_exist <- doesFileExist stub_fn
402 obj_time <- getModificationTime obj_fn
404 then return (Just (LM obj_time mod [DotO obj_fn, DotO stub_fn]))
405 else return (Just (LM obj_time mod [DotO obj_fn]))
407 -- -----------------------------------------------------------------------------
410 dots_to_slashes = map (\c -> if c == '.' then '/' else c)
413 -- -----------------------------------------------------------------------------
416 cantFindError :: DynFlags -> Module -> FindResult -> SDoc
417 cantFindError dflags mod_name find_result
418 = hang (ptext SLIT("Could not find module") <+> quotes (ppr mod_name) <> colon)
422 = case find_result of
424 -> ptext SLIT("it is a member of package") <+> ppr pkg <> comma
425 <+> ptext SLIT("which is hidden")
428 -> ptext SLIT("it is hidden") <+> parens (ptext SLIT("in package")
433 -> ptext SLIT("it is not a module in the current program, or in any known package.")
434 | verbosity dflags < 3
435 -> ptext SLIT("use -v to see a list of the files searched for")
437 -> hang (ptext SLIT("locations searched:"))
438 2 (vcat (map text files))
440 Found _ _ -> panic "cantFindErr"