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'
112 -> (DynFlags -> Module -> IO LocalFindResult)
113 -> DynFlags -> Module -> Bool -> IO FindResult
114 cached home_allowed wrapped_fn dflags name explicit
115 = do { -- First try the cache
116 mb_entry <- lookupFinderCache name
118 Just old_entry -> return (found old_entry) ;
121 { -- Now try the wrapped function
122 mb_entry <- wrapped_fn dflags name
124 Failed paths -> return (NotFound paths)
125 Succeeded new_entry -> do { addToFinderCache name new_entry
126 ; return (found new_entry) }
129 -- We've found the module, so the remaining question is
130 -- whether it's visible or not
131 found :: FinderCacheEntry -> FindResult
133 | home_allowed = Found loc HomePackage
134 | otherwise = NotFound []
135 found (loc, Just (pkg, exposed_mod))
136 | explicit && not exposed_mod = ModuleHidden pkg_name
137 | explicit && not (exposed pkg) = PackageHidden pkg_name
138 | otherwise = Found loc (ExtPackage (mkPackageId (package pkg)))
140 pkg_name = packageConfigId pkg
142 addHomeModuleToFinder :: Module -> ModLocation -> IO ()
143 addHomeModuleToFinder mod loc = addToFinderCache mod (loc, Nothing)
146 -- -----------------------------------------------------------------------------
147 -- The two external entry points
150 findModule :: DynFlags -> Module -> Bool -> IO FindResult
151 findModule = cached True findModule'
153 findPackageModule :: DynFlags -> Module -> Bool -> IO FindResult
154 findPackageModule = cached False findPackageModule'
156 -- -----------------------------------------------------------------------------
157 -- The internal workers
159 findModule' :: DynFlags -> Module -> IO LocalFindResult
160 -- Find home or package module
161 findModule' dflags name = do
162 r <- findPackageModule' dflags name
164 Failed pkg_files -> do
165 j <- findHomeModule' dflags name
168 return (Failed (home_files ++ pkg_files))
170 -> return other_result
172 -> return other_result
174 findHomeModule' :: DynFlags -> Module -> IO LocalFindResult
175 findHomeModule' dflags mod = do
176 let home_path = importPaths dflags
177 hisuf <- readIORef v_Hi_suf
178 mode <- readIORef v_GhcMode
182 [ ("hs", mkHomeModLocationSearched mod "hs")
183 , ("lhs", mkHomeModLocationSearched mod "lhs")
186 hi_exts = [ (hisuf, mkHiOnlyModLocation hisuf)
187 , (addBootSuffix hisuf, mkHiOnlyModLocation hisuf)
190 -- In compilation manager modes, we look for source files in the home
191 -- package because we can compile these automatically. In one-shot
192 -- compilation mode we look for .hi and .hi-boot files only.
194 | DoMkDependHS <- mode = source_exts
195 | isCompManagerMode mode = source_exts
196 | otherwise {-one-shot-} = hi_exts
198 searchPathExts home_path mod exts
200 findPackageModule' :: DynFlags -> Module -> IO LocalFindResult
201 findPackageModule' dflags mod
202 = case moduleToPackageConfig dflags mod of
203 Nothing -> return (Failed [])
204 Just pkg_info -> findPackageIface mod pkg_info
206 findPackageIface :: Module -> (PackageConfig,Bool) -> IO LocalFindResult
207 findPackageIface mod pkg_info@(pkg_conf, _) = do
208 mode <- readIORef v_GhcMode
209 tag <- readIORef v_Build_tag
211 -- hi-suffix for packages depends on the build tag.
212 package_hisuf | null tag = "hi"
213 | otherwise = tag ++ "_hi"
216 mkPackageModLocation pkg_info package_hisuf) ]
219 [ ("hs", mkPackageModLocation pkg_info package_hisuf)
220 , ("lhs", mkPackageModLocation pkg_info package_hisuf)
223 -- mkdependHS needs to look for source files in packages too, so
224 -- that we can make dependencies between package before they have
227 | DoMkDependHS <- mode = hi_exts ++ source_exts
228 | otherwise = hi_exts
229 -- we never look for a .hi-boot file in an external package;
230 -- .hi-boot files only make sense for the home package.
232 searchPathExts (importDirs pkg_conf) mod exts
234 -- -----------------------------------------------------------------------------
235 -- General path searching
238 :: [FilePath] -- paths to search
239 -> Module -- module name
242 FilePath -> BaseName -> IO FinderCacheEntry -- action
245 -> IO LocalFindResult
247 searchPathExts paths mod exts
248 = do result <- search to_search
250 hPutStrLn stderr (showSDoc $
251 vcat [text "Search" <+> ppr mod <+> sep (map (text. fst) exts)
252 , nest 2 (vcat (map text paths))
254 Succeeded (loc, p) -> text "Found" <+> ppr loc
255 Failed fs -> text "not found"])
260 basename = dots_to_slashes (moduleUserString mod)
262 to_search :: [(FilePath, IO FinderCacheEntry)]
263 to_search = [ (file, fn path basename)
266 let base | path == "." = basename
267 | otherwise = path ++ '/':basename
268 file = base ++ '.':ext
271 search [] = return (Failed (map fst to_search))
272 search ((file, mk_result) : rest) = do
273 b <- doesFileExist file
275 then do { res <- mk_result; return (Succeeded res) }
278 mkHomeModLocationSearched :: Module -> FileExt
279 -> FilePath -> BaseName -> IO FinderCacheEntry
280 mkHomeModLocationSearched mod suff path basename = do
281 loc <- mkHomeModLocation2 mod (path ++ '/':basename) suff
282 return (loc, Nothing)
284 mkHiOnlyModLocation :: FileExt -> FilePath -> BaseName -> IO FinderCacheEntry
285 mkHiOnlyModLocation hisuf path basename = do
286 loc <- hiOnlyModLocation path basename hisuf
287 return (loc, Nothing)
289 mkPackageModLocation :: (PackageConfig, Bool) -> FileExt
290 -> FilePath -> BaseName -> IO FinderCacheEntry
291 mkPackageModLocation pkg_info hisuf path basename = do
292 loc <- hiOnlyModLocation path basename hisuf
293 return (loc, Just pkg_info)
295 -- -----------------------------------------------------------------------------
296 -- Constructing a home module location
298 -- This is where we construct the ModLocation for a module in the home
299 -- package, for which we have a source file. It is called from three
302 -- (a) Here in the finder, when we are searching for a module to import,
303 -- using the search path (-i option).
305 -- (b) The compilation manager, when constructing the ModLocation for
306 -- a "root" module (a source file named explicitly on the command line
307 -- or in a :load command in GHCi).
309 -- (c) The driver in one-shot mode, when we need to construct a
310 -- ModLocation for a source file named on the command-line.
315 -- The name of the module
318 -- (a): The search path component where the source file was found.
322 -- (a): dots_to_slashes (moduleNameUserString mod)
323 -- (b) and (c): The filename of the source file, minus its extension
326 -- The filename extension of the source file (usually "hs" or "lhs").
328 mkHomeModLocation :: Module -> FilePath -> IO ModLocation
329 mkHomeModLocation mod src_filename = do
330 let (basename,extension) = splitFilename src_filename
331 mkHomeModLocation2 mod basename extension
333 mkHomeModLocation2 :: Module
334 -> FilePath -- Of source module, without suffix
337 mkHomeModLocation2 mod src_basename ext = do
338 let mod_basename = dots_to_slashes (moduleUserString mod)
340 obj_fn <- mkObjPath src_basename mod_basename
341 hi_fn <- mkHiPath src_basename mod_basename
343 return (ModLocation{ ml_hs_file = Just (src_basename ++ '.':ext),
345 ml_obj_file = obj_fn })
347 hiOnlyModLocation :: FilePath -> String -> Suffix -> IO ModLocation
348 hiOnlyModLocation path basename hisuf
349 = do let full_basename = path++'/':basename
350 obj_fn <- mkObjPath full_basename basename
351 return ModLocation{ ml_hs_file = Nothing,
352 ml_hi_file = full_basename ++ '.':hisuf,
353 -- Remove the .hi-boot suffix from
354 -- hi_file, if it had one. We always
355 -- want the name of the real .hi file
356 -- in the ml_hi_file field.
360 -- | Constructs the filename of a .o file for a given source file.
361 -- Does /not/ check whether the .o file exists
363 :: FilePath -- the filename of the source file, minus the extension
364 -> String -- the module name with dots replaced by slashes
366 mkObjPath basename mod_basename
367 = do odir <- readIORef v_Output_dir
368 osuf <- readIORef v_Object_suf
370 let obj_basename | Just dir <- odir = dir ++ '/':mod_basename
371 | otherwise = basename
373 return (obj_basename ++ '.':osuf)
375 -- | Constructs the filename of a .hi file for a given source file.
376 -- Does /not/ check whether the .hi file exists
378 :: FilePath -- the filename of the source file, minus the extension
379 -> String -- the module name with dots replaced by slashes
381 mkHiPath basename mod_basename
382 = do hidir <- readIORef v_Hi_dir
383 hisuf <- readIORef v_Hi_suf
385 let hi_basename | Just dir <- hidir = dir ++ '/':mod_basename
386 | otherwise = basename
388 return (hi_basename ++ '.':hisuf)
391 -- -----------------------------------------------------------------------------
392 -- findLinkable isn't related to the other stuff in here,
393 -- but there's no other obvious place for it
395 findLinkable :: Module -> ModLocation -> IO (Maybe Linkable)
396 findLinkable mod locn
397 = do let obj_fn = ml_obj_file locn
398 obj_exist <- doesFileExist obj_fn
402 do let stub_fn = case splitFilename3 obj_fn of
403 (dir, base, ext) -> dir ++ "/" ++ base ++ "_stub.o"
404 stub_exist <- doesFileExist stub_fn
405 obj_time <- getModificationTime obj_fn
407 then return (Just (LM obj_time mod [DotO obj_fn, DotO stub_fn]))
408 else return (Just (LM obj_time mod [DotO obj_fn]))
410 -- -----------------------------------------------------------------------------
413 dots_to_slashes = map (\c -> if c == '.' then '/' else c)
416 -- -----------------------------------------------------------------------------
419 cantFindError :: DynFlags -> Module -> FindResult -> SDoc
420 cantFindError dflags mod_name find_result
421 = hang (ptext SLIT("Could not find module") <+> quotes (ppr mod_name) <> colon)
425 = case find_result of
427 -> ptext SLIT("it is a member of package") <+> ppr pkg <> comma
428 <+> ptext SLIT("which is hidden")
431 -> ptext SLIT("it is hidden") <+> parens (ptext SLIT("in package")
436 -> ptext SLIT("it is not a module in the current program, or in any known package.")
437 | verbosity dflags < 3
438 -> ptext SLIT("use -v to see a list of the files searched for")
440 -> hang (ptext SLIT("locations searched:"))
441 2 (vcat (map text files))
443 Found _ _ -> panic "cantFindErr"