[project @ 2002-11-11 10:58:40 by simonpj]
[ghc-hetmet.git] / ghc / compiler / ghci / Linker.lhs
index 2b45436..a3dc62e 100644 (file)
@@ -16,8 +16,8 @@ necessary.
 {-# OPTIONS -optc-DNON_POSIX_SOURCE #-}
 
 module Linker ( HValue, initLinker, showLinkerState,
-               linkPackages, linkLibraries,
-               linkModules, unload, extendLinkEnv, linkExpr,
+               linkLibraries, linkExpr,
+               unload, extendLinkEnv, 
                LibrarySpec(..)
        ) where
 
@@ -33,16 +33,18 @@ import ByteCodeAsm  ( CompiledByteCode(..), bcosFreeNames,
 import Packages                ( PackageConfig(..), PackageName, PackageConfigMap, lookupPkg,
                          packageDependents, packageNameString )
 import DriverState     ( v_Library_paths, v_Cmdline_libraries, getPackageConfigMap )
-
+import Finder          ( findModule, findLinkable )
 import HscTypes                ( Linkable(..), isObjectLinkable, nameOfObject, byteCodeOfObject,
-                         Unlinked(..), isInterpretable, isObject,
+                         Unlinked(..), isInterpretable, isObject, Dependencies(..),
                          HscEnv(..), PersistentCompilerState(..), ExternalPackageState(..),
-                         HomePackageTable, PackageIfaceTable, ModIface(..), HomeModInfo(..) )
+                         HomePackageTable, PackageIfaceTable, ModIface(..), HomeModInfo(..),
+                         lookupIface )
 import Name            ( Name,  nameModule, isExternalName )
 import NameEnv
 import NameSet         ( nameSetToList )
-import Module          ( Module, ModuleName, moduleName, lookupModuleEnvByName )
+import Module          ( ModLocation(..), Module, ModuleName, isHomeModule, moduleName, lookupModuleEnvByName )
 import FastString      ( FastString(..), unpackFS )
+import ListSetOps      ( minusList )
 import CmdLineOpts     ( DynFlags(verbosity) )
 import BasicTypes      ( SuccessFlag(..), succeeded, failed )
 import Outputable
@@ -54,10 +56,10 @@ import ErrUtils             ( Message )
 import Control.Monad   ( when, filterM, foldM )
 
 import Data.IORef      ( IORef, readIORef, writeIORef )
-import Data.List       ( partition )
+import Data.List       ( partition, nub )
 
 import System.IO       ( putStr, putStrLn, hPutStrLn, stderr, fixIO )
-import System.Directory        ( doesFileExist )
+import System.Directory        ( doesFileExist, getModificationTime )
 
 import Control.Exception ( block, throwDyn )
 
@@ -176,11 +178,11 @@ linkExpr :: HscEnv -> PersistentCompilerState
 -- dependents to link.
 
 linkExpr hsc_env pcs (root_ul_bco, aux_ul_bcos)
-   =   -- Find what packages and linkables are required
-     case getLinkDeps hpt pit needed_mods of {
-       Left msg -> dieWith (msg $$ ptext SLIT("When linking an expression")) ;
-       Right (lnks, pkgs) -> do {
+  = do {  
+       -- Find what packages and linkables are required
+     (lnks, pkgs) <- getLinkDeps hpt pit needed_mods ;
 
+       -- Link the packages and modules required
      linkPackages dflags pkgs
    ; ok <-  linkModules dflags lnks
    ; if failed ok then
@@ -195,7 +197,7 @@ linkExpr hsc_env pcs (root_ul_bco, aux_ul_bcos)
        -- Link the necessary packages and linkables
    ; (_, (root_hval:_)) <- linkSomeBCOs False ie ce all_bcos
    ; return root_hval
-   }}}
+   }}
    where
      pit    = eps_PIT (pcs_EPS pcs)
      hpt    = hsc_HPT hsc_env
@@ -209,45 +211,70 @@ linkExpr hsc_env pcs (root_ul_bco, aux_ul_bcos)
 dieWith msg = throwDyn (UsageError (showSDoc msg))
 
 getLinkDeps :: HomePackageTable -> PackageIfaceTable
-           -> [Module]                                 -- If you need these
-           -> Either Message
-                     ([Linkable], [PackageName])       -- ... then link these first
+           -> [Module]                         -- If you need these
+           -> IO ([Linkable], [PackageName])   -- ... then link these first
+-- Fails with an IO exception if it can't find enough files
 
+getLinkDeps hpt pit mods
 -- Find all the packages and linkables that a set of modules depends on
