summaryrefslogtreecommitdiff
path: root/compiler/GHC/Linker
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/GHC/Linker')
-rw-r--r--compiler/GHC/Linker/Loader.hs122
-rw-r--r--compiler/GHC/Linker/Types.hs58
2 files changed, 104 insertions, 76 deletions
diff --git a/compiler/GHC/Linker/Loader.hs b/compiler/GHC/Linker/Loader.hs
index ccd3879910..8535bc83f2 100644
--- a/compiler/GHC/Linker/Loader.hs
+++ b/compiler/GHC/Linker/Loader.hs
@@ -15,6 +15,7 @@ module GHC.Linker.Loader
, initLoaderState
, uninitializedLoader
, showLoaderState
+ , getLoaderState
-- * Load & Unload
, loadExpr
, loadDecls
@@ -98,7 +99,7 @@ import qualified Data.Set as Set
import Data.Char (isSpace)
import Data.Function ((&))
import Data.IORef
-import Data.List (intercalate, isPrefixOf, isSuffixOf, nub, partition)
+import Data.List (intercalate, isPrefixOf, isSuffixOf, nub, partition, find)
import Data.Maybe
import Control.Concurrent.MVar
import qualified Control.Monad.Catch as MC
@@ -113,6 +114,8 @@ import System.Win32.Info (getSystemDirectory)
#endif
import GHC.Utils.Exception
+import qualified Data.Map as M
+import Data.Either (partitionEithers)
uninitialised :: a
uninitialised = panic "Loader not initialised"
@@ -128,6 +131,10 @@ modifyLoaderState interp f =
(fmapFst pure . f . fromMaybe uninitialised)
where fmapFst f = fmap (\(x, y) -> (f x, y))
+getLoaderState :: Interp -> IO (Maybe LoaderState)
+getLoaderState interp = readMVar (loader_state (interpLoader interp))
+
+
emptyLoaderState :: LoaderState
emptyLoaderState = LoaderState
{ closure_env = emptyNameEnv
@@ -135,6 +142,9 @@ emptyLoaderState = LoaderState
, pkgs_loaded = init_pkgs
, bcos_loaded = []
, objs_loaded = []
+ , hs_objs_loaded = []
+ , non_hs_objs_loaded = []
+ , module_deps = M.empty
, temp_sos = []
}
-- Packages that don't need loading, because the compiler
@@ -166,14 +176,14 @@ deleteFromLoadedEnv interp to_remove =
-- | Load the module containing the given Name and get its associated 'HValue'.
--
-- Throws a 'ProgramError' if loading fails or the name cannot be found.
-loadName :: Interp -> HscEnv -> Name -> IO ForeignHValue
-loadName interp hsc_env name = do
+loadName :: Interp -> HscEnv -> Maybe ModuleNameWithIsBoot -> Name -> IO ForeignHValue
+loadName interp hsc_env mnwib name = do
initLoaderState interp hsc_env
modifyLoaderState interp $ \pls0 -> do
pls <- if not (isExternalName name)
then return pls0
else do
- (pls', ok) <- loadDependencies interp hsc_env pls0 noSrcSpan
+ (pls', ok) <- loadDependencies interp hsc_env pls0 (noSrcSpan, mnwib)
[nameModule name]
if failed ok
then throwGhcExceptionIO (ProgramError "")
@@ -194,7 +204,7 @@ loadDependencies
:: Interp
-> HscEnv
-> LoaderState
- -> SrcSpan -> [Module]
+ -> (SrcSpan, Maybe ModuleNameWithIsBoot) -> [Module]
-> IO (LoaderState, SuccessFlag)
loadDependencies interp hsc_env pls span needed_mods = do
-- initLoaderState (hsc_dflags hsc_env) dl
@@ -204,15 +214,20 @@ loadDependencies interp hsc_env pls span needed_mods = do
-- the "normal" way, i.e. no non-std ways like profiling or ticky-ticky.
-- So here we check the build tag: if we're building a non-standard way
-- then we need to find & link object files built the "normal" way.
- maybe_normal_osuf <- checkNonStdWay dflags interp span
+ maybe_normal_osuf <- checkNonStdWay dflags interp (fst span)
-- Find what packages and linkables are required
- (lnks, pkgs) <- getLinkDeps hsc_env hpt pls
- maybe_normal_osuf span needed_mods
+ (lnks, all_lnks, pkgs) <- getLinkDeps hsc_env hpt pls
+ maybe_normal_osuf (fst span) needed_mods
+
+ let pls1 =
+ case (snd span) of
+ Just mn -> pls { module_deps = M.insertWith (++) mn all_lnks (module_deps pls) }
+ Nothing -> pls
-- Link the packages and modules required
- pls1 <- loadPackages' interp hsc_env pkgs pls
- loadModules interp hsc_env pls1 lnks
+ pls2 <- loadPackages' interp hsc_env pkgs pls1
+ loadModules interp hsc_env pls2 lnks
-- | Temporarily extend the loaded env.
@@ -547,7 +562,7 @@ preloadLib interp hsc_env lib_paths framework_paths pls lib_spec = do
-- Raises an IO exception ('ProgramError') if it can't find a compiled
-- version of the dependents to load.
--
-loadExpr :: Interp -> HscEnv -> SrcSpan -> UnlinkedBCO -> IO ForeignHValue
+loadExpr :: Interp -> HscEnv -> (SrcSpan, Maybe ModuleNameWithIsBoot) -> UnlinkedBCO -> IO ForeignHValue
loadExpr interp hsc_env span root_ul_bco = do
-- Initialise the linker (if it's not been done already)
initLoaderState interp hsc_env
@@ -636,7 +651,7 @@ getLinkDeps :: HscEnv -> HomePackageTable
-> Maybe FilePath -- replace object suffices?
-> SrcSpan -- for error messages
-> [Module] -- If you need these
- -> IO ([Linkable], [UnitId]) -- ... then link these first
+ -> IO ([Linkable], [Linkable], [UnitId]) -- ... then link these first
-- Fails with an IO exception if it can't find enough files
getLinkDeps hsc_env hpt pls replace_osuf span mods
@@ -647,14 +662,17 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods
; (mods_s, pkgs_s) <- follow_deps (filterOut isInteractiveModule mods)
emptyUniqDSet emptyUniqDSet;
- ; let {
+ ; let
-- 2. Exclude ones already linked
-- Main reason: avoid findModule calls in get_linkable
- mods_needed = mods_s `minusList` linked_mods ;
- pkgs_needed = pkgs_s `minusList` pkgs_loaded pls ;
+ (mods_needed, mods_got) = partitionEithers (map split_mods mods_s)
+ pkgs_needed = pkgs_s `minusList` pkgs_loaded pls
- linked_mods = map (moduleName.linkableModule)
- (objs_loaded pls ++ bcos_loaded pls) }
+ split_mods mod_name =
+ let is_linked = find ((== mod_name) . (moduleName . linkableModule)) (objs_loaded pls ++ bcos_loaded pls)
+ in case is_linked of
+ Just linkable -> Right linkable
+ Nothing -> Left mod_name
-- 3. For each dependent module, find its linkable
-- This will either be in the HPT or (in the case of one-shot
@@ -662,7 +680,7 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods
; let { osuf = objectSuf dflags }
; lnks_needed <- mapM (get_linkable osuf) mods_needed
- ; return (lnks_needed, pkgs_needed) }
+ ; return (lnks_needed, mods_got ++ lnks_needed, pkgs_needed) }
where
dflags = hsc_dflags hsc_env
@@ -779,7 +797,7 @@ getLinkDeps hsc_env hpt pls replace_osuf span mods
********************************************************************* -}
-loadDecls :: Interp -> HscEnv -> SrcSpan -> CompiledByteCode -> IO ()
+loadDecls :: Interp -> HscEnv -> (SrcSpan, Maybe ModuleNameWithIsBoot) -> CompiledByteCode -> IO ()
loadDecls interp hsc_env span cbc@CompiledByteCode{..} = do
-- Initialise the linker (if it's not been done already)
initLoaderState interp hsc_env
@@ -822,11 +840,11 @@ loadDecls interp hsc_env span cbc@CompiledByteCode{..} = do
********************************************************************* -}
-loadModule :: Interp -> HscEnv -> Module -> IO ()
-loadModule interp hsc_env mod = do
+loadModule :: Interp -> HscEnv -> Maybe ModuleNameWithIsBoot -> Module -> IO ()
+loadModule interp hsc_env mnwib mod = do
initLoaderState interp hsc_env
modifyLoaderState_ interp $ \pls -> do
- (pls', ok) <- loadDependencies interp hsc_env pls noSrcSpan [mod]
+ (pls', ok) <- loadDependencies interp hsc_env pls (noSrcSpan, mnwib) [mod]
if failed ok
then throwGhcExceptionIO (ProgramError "could not load module")
else return pls'
@@ -1184,40 +1202,6 @@ unload_wkr interp keep_linkables pls@LoaderState{..} = do
-- letting go of them (plus of course depopulating
-- the symbol table which is done in the main body)
-{- **********************************************************************
-
- Loading packages
-
- ********************************************************************* -}
-
-data LibrarySpec
- = Objects [FilePath] -- Full path names of set of .o files, including trailing .o
- -- We allow batched loading to ensure that cyclic symbol
- -- references can be resolved (see #13786).
- -- For dynamic objects only, try to find the object
- -- file in all the directories specified in
- -- v_Library_paths before giving up.
-
- | Archive FilePath -- Full path name of a .a file, including trailing .a
-
- | DLL String -- "Unadorned" name of a .DLL/.so
- -- e.g. On unix "qt" denotes "libqt.so"
- -- On Windows "burble" denotes "burble.DLL" or "libburble.dll"
- -- loadDLL is platform-specific and adds the lib/.so/.DLL
- -- suffixes platform-dependently
-
- | DLLPath FilePath -- Absolute or relative pathname to a dynamic library
- -- (ends with .dll or .so).
-
- | Framework String -- Only used for darwin, but does no harm
-
-instance Outputable LibrarySpec where
- ppr (Objects objs) = text "Objects" <+> ppr objs
- ppr (Archive a) = text "Archive" <+> text a
- ppr (DLL s) = text "DLL" <+> text s
- ppr (DLLPath f) = text "DLLPath" <+> text f
- ppr (Framework s) = text "Framework" <+> text s
-
-- If this package is already part of the GHCi binary, we'll already
-- have the right DLLs for this package loaded, so don't try to
-- load them again.
@@ -1263,29 +1247,31 @@ loadPackages interp hsc_env new_pkgs = do
loadPackages' :: Interp -> HscEnv -> [UnitId] -> LoaderState -> IO LoaderState
loadPackages' interp hsc_env new_pks pls = do
- pkgs' <- link (pkgs_loaded pls) new_pks
- return $! pls { pkgs_loaded = pkgs' }
+ (pkgs', hs_objs, non_hs_objs) <- link (pkgs_loaded pls) new_pks
+ return $! pls { pkgs_loaded = pkgs'
+ , hs_objs_loaded = hs_objs ++ hs_objs_loaded pls
+ , non_hs_objs_loaded = non_hs_objs ++ non_hs_objs_loaded pls }
where
- link :: [UnitId] -> [UnitId] -> IO [UnitId]
+ link :: [UnitId] -> [UnitId] -> IO ([UnitId], [LibrarySpec], [LibrarySpec])
link pkgs new_pkgs =
- foldM link_one pkgs new_pkgs
+ foldM link_one (pkgs, [],[]) new_pkgs
- link_one pkgs new_pkg
+ link_one (pkgs, acc_hs, acc_non_hs) new_pkg
| new_pkg `elem` pkgs -- Already linked
- = return pkgs
+ = return (pkgs, acc_hs, acc_non_hs)
| Just pkg_cfg <- lookupUnitId (hsc_units hsc_env) new_pkg
= do { -- Link dependents first
- pkgs' <- link pkgs (unitDepends pkg_cfg)
+ (pkgs', hs_cls', extra_cls') <- link pkgs (unitDepends pkg_cfg)
-- Now link the package itself
- ; loadPackage interp hsc_env pkg_cfg
- ; return (new_pkg : pkgs') }
+ ; (hs_cls, extra_cls) <- loadPackage interp hsc_env pkg_cfg
+ ; return (new_pkg : pkgs', acc_hs ++ hs_cls ++ hs_cls', acc_non_hs ++ extra_cls ++ extra_cls') }
| otherwise
= throwGhcExceptionIO (CmdLineError ("unknown package: " ++ unpackFS (unitIdFS new_pkg)))
-loadPackage :: Interp -> HscEnv -> UnitInfo -> IO ()
+loadPackage :: Interp -> HscEnv -> UnitInfo -> IO ([LibrarySpec], [LibrarySpec])
loadPackage interp hsc_env pkg
= do
let dflags = hsc_dflags hsc_env
@@ -1369,7 +1355,9 @@ loadPackage interp hsc_env pkg
mapM_ (removeLibrarySearchPath interp) $ reverse pathCache
if succeeded ok
- then maybePutStrLn logger dflags "done."
+ then do
+ maybePutStrLn logger dflags "done."
+ return (hs_classifieds, extra_classifieds)
else let errmsg = text "unable to load unit `"
<> pprUnitInfoForUser pkg <> text "'"
in throwGhcExceptionIO (InstallationError (showSDoc dflags errmsg))
diff --git a/compiler/GHC/Linker/Types.hs b/compiler/GHC/Linker/Types.hs
index 728d6a3b06..e0d04f5bfa 100644
--- a/compiler/GHC/Linker/Types.hs
+++ b/compiler/GHC/Linker/Types.hs
@@ -17,13 +17,15 @@ module GHC.Linker.Types
, linkableObjs
, isObject
, nameOfObject
+ , nameOfObject_maybe
, isInterpretable
, byteCodeOfObject
+ , LibrarySpec(..)
)
where
import GHC.Prelude
-import GHC.Unit ( UnitId, Module )
+import GHC.Unit ( UnitId, Module, ModuleNameWithIsBoot )
import GHC.ByteCode.Types ( ItblEnv, CompiledByteCode )
import GHC.Fingerprint.Type ( Fingerprint )
import GHCi.RemoteTypes ( ForeignHValue )
@@ -37,6 +39,8 @@ import GHC.Utils.Panic
import Control.Concurrent.MVar
import Data.Time ( UTCTime )
+import Data.Maybe
+import qualified Data.Map as M
{- **********************************************************************
@@ -81,6 +85,9 @@ data LoaderState = LoaderState
-- ^ The currently-loaded packages; always object code
-- Held, as usual, in dependency order; though I am not sure if
-- that is really important
+ , hs_objs_loaded :: ![LibrarySpec]
+ , non_hs_objs_loaded :: ![LibrarySpec]
+ , module_deps :: M.Map ModuleNameWithIsBoot [Linkable]
, temp_sos :: ![(FilePath, String)]
-- ^ We need to remember the name of previous temporary DLL/.so
@@ -102,10 +109,6 @@ data Linkable = LM {
-- ^ Those files and chunks of code we have yet to link.
--
-- INVARIANT: A valid linkable always has at least one 'Unlinked' item.
- -- If this list is empty, the Linkable represents a fake linkable, which
- -- is generated with no backend is used to avoid recompiling modules.
- --
- -- ToDo: Do items get removed from this list when they get linked?
}
instance Outputable Linkable where
@@ -163,14 +166,51 @@ isObject _ = False
isInterpretable :: Unlinked -> Bool
isInterpretable = not . isObject
+nameOfObject_maybe :: Unlinked -> Maybe FilePath
+nameOfObject_maybe (DotO fn) = Just fn
+nameOfObject_maybe (DotA fn) = Just fn
+nameOfObject_maybe (DotDLL fn) = Just fn
+nameOfObject_maybe (BCOs {}) = Nothing
+
-- | Retrieve the filename of the linkable if possible. Panic if it is a byte-code object
nameOfObject :: Unlinked -> FilePath
-nameOfObject (DotO fn) = fn
-nameOfObject (DotA fn) = fn
-nameOfObject (DotDLL fn) = fn
-nameOfObject other = pprPanic "nameOfObject" (ppr other)
+nameOfObject o = fromMaybe (pprPanic "nameOfObject" (ppr o)) (nameOfObject_maybe o)
-- | Retrieve the compiled byte-code if possible. Panic if it is a file-based linkable
byteCodeOfObject :: Unlinked -> CompiledByteCode
byteCodeOfObject (BCOs bc _) = bc
byteCodeOfObject other = pprPanic "byteCodeOfObject" (ppr other)
+
+{- **********************************************************************
+
+ Loading packages
+
+ ********************************************************************* -}
+
+data LibrarySpec
+ = Objects [FilePath] -- Full path names of set of .o files, including trailing .o
+ -- We allow batched loading to ensure that cyclic symbol
+ -- references can be resolved (see #13786).
+ -- For dynamic objects only, try to find the object
+ -- file in all the directories specified in
+ -- v_Library_paths before giving up.
+
+ | Archive FilePath -- Full path name of a .a file, including trailing .a
+
+ | DLL String -- "Unadorned" name of a .DLL/.so
+ -- e.g. On unix "qt" denotes "libqt.so"
+ -- On Windows "burble" denotes "burble.DLL" or "libburble.dll"
+ -- loadDLL is platform-specific and adds the lib/.so/.DLL
+ -- suffixes platform-dependently
+
+ | DLLPath FilePath -- Absolute or relative pathname to a dynamic library
+ -- (ends with .dll or .so).
+
+ | Framework String -- Only used for darwin, but does no harm
+
+instance Outputable LibrarySpec where
+ ppr (Objects objs) = text "Objects" <+> ppr objs
+ ppr (Archive a) = text "Archive" <+> text a
+ ppr (DLL s) = text "DLL" <+> text s
+ ppr (DLLPath f) = text "DLLPath" <+> text f
+ ppr (Framework s) = text "Framework" <+> text s