2 % (c) The University of Glasgow, 2000
4 \section[Finder]{Module Finder}
8 flushFinderCache, -- :: IO ()
10 findModule, -- :: ModuleName
11 -- -> IO (Either [FilePath] (Module, ModLocation))
13 findPackageModule, -- :: ModuleName
14 -- -> IO (Either [FilePath] (Module, ModLocation))
16 mkHomeModLocation, -- :: ModuleName -> FilePath -> IO ModLocation
18 findLinkable, -- :: ModuleName -> ModLocation -> IO (Maybe Linkable)
20 hiBootExt, -- :: String
21 hiBootVerExt, -- :: String
25 #include "HsVersions.h"
28 import UniqFM ( filterUFM )
29 import HscTypes ( Linkable(..), Unlinked(..) )
36 import DATA_IOREF ( IORef, writeIORef, readIORef )
43 -- -----------------------------------------------------------------------------
46 -- The Finder provides a thin filesystem abstraction to the rest of the
47 -- compiler. For a given module, it knows (a) whether the module lives
48 -- in the home package or in another package, so it can make a Module
49 -- from a ModuleName, and (b) where the source, interface, and object
50 -- files for a module live.
52 -- It does *not* know which particular package a module lives in, because
53 -- that information is only contained in the interface file.
55 -- -----------------------------------------------------------------------------
58 GLOBAL_VAR(finder_cache, emptyModuleEnv, ModuleEnv (Module,ModLocation))
60 -- remove all the home modules from the cache; package modules are
61 -- assumed to not move around during a session.
62 flushFinderCache :: IO ()
64 fm <- readIORef finder_cache
65 writeIORef finder_cache (filterUFM (not . isHomeModule . fst) fm)
67 addToFinderCache :: ModuleName -> (Module,ModLocation) -> IO ()
68 addToFinderCache mod_name stuff = do
69 fm <- readIORef finder_cache
70 writeIORef finder_cache (extendModuleEnvByName fm mod_name stuff)
72 lookupFinderCache :: ModuleName -> IO (Maybe (Module,ModLocation))
73 lookupFinderCache mod_name = do
74 fm <- readIORef finder_cache
75 return $! lookupModuleEnvByName fm mod_name
77 -- -----------------------------------------------------------------------------
80 -- This is the main interface to the finder, which maps ModuleNames to
81 -- Modules and ModLocations.
83 -- The Module contains one crucial bit of information about a module:
84 -- whether it lives in the current ("home") package or not (see Module
87 -- The ModLocation contains the names of all the files associated with
88 -- that module: its source file, .hi file, object file, etc.
90 findModule :: ModuleName -> IO (Either [FilePath] (Module, ModLocation))
92 r <- lookupFinderCache name
94 Just result -> return (Right result)
96 j <- maybeHomeModule name
98 Right home_module -> return (Right home_module)
100 r <- findPackageMod name
102 Right pkg_module -> return (Right pkg_module)
103 Left pkg_files -> return (Left (home_files ++ pkg_files))
105 findPackageModule :: ModuleName -> IO (Either [FilePath] (Module, ModLocation))
106 findPackageModule name = do
107 r <- lookupFinderCache name
109 Just result -> return (Right result)
110 Nothing -> findPackageMod name
112 hiBootExt = "hi-boot"
113 hiBootVerExt = "hi-boot-" ++ cHscIfaceFileVersion
115 maybeHomeModule :: ModuleName -> IO (Either [FilePath] (Module, ModLocation))
116 maybeHomeModule mod_name = do
117 home_path <- readIORef v_Import_paths
118 hisuf <- readIORef v_Hi_suf
119 mode <- readIORef v_GhcMode
123 [ ("hs", mkHomeModLocationSearched mod_name)
124 , ("lhs", mkHomeModLocationSearched mod_name)
127 hi_exts = [ (hisuf, mkHiOnlyModLocation hisuf mod_name) ]
130 [ (hiBootVerExt, mkHiOnlyModLocation hisuf mod_name)
131 , (hiBootExt, mkHiOnlyModLocation hisuf mod_name)
134 -- In compilation manager modes, we look for source files in the home
135 -- package because we can compile these automatically. In one-shot
136 -- compilation mode we look for .hi and .hi-boot files only.
138 -- When generating dependencies, we're interested in either category.
141 | mode == DoMkDependHS = hi_exts ++ source_exts ++ boot_exts
142 | isCompManagerMode mode = source_exts
143 | otherwise {-one-shot-} = hi_exts ++ boot_exts
145 searchPathExts home_path mod_name exts
147 -- -----------------------------------------------------------------------------
148 -- Looking for a package module
150 findPackageMod :: ModuleName -> IO (Either [FilePath] (Module, ModLocation))
151 findPackageMod mod_name = do
152 mode <- readIORef v_GhcMode
153 imp_dirs <- getPackageImportPath -- including the 'auto' ones
155 -- hi-suffix for packages depends on the build tag.
157 do tag <- readIORef v_Build_tag
160 else return (tag ++ "_hi")
164 [ (package_hisuf, mkPackageModLocation package_hisuf mod_name) ]
167 [ ("hs", mkPackageModLocation package_hisuf mod_name)
168 , ("lhs", mkPackageModLocation package_hisuf mod_name)
171 -- mkdependHS needs to look for source files in packages too, so
172 -- that we can make dependencies between package before they have
175 | mode == DoMkDependHS = hi_exts ++ source_exts
176 | otherwise = hi_exts
178 -- we never look for a .hi-boot file in an external package;
179 -- .hi-boot files only make sense for the home package.
180 searchPathExts imp_dirs mod_name exts
182 -- -----------------------------------------------------------------------------
183 -- General path searching
186 :: [FilePath] -- paths to search
187 -> ModuleName -- module name
190 String -> String -> String -> IO (Module, ModLocation) -- action
193 -> IO (Either [FilePath] (Module, ModLocation))
195 searchPathExts path mod_name exts = search to_search
197 basename = dots_to_slashes (moduleNameUserString mod_name)
199 to_search :: [(FilePath, IO (Module,ModLocation))]
200 to_search = [ (file, fn p basename ext)
203 let base | p == "." = basename
204 | otherwise = p ++ '/':basename
205 file = base ++ '.':ext
208 search [] = return (Left (map fst to_search))
209 search ((file, result) : rest) = do
210 b <- doesFileExist file
212 then Right `liftM` result
215 -- -----------------------------------------------------------------------------
216 -- Building ModLocations
218 mkHiOnlyModLocation hisuf mod_name path basename _ext = do
219 -- basename == dots_to_slashes (moduleNameUserString mod_name)
220 loc <- hiOnlyModLocation path basename hisuf
221 let result = (mkHomeModule mod_name, loc)
222 addToFinderCache mod_name result
225 mkPackageModLocation hisuf mod_name path basename _ext = do
226 -- basename == dots_to_slashes (moduleNameUserString mod_name)
227 loc <- hiOnlyModLocation path basename hisuf
228 let result = (mkPackageModule mod_name, loc)
229 addToFinderCache mod_name result
232 hiOnlyModLocation path basename hisuf
233 = do let full_basename = path++'/':basename
234 obj_fn <- mkObjPath full_basename basename
235 return ModLocation{ ml_hspp_file = Nothing,
236 ml_hs_file = Nothing,
237 ml_hi_file = full_basename ++ '.':hisuf,
238 -- Remove the .hi-boot suffix from
239 -- hi_file, if it had one. We always
240 -- want the name of the real .hi file
241 -- in the ml_hi_file field.
245 -- -----------------------------------------------------------------------------
246 -- Constructing a home module location
248 -- This is where we construct the ModLocation for a module in the home
249 -- package, for which we have a source file. It is called from three
252 -- (a) Here in the finder, when we are searching for a module to import,
253 -- using the search path (-i option).
255 -- (b) The compilation manager, when constructing the ModLocation for
256 -- a "root" module (a source file named explicitly on the command line
257 -- or in a :load command in GHCi).
259 -- (c) The driver in one-shot mode, when we need to construct a
260 -- ModLocation for a source file named on the command-line.
265 -- The name of the module
268 -- (a): The search path component where the source file was found.
272 -- (a): dots_to_slashes (moduleNameUserString mod_name)
273 -- (b) and (c): The filename of the source file, minus its extension
276 -- The filename extension of the source file (usually "hs" or "lhs").
278 mkHomeModLocation mod_name src_filename = do
279 let (basename,extension) = splitFilename src_filename
280 mkHomeModLocation' mod_name basename extension
282 mkHomeModLocationSearched mod_name path basename ext =
283 mkHomeModLocation' mod_name (path ++ '/':basename) ext
285 mkHomeModLocation' mod_name src_basename ext = do
286 let mod_basename = dots_to_slashes (moduleNameUserString mod_name)
288 obj_fn <- mkObjPath src_basename mod_basename
289 hi_fn <- mkHiPath src_basename mod_basename
291 let result = ( mkHomeModule mod_name,
292 ModLocation{ ml_hspp_file = Nothing,
293 ml_hs_file = Just (src_basename ++ '.':ext),
298 addToFinderCache mod_name result
301 -- | Constructs the filename of a .o file for a given source file.
302 -- Does /not/ check whether the .o file exists
304 :: FilePath -- the filename of the source file, minus the extension
305 -> String -- the module name with dots replaced by slashes
307 mkObjPath basename mod_basename
308 = do odir <- readIORef v_Output_dir
309 osuf <- readIORef v_Object_suf
311 let obj_basename | Just dir <- odir = dir ++ '/':mod_basename
312 | otherwise = basename
314 return (obj_basename ++ '.':osuf)
316 -- | Constructs the filename of a .hi file for a given source file.
317 -- Does /not/ check whether the .hi file exists
319 :: FilePath -- the filename of the source file, minus the extension
320 -> String -- the module name with dots replaced by slashes
322 mkHiPath basename mod_basename
323 = do hidir <- readIORef v_Hi_dir
324 hisuf <- readIORef v_Hi_suf
326 let hi_basename | Just dir <- hidir = dir ++ '/':mod_basename
327 | otherwise = basename
329 return (hi_basename ++ '.':hisuf)
331 -- -----------------------------------------------------------------------------
332 -- findLinkable isn't related to the other stuff in here,
333 -- but there's no other obvious place for it
335 findLinkable :: ModuleName -> ModLocation -> IO (Maybe Linkable)
336 findLinkable mod locn
337 = do let obj_fn = ml_obj_file locn
338 obj_exist <- doesFileExist obj_fn
342 do let stub_fn = case splitFilename3 obj_fn of
343 (dir, base, ext) -> dir ++ "/" ++ base ++ "_stub.o"
344 stub_exist <- doesFileExist stub_fn
345 obj_time <- getModificationTime obj_fn
347 then return (Just (LM obj_time mod [DotO obj_fn, DotO stub_fn]))
348 else return (Just (LM obj_time mod [DotO obj_fn]))
350 -- -----------------------------------------------------------------------------
353 dots_to_slashes = map (\c -> if c == '.' then '/' else c)