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 { obj_fn <- mkObjPath path basename ;
234 return (ModLocation{ ml_hspp_file = Nothing,
235 ml_hs_file = Nothing,
236 ml_hi_file = path ++ '/':basename ++ '.':hisuf,
237 -- Remove the .hi-boot suffix from
238 -- hi_file, if it had one. We always
239 -- want the name of the real .hi file
240 -- in the ml_hi_file field.
244 -- -----------------------------------------------------------------------------
245 -- Constructing a home module location
247 -- This is where we construct the ModLocation for a module in the home
248 -- package, for which we have a source file. It is called from three
251 -- (a) Here in the finder, when we are searching for a module to import,
252 -- using the search path (-i option).
254 -- (b) The compilation manager, when constructing the ModLocation for
255 -- a "root" module (a source file named explicitly on the command line
256 -- or in a :load command in GHCi).
258 -- (c) The driver in one-shot mode, when we need to construct a
259 -- ModLocation for a source file named on the command-line.
264 -- The name of the module
267 -- (a): The search path component where the source file was found.
271 -- (a): dots_to_slashes (moduleNameUserString mod_name)
272 -- (b) and (c): The filename of the source file, minus its extension
275 -- The filename extension of the source file (usually "hs" or "lhs").
277 mkHomeModLocation mod_name src_filename = do
278 let mod_basename = dots_to_slashes (moduleNameUserString mod_name)
279 (basename,extension) = splitFilename src_filename
281 case maybePrefixMatch (reverse mod_basename) (reverse basename) of
283 mkHomeModLocationSearched mod_name "." mod_basename extension
284 Just rest@(r:_) | isPathSeparator r -> do
285 let path = reverse (dropWhile (=='/') rest)
286 mkHomeModLocationSearched mod_name path mod_basename extension
288 -- hPutStrLn stderr ("Warning: " ++ src_filename ++
289 -- ": filename and module name do not match")
290 let (dir,basename,ext) = splitFilename3 src_filename
291 mkHomeModLocationSearched mod_name dir basename ext
293 mkHomeModLocationSearched mod_name path src_basename ext = do
294 hisuf <- readIORef v_Hi_suf
295 hidir <- readIORef v_Hi_dir
297 let mod_basename = dots_to_slashes (moduleNameUserString mod_name)
299 obj_fn <- mkObjPath path mod_basename
301 let -- hi filename, always follows the module name
302 hi_path | Just d <- hidir = d
305 hi_fn = hi_path ++ '/':mod_basename ++ '.':hisuf
308 source_fn = path ++ '/':src_basename ++ '.':ext
310 result = ( mkHomeModule mod_name,
311 ModLocation{ ml_hspp_file = Nothing,
312 ml_hs_file = Just source_fn,
314 ml_obj_file = obj_fn,
317 addToFinderCache mod_name result
320 mkObjPath :: FilePath -> String -> IO FilePath
321 -- Construct the filename of a .o file.
322 -- Does *not* check whether the .o file exists
323 mkObjPath path basename
324 = do odir <- readIORef v_Output_dir
325 osuf <- readIORef v_Object_suf
327 let obj_path | Just d <- odir = d
330 return (obj_path ++ '/':basename ++ '.':osuf)
332 -- -----------------------------------------------------------------------------
333 -- findLinkable isn't related to the other stuff in here,
334 -- but there's no other obvious place for it
336 findLinkable :: ModuleName -> ModLocation -> IO (Maybe Linkable)
337 findLinkable mod locn
338 = do let obj_fn = ml_obj_file locn
339 obj_exist <- doesFileExist obj_fn
343 do let stub_fn = case splitFilename3 obj_fn of
344 (dir, base, ext) -> dir ++ "/" ++ base ++ "_stub.o"
345 stub_exist <- doesFileExist stub_fn
346 obj_time <- getModificationTime obj_fn
348 then return (Just (LM obj_time mod [DotO obj_fn, DotO stub_fn]))
349 else return (Just (LM obj_time mod [DotO obj_fn]))
351 -- -----------------------------------------------------------------------------
354 dots_to_slashes = map (\c -> if c == '.' then '/' else c)