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 findLinkable, -- :: ModuleName -> ModLocation -> IO (Maybe Linkable)
15 hiBootExt, -- :: String
16 hiBootVerExt, -- :: String
20 #include "HsVersions.h"
23 import UniqFM ( filterUFM )
24 import HscTypes ( Linkable(..), Unlinked(..), IfacePackage(..) )
31 import CmdLineOpts ( DynFlags(..) )
33 import DATA_IOREF ( IORef, writeIORef, readIORef )
36 import System.Directory
39 import Data.Maybe ( isNothing )
41 -- -----------------------------------------------------------------------------
44 -- The Finder provides a thin filesystem abstraction to the rest of
45 -- the compiler. For a given module, it can tell you where the
46 -- source, interface, and object files for that module live.
48 -- It does *not* know which particular package a module lives in. Use
49 -- Packages.moduleToPackageConfig for that.
51 -- -----------------------------------------------------------------------------
54 GLOBAL_VAR(finder_cache, emptyModuleEnv, ModuleEnv FinderCacheEntry)
56 type FinderCacheEntry = (ModLocation,Maybe (PackageConfig,Bool))
58 -- remove all the home modules from the cache; package modules are
59 -- assumed to not move around during a session.
60 flushFinderCache :: IO ()
62 fm <- readIORef finder_cache
63 writeIORef finder_cache (filterUFM (\(loc,m) -> isNothing m) fm)
65 addToFinderCache :: Module -> FinderCacheEntry -> IO ()
66 addToFinderCache mod_name entry = do
67 fm <- readIORef finder_cache
68 writeIORef finder_cache (extendModuleEnv fm mod_name entry)
70 lookupFinderCache :: Module -> IO (Maybe FinderCacheEntry)
71 lookupFinderCache 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 IfacePackage
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 findModule :: DynFlags -> Module -> Bool -> IO FindResult
101 findModule = cached findModule'
103 findModule' :: DynFlags -> Module -> Bool -> IO FindResult
104 findModule' dflags name explicit = do
105 r <- findPackageModule' dflags name explicit
107 NotFound pkg_files -> do
108 j <- maybeHomeModule dflags name
110 NotFound home_files ->
111 return (NotFound (home_files ++ pkg_files))
113 -> return other_result
115 -> return other_result
117 cached fn dflags name explicit = do
118 m <- lookupFinderCache name
120 Nothing -> fn dflags name explicit
122 | Just err <- visible explicit maybe_pkg -> return err
123 | otherwise -> return (Found loc (pkgInfoToId maybe_pkg))
125 pkgInfoToId :: Maybe (PackageConfig,Bool) -> IfacePackage
126 pkgInfoToId (Just (pkg,_)) = ExternalPackage (mkPackageId (package pkg))
127 pkgInfoToId Nothing = ThisPackage
129 -- Is a module visible or not? Returns Nothing if the import is ok,
130 -- or Just err if there's a visibility error.
131 visible :: Bool -> Maybe (PackageConfig,Bool) -> Maybe FindResult
132 visible explicit maybe_pkg
133 | Nothing <- maybe_pkg = Nothing -- home module ==> YES
134 | not explicit = Nothing -- implicit import ==> YES
135 | Just (pkg, exposed_module) <- maybe_pkg
137 _ | not exposed_module -> Just (ModuleHidden pkgname)
138 | not (exposed pkg) -> Just (PackageHidden pkgname)
139 | otherwise -> Nothing
141 pkgname = packageConfigId pkg
144 hiBootExt = "hi-boot"
145 hiBootVerExt = "hi-boot-" ++ cHscIfaceFileVersion
147 maybeHomeModule :: DynFlags -> Module -> IO FindResult
148 maybeHomeModule dflags mod = do
149 let home_path = importPaths dflags
150 hisuf <- readIORef v_Hi_suf
151 mode <- readIORef v_GhcMode
155 [ ("hs", mkHomeModLocationSearched mod)
156 , ("lhs", mkHomeModLocationSearched mod)
159 hi_exts = [ (hisuf, mkHiOnlyModLocation hisuf mod) ]
162 [ (hiBootVerExt, mkHiOnlyModLocation hisuf mod)
163 , (hiBootExt, mkHiOnlyModLocation hisuf mod)
166 -- In compilation manager modes, we look for source files in the home
167 -- package because we can compile these automatically. In one-shot
168 -- compilation mode we look for .hi and .hi-boot files only.
170 -- When generating dependencies, we're interested in either category.
173 | mode == DoMkDependHS = hi_exts ++ source_exts ++ boot_exts
174 | isCompManagerMode mode = source_exts
175 | otherwise {-one-shot-} = hi_exts ++ boot_exts
177 searchPathExts home_path mod exts
179 -- -----------------------------------------------------------------------------
180 -- Looking for a package module
182 findPackageModule :: DynFlags -> Module -> Bool -> IO FindResult
183 findPackageModule = cached findPackageModule'
185 findPackageModule' :: DynFlags -> Module -> Bool -> IO FindResult
186 findPackageModule' dflags mod explicit = do
187 mode <- readIORef v_GhcMode
189 case moduleToPackageConfig dflags mod of
190 Nothing -> return (NotFound [])
191 pkg_info@(Just (pkg_conf, module_exposed))
192 | Just err <- visible explicit pkg_info -> return err
193 | otherwise -> findPackageIface mode mod paths pkg_info
195 paths = importDirs pkg_conf
201 -> Maybe (PackageConfig,Bool)
203 findPackageIface mode mod imp_dirs pkg_info = do
204 -- hi-suffix for packages depends on the build tag.
206 do tag <- readIORef v_Build_tag
209 else return (tag ++ "_hi")
214 mkPackageModLocation pkg_info package_hisuf mod) ]
217 [ ("hs", mkPackageModLocation pkg_info package_hisuf mod)
218 , ("lhs", mkPackageModLocation pkg_info package_hisuf mod)
221 -- mkdependHS needs to look for source files in packages too, so
222 -- that we can make dependencies between package before they have
225 | mode == DoMkDependHS = hi_exts ++ source_exts
226 | otherwise = hi_exts
228 -- we never look for a .hi-boot file in an external package;
229 -- .hi-boot files only make sense for the home package.
230 searchPathExts imp_dirs mod exts
232 -- -----------------------------------------------------------------------------
233 -- General path searching
236 :: [FilePath] -- paths to search
237 -> Module -- module name
240 String -> String -> String -> IO FindResult -- action
245 searchPathExts path mod exts = search to_search
247 basename = dots_to_slashes (moduleUserString mod)
249 to_search :: [(FilePath, IO FindResult)]
250 to_search = [ (file, fn p basename ext)
253 let base | p == "." = basename
254 | otherwise = p ++ '/':basename
255 file = base ++ '.':ext
258 search [] = return (NotFound (map fst to_search))
259 search ((file, result) : rest) = do
260 b <- doesFileExist file
265 -- -----------------------------------------------------------------------------
266 -- Building ModLocations
268 mkHiOnlyModLocation hisuf mod path basename _ext = do
269 -- basename == dots_to_slashes (moduleNameUserString mod)
270 loc <- hiOnlyModLocation path basename hisuf
271 addToFinderCache mod (loc, Nothing)
272 return (Found loc ThisPackage)
274 mkPackageModLocation pkg_info hisuf mod path basename _ext = do
275 -- basename == dots_to_slashes (moduleNameUserString mod)
276 loc <- hiOnlyModLocation path basename hisuf
277 addToFinderCache mod (loc, pkg_info)
278 return (Found loc (pkgInfoToId pkg_info))
280 hiOnlyModLocation path basename hisuf
281 = do let full_basename = path++'/':basename
282 obj_fn <- mkObjPath full_basename basename
283 return ModLocation{ ml_hspp_file = Nothing,
284 ml_hspp_buf = Nothing,
285 ml_hs_file = Nothing,
286 ml_hi_file = full_basename ++ '.':hisuf,
287 -- Remove the .hi-boot suffix from
288 -- hi_file, if it had one. We always
289 -- want the name of the real .hi file
290 -- in the ml_hi_file field.
294 -- -----------------------------------------------------------------------------
295 -- Constructing a home module location
297 -- This is where we construct the ModLocation for a module in the home
298 -- package, for which we have a source file. It is called from three
301 -- (a) Here in the finder, when we are searching for a module to import,
302 -- using the search path (-i option).
304 -- (b) The compilation manager, when constructing the ModLocation for
305 -- a "root" module (a source file named explicitly on the command line
306 -- or in a :load command in GHCi).
308 -- (c) The driver in one-shot mode, when we need to construct a
309 -- ModLocation for a source file named on the command-line.
314 -- The name of the module
317 -- (a): The search path component where the source file was found.
321 -- (a): dots_to_slashes (moduleNameUserString mod)
322 -- (b) and (c): The filename of the source file, minus its extension
325 -- The filename extension of the source file (usually "hs" or "lhs").
327 mkHomeModLocation mod src_filename = do
328 let (basename,extension) = splitFilename src_filename
329 mkHomeModLocation' mod basename extension
331 mkHomeModLocationSearched mod path basename ext = do
332 loc <- mkHomeModLocation' mod (path ++ '/':basename) ext
333 return (Found loc ThisPackage)
335 mkHomeModLocation' mod src_basename ext = do
336 let mod_basename = dots_to_slashes (moduleUserString mod)
338 obj_fn <- mkObjPath src_basename mod_basename
339 hi_fn <- mkHiPath src_basename mod_basename
341 let loc = ModLocation{ ml_hspp_file = Nothing,
342 ml_hspp_buf = Nothing,
343 ml_hs_file = Just (src_basename ++ '.':ext),
345 ml_obj_file = obj_fn }
347 addToFinderCache mod (loc, Nothing)
350 -- | Constructs the filename of a .o file for a given source file.
351 -- Does /not/ check whether the .o file exists
353 :: FilePath -- the filename of the source file, minus the extension
354 -> String -- the module name with dots replaced by slashes
356 mkObjPath basename mod_basename
357 = do odir <- readIORef v_Output_dir
358 osuf <- readIORef v_Object_suf
360 let obj_basename | Just dir <- odir = dir ++ '/':mod_basename
361 | otherwise = basename
363 return (obj_basename ++ '.':osuf)
365 -- | Constructs the filename of a .hi file for a given source file.
366 -- Does /not/ check whether the .hi file exists
368 :: FilePath -- the filename of the source file, minus the extension
369 -> String -- the module name with dots replaced by slashes
371 mkHiPath basename mod_basename
372 = do hidir <- readIORef v_Hi_dir
373 hisuf <- readIORef v_Hi_suf
375 let hi_basename | Just dir <- hidir = dir ++ '/':mod_basename
376 | otherwise = basename
378 return (hi_basename ++ '.':hisuf)
380 -- -----------------------------------------------------------------------------
381 -- findLinkable isn't related to the other stuff in here,
382 -- but there's no other obvious place for it
384 findLinkable :: Module -> ModLocation -> IO (Maybe Linkable)
385 findLinkable mod locn
386 = do let obj_fn = ml_obj_file locn
387 obj_exist <- doesFileExist obj_fn
391 do let stub_fn = case splitFilename3 obj_fn of
392 (dir, base, ext) -> dir ++ "/" ++ base ++ "_stub.o"
393 stub_exist <- doesFileExist stub_fn
394 obj_time <- getModificationTime obj_fn
396 then return (Just (LM obj_time mod [DotO obj_fn, DotO stub_fn]))
397 else return (Just (LM obj_time mod [DotO obj_fn]))
399 -- -----------------------------------------------------------------------------
402 dots_to_slashes = map (\c -> if c == '.' then '/' else c)