+ = do {        pls <- readIORef v_PersistentLinkerState ;
+       let {
+       -- 1.  Find the dependent home-pkg-modules/packages from each iface
+           (mods_s, pkgs_s) = unzip (map get_deps mods) ;
+
+       -- 2.  Exclude ones already linked
+       --      Main reason: avoid findModule calls in get_linkable
+           mods_needed = nub (concat mods_s) `minusList` linked_mods     ;
+           pkgs_needed = nub (concat pkgs_s) `minusList` pkgs_loaded pls ;
+
+           linked_mods = map linkableModName (objs_loaded pls ++ bcos_loaded pls)
+       } ;
+       
+       -- 3.  For each dependent module, find its linkable
+       --     This will either be in the HPT or (in the case of one-shot compilation)
+       --     we may need to use maybe_getFileLinkable
+       lnks_needed <- mapM get_linkable mods_needed ;
 
-getLinkDeps hpt pit mods
-  = go []      -- Linkables so far
-       []      -- Packages so far
-       []      -- Modules dealt with
-       (map moduleName mods)   -- The usage info that we use for 
-                               -- dependencies has ModuleNames not Modules
+       return (lnks_needed, pkgs_needed) }
   where
-     go lnks pkgs _        [] = Right (lnks,pkgs)
-     go lnks pkgs mods_done (mod:mods) 
-       | mod `elem` mods_done 
-       =       -- Already dealt with
-         go lnks pkgs mods_done mods   
-
-       | Just mod_info <- lookupModuleEnvByName hpt mod 
-       =       -- OK, so it's a home module
-         let
-            mod_deps = [m | (m,_,_,_) <- mi_usages (hm_iface mod_info)]
-               -- Get the modules that this one depends on
-         in
-         go (hm_linkable mod_info : lnks) pkgs (mod : mods_done) (mod_deps ++ mods)
-
-       | Just pkg_iface <- lookupModuleEnvByName pit mod 
-       =       -- It's a package module, so add it to the package list
-         let
-            pkg_name = mi_package pkg_iface
-            pkgs' | pkg_name `elem` pkgs = pkgs
-                  | otherwise            = pkg_name : pkgs
-         in
-         go lnks pkgs' (mod : mods_done) mods
-
+    get_deps :: Module -> ([ModuleName],[PackageName])
+       -- Get the things needed for the specified module
+       -- This is rather similar to the code in RnNames.importsFromImportDecl
+    get_deps mod
+       | isHomeModule (mi_module iface) 
+       = (moduleName mod : [m | (m,_) <- dep_mods deps], dep_pkgs deps)
        | otherwise
-       =       -- Not in either table
-         Left (ptext SLIT("Can't find compiled code for dependent module") <+> ppr mod)
+       = ([], mi_package iface : dep_pkgs deps)
+       where
+         iface = get_iface mod
+         deps  = mi_deps iface
+
+    get_iface mod = case lookupIface hpt pit mod of
+                           Just iface -> iface
+                           Nothing    -> pprPanic "getLinkDeps" (no_iface mod)
+    no_iface mod = ptext SLIT("No iface for") <+> ppr mod
+       -- This one is a GHC bug
+
+    no_obj mod = dieWith (ptext SLIT("No compiled code for") <+> ppr mod)
+       -- This one is a build-system bug
+
+    get_linkable mod_name      -- A home-package module
+       | Just mod_info <- lookupModuleEnvByName hpt mod_name 
+       = return (hm_linkable mod_info)
+       | otherwise     
+       =       -- It's not in the HPT because we are in one shot mode, 
+               -- so use the Finder to get a ModLocation...
+         do { mb_stuff <- findModule mod_name ;
+              case mb_stuff of {
+                 Nothing -> no_obj mod_name ;
+                 Just (_, loc) -> do {
+
+               -- ...and then find the linkable for it
+              mb_lnk <- findLinkable mod_name loc ;
+              case mb_lnk of {
+                 Nothing -> no_obj mod_name ;
+                 Just lnk -> return lnk
+         }}}} 
 \end{code}                       
 
 
@@ -610,6 +637,13 @@ linkPackages :: DynFlags -> [PackageName] -> IO ()
 -- (unless of course they are already linked)
 -- The dependents are linked automatically, and it doesn't matter
 -- what order you specify the input packages.
+--
+-- NOTE: in fact, since each module tracks all the packages it depends on,
+--      we don't really need to use the package-config dependencies.
+-- However we do need the package-config stuff (to find aux libs etc),
+-- and following them lets us load libraries in the right order, which 
+-- perhaps makes the error message a bit more localised if we get a link
+-- failure.  So the dependency walking code is still here.
 
 linkPackages dflags new_pkgs
    = do        { pls     <- readIORef v_PersistentLinkerState