summaryrefslogtreecommitdiff
path: root/compiler/GHC/Iface
diff options
context:
space:
mode:
authorMatthew Pickering <matthewtpickering@gmail.com>2021-05-05 14:02:37 +0100
committerMatthew Pickering <matthewtpickering@gmail.com>2021-06-03 08:46:47 +0100
commit25977ab542a30df4ae71d9699d015bcdd1ab7cfb (patch)
treefc2195f9ceb5651603aa5fed03580eb47e0412d7 /compiler/GHC/Iface
parent79d12d34ad7177d33b191305f2c0157349f97355 (diff)
downloadhaskell-25977ab542a30df4ae71d9699d015bcdd1ab7cfb.tar.gz
Driver Rework Patch
This patch comprises of four different but closely related ideas. The net result is fixing a large number of open issues with the driver whilst making it simpler to understand. 1. Use the hash of the source file to determine whether the source file has changed or not. This makes the recompilation checking more robust to modern build systems which are liable to copy files around changing their modification times. 2. Remove the concept of a "stable module", a stable module was one where the object file was older than the source file, and all transitive dependencies were also stable. Now we don't rely on the modification time of the source file, the notion of stability is moot. 3. Fix TH/plugin recompilation after the removal of stable modules. The TH recompilation check used to rely on stable modules. Now there is a uniform and simple way, we directly track the linkables which were loaded into the interpreter whilst compiling a module. This is an over-approximation but more robust wrt package dependencies changing. 4. Fix recompilation checking for dynamic object files. Now we actually check if the dynamic object file exists when compiling with -dynamic-too Fixes #19774 #19771 #19758 #17434 #11556 #9121 #8211 #16495 #7277 #16093
Diffstat (limited to 'compiler/GHC/Iface')
-rw-r--r--compiler/GHC/Iface/Binary.hs35
-rw-r--r--compiler/GHC/Iface/Load.hs6
-rw-r--r--compiler/GHC/Iface/Make.hs26
-rw-r--r--compiler/GHC/Iface/Recomp.hs183
4 files changed, 156 insertions, 94 deletions
diff --git a/compiler/GHC/Iface/Binary.hs b/compiler/GHC/Iface/Binary.hs
index b248158ef8..8e6fb6f5b7 100644
--- a/compiler/GHC/Iface/Binary.hs
+++ b/compiler/GHC/Iface/Binary.hs
@@ -13,6 +13,7 @@ module GHC.Iface.Binary (
-- * Public API for interface file serialisation
writeBinIface,
readBinIface,
+ readBinIfaceHeader,
getSymtabName,
getDictFastString,
CheckHiWay(..),
@@ -49,6 +50,7 @@ import GHC.Types.SrcLoc
import GHC.Platform
import GHC.Data.FastString
import GHC.Settings.Constants
+import GHC.Utils.Fingerprint
import Data.Array
import Data.Array.IO
@@ -69,15 +71,17 @@ data TraceBinIFace
= TraceBinIFace (SDoc -> IO ())
| QuietBinIFace
--- | Read an interface file.
-readBinIface
+-- | Read an interface file header, checking the magic number, version, and
+-- way. Returns the hash of the source file and a BinHandle which points at the
+-- start of the rest of the interface file data.
+readBinIfaceHeader
:: Profile
-> NameCache
-> CheckHiWay
-> TraceBinIFace
-> FilePath
- -> IO ModIface
-readBinIface profile name_cache checkHiWay traceBinIFace hi_path = do
+ -> IO (Fingerprint, BinHandle)
+readBinIfaceHeader profile _name_cache checkHiWay traceBinIFace hi_path = do
let platform = profilePlatform profile
wantedGot :: String -> a -> a -> (a -> SDoc) -> IO ()
@@ -118,6 +122,20 @@ readBinIface profile name_cache checkHiWay traceBinIFace hi_path = do
when (checkHiWay == CheckHiWay) $
errorOnMismatch "mismatched interface file profile tag" tag check_tag
+ src_hash <- get bh
+ pure (src_hash, bh)
+
+-- | Read an interface file.
+readBinIface
+ :: Profile
+ -> NameCache
+ -> CheckHiWay
+ -> TraceBinIFace
+ -> FilePath
+ -> IO ModIface
+readBinIface profile name_cache checkHiWay traceBinIface hi_path = do
+ (src_hash, bh) <- readBinIfaceHeader profile name_cache checkHiWay traceBinIface hi_path
+
extFields_p <- get bh
mod_iface <- getWithUserData name_cache bh
@@ -125,8 +143,10 @@ readBinIface profile name_cache checkHiWay traceBinIFace hi_path = do
seekBin bh extFields_p
extFields <- get bh
- return mod_iface{mi_ext_fields = extFields}
-
+ return mod_iface
+ { mi_ext_fields = extFields
+ , mi_src_hash = src_hash
+ }
-- | This performs a get action after reading the dictionary and symbol
-- table. It is necessary to run this before trying to deserialise any
@@ -166,10 +186,11 @@ writeBinIface profile traceBinIface hi_path mod_iface = do
let platform = profilePlatform profile
put_ bh (binaryInterfaceMagic platform)
- -- The version and profile tag go next
+ -- The version, profile tag, and source hash go next
put_ bh (show hiVersion)
let tag = profileBuildTag profile
put_ bh tag
+ put_ bh (mi_src_hash mod_iface)
extFields_p_p <- tellBin bh
put_ bh extFields_p_p
diff --git a/compiler/GHC/Iface/Load.hs b/compiler/GHC/Iface/Load.hs
index 89480c6112..2afba91a6c 100644
--- a/compiler/GHC/Iface/Load.hs
+++ b/compiler/GHC/Iface/Load.hs
@@ -1107,6 +1107,7 @@ pprModIface unit_state iface@ModIface{ mi_final_exts = exts }
, nest 2 (text "opt_hash:" <+> ppr (mi_opt_hash exts))
, nest 2 (text "hpc_hash:" <+> ppr (mi_hpc_hash exts))
, nest 2 (text "plugin_hash:" <+> ppr (mi_plugin_hash exts))
+ , nest 2 (text "src_hash:" <+> ppr (mi_src_hash iface))
, nest 2 (text "sig of:" <+> ppr (mi_sig_of iface))
, nest 2 (text "used TH splices:" <+> ppr (mi_used_th iface))
, nest 2 (text "where")
@@ -1168,6 +1169,8 @@ pprUsage usage@UsageFile{}
ppr (usg_file_hash usage)]
pprUsage usage@UsageMergedRequirement{}
= hsep [text "merged", ppr (usg_mod usage), ppr (usg_mod_hash usage)]
+pprUsage usage@UsageHomeModuleInterface{}
+ = hsep [text "implementation", ppr (usg_mod_name usage), ppr (usg_iface_hash usage)]
pprUsageImport :: Outputable a => Usage -> (Usage -> a) -> SDoc
pprUsageImport usage usg_mod'
@@ -1185,14 +1188,13 @@ pprDeps unit_state (Deps { dep_direct_mods = dmods
, dep_direct_pkgs = pkgs
, dep_trusted_pkgs = tps
, dep_finsts = finsts
- , dep_plgins = plugins })
+ })
= pprWithUnitState unit_state $
vcat [text "direct module dependencies:" <+> fsep (map ppr_mod dmods),
text "boot module dependencies:" <+> fsep (map ppr bmods),
text "direct package dependencies:" <+> fsep (map ppr_pkg pkgs),
if null tps then empty else text "trusted package dependencies:" <+> fsep (map ppr_pkg pkgs),
text "orphans:" <+> fsep (map ppr orphs),
- text "plugins:" <+> fsep (map ppr plugins),
text "family instance modules:" <+> fsep (map ppr finsts)
]
where
diff --git a/compiler/GHC/Iface/Make.hs b/compiler/GHC/Iface/Make.hs
index 416cd56d9e..86ff68272d 100644
--- a/compiler/GHC/Iface/Make.hs
+++ b/compiler/GHC/Iface/Make.hs
@@ -89,6 +89,7 @@ import GHC.Unit.Module.Warnings
import GHC.Unit.Module.ModIface
import GHC.Unit.Module.ModDetails
import GHC.Unit.Module.ModGuts
+import GHC.Unit.Module.ModSummary
import GHC.Unit.Module.Deps
import Data.Function
@@ -96,6 +97,7 @@ import Data.List ( findIndex, mapAccumL, sortBy )
import Data.Ord
import Data.IORef
+
{-
************************************************************************
* *
@@ -106,9 +108,10 @@ import Data.IORef
mkPartialIface :: HscEnv
-> ModDetails
+ -> ModSummary
-> ModGuts
-> PartialModIface
-mkPartialIface hsc_env mod_details
+mkPartialIface hsc_env mod_details mod_summary
ModGuts{ mg_module = this_mod
, mg_hsc_src = hsc_src
, mg_usages = usages
@@ -125,7 +128,7 @@ mkPartialIface hsc_env mod_details
, mg_arg_docs = arg_docs
}
= mkIface_ hsc_env this_mod hsc_src used_th deps rdr_env fix_env warns hpc_info self_trust
- safe_mode usages doc_hdr decl_docs arg_docs mod_details
+ safe_mode usages doc_hdr decl_docs arg_docs mod_summary mod_details
-- | Fully instantiate an interface. Adds fingerprints and potentially code
-- generator produced information.
@@ -177,9 +180,10 @@ updateDecl decls (Just CgInfos{ cgNonCafs = NonCaffySet non_cafs, cgLFInfos = lf
mkIfaceTc :: HscEnv
-> SafeHaskellMode -- The safe haskell mode
-> ModDetails -- gotten from mkBootModDetails, probably
+ -> ModSummary
-> TcGblEnv -- Usages, deprecations, etc
-> IO ModIface
-mkIfaceTc hsc_env safe_mode mod_details
+mkIfaceTc hsc_env safe_mode mod_details mod_summary
tc_result@TcGblEnv{ tcg_mod = this_mod,
tcg_src = hsc_src,
tcg_imports = imports,
@@ -196,7 +200,8 @@ mkIfaceTc hsc_env safe_mode mod_details
let pluginModules = map lpModule (hsc_plugins hsc_env)
let home_unit = hsc_home_unit hsc_env
deps <- mkDependencies (homeUnitId home_unit)
- (map mi_module pluginModules) tc_result
+ (map mi_module pluginModules)
+ tc_result
let hpc_info = emptyHpcInfo other_hpc_info
used_th <- readIORef tc_splice_used
dep_files <- (readIORef dependent_files)
@@ -207,8 +212,8 @@ mkIfaceTc hsc_env safe_mode mod_details
-- but if you pass that in here, we'll decide it's the local
-- module and does not need to be recorded as a dependency.
-- See Note [Identity versus semantic module]
- usages <- mkUsageInfo hsc_env this_mod (imp_mods imports) used_names
- dep_files merged pluginModules
+ usages <- mkUsageInfo hsc_env this_mod hsc_src (imp_mods imports) used_names
+ dep_files merged
(doc_hdr', doc_map, arg_map) <- extractDocs tc_result
@@ -217,7 +222,7 @@ mkIfaceTc hsc_env safe_mode mod_details
used_th deps rdr_env
fix_env warns hpc_info
(imp_trust_own_pkg imports) safe_mode usages
- doc_hdr' doc_map arg_map
+ doc_hdr' doc_map arg_map mod_summary
mod_details
mkFullIface hsc_env partial_iface Nothing
@@ -231,12 +236,13 @@ mkIface_ :: HscEnv -> Module -> HscSource
-> Maybe HsDocString
-> DeclDocMap
-> ArgDocMap
+ -> ModSummary
-> ModDetails
-> PartialModIface
mkIface_ hsc_env
this_mod hsc_src used_th deps rdr_env fix_env src_warns
hpc_info pkg_trust_req safe_mode usages
- doc_hdr decl_docs arg_docs
+ doc_hdr decl_docs arg_docs mod_summary
ModDetails{ md_insts = insts,
md_fam_insts = fam_insts,
md_rules = rules,
@@ -313,7 +319,9 @@ mkIface_ hsc_env
mi_decl_docs = decl_docs,
mi_arg_docs = arg_docs,
mi_final_exts = (),
- mi_ext_fields = emptyExtensibleFields }
+ mi_ext_fields = emptyExtensibleFields,
+ mi_src_hash = ms_hs_hash mod_summary
+ }
where
cmp_rule = lexicalCompareFS `on` ifRuleName
-- Compare these lexicographically by OccName, *not* by unique,
diff --git a/compiler/GHC/Iface/Recomp.hs b/compiler/GHC/Iface/Recomp.hs
index 392085f309..ee47ec97ee 100644
--- a/compiler/GHC/Iface/Recomp.hs
+++ b/compiler/GHC/Iface/Recomp.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE TupleSections #-}
-- | Module for detecting if recompilation is required
module GHC.Iface.Recomp
@@ -49,7 +50,6 @@ import GHC.Types.SrcLoc
import GHC.Types.Unique
import GHC.Types.Unique.Set
import GHC.Types.Fixity.Env
-import GHC.Types.SourceFile
import GHC.Unit.External
import GHC.Unit.Finder
@@ -66,10 +66,13 @@ import Data.Function
import Data.List (sortBy, sort)
import qualified Data.Map as Map
import Data.Word (Word64)
+import Data.Either
--Qualified import so we can define a Semigroup instance
-- but it doesn't clash with Outputable.<>
import qualified Data.Semigroup
+import GHC.List (uncons)
+import Data.Ord
{-
-----------------------------------------------
@@ -107,11 +110,11 @@ data RecompileRequired
= UpToDate
-- ^ everything is up to date, recompilation is not required
| MustCompile
- -- ^ The .hs file has been touched, or the .o/.hi file does not exist
+ -- ^ The .hs file has been modified, or the .o/.hi file does not exist
| RecompBecause String
-- ^ The .o/.hi files are up to date, but something else has changed
-- to force recompilation; the String says what (one-line summary)
- deriving Eq
+ deriving (Eq, Show)
instance Semigroup RecompileRequired where
UpToDate <> r = r
@@ -133,11 +136,10 @@ recompileRequired _ = True
checkOldIface
:: HscEnv
-> ModSummary
- -> SourceModified
-> Maybe ModIface -- Old interface from compilation manager, if any
-> IO (RecompileRequired, Maybe ModIface)
-checkOldIface hsc_env mod_summary source_modified maybe_iface
+checkOldIface hsc_env mod_summary maybe_iface
= do let dflags = hsc_dflags hsc_env
let logger = hsc_logger hsc_env
showPass logger dflags $
@@ -145,16 +147,15 @@ checkOldIface hsc_env mod_summary source_modified maybe_iface
(showPpr dflags $ ms_mod mod_summary) ++
" (use -ddump-hi-diffs for more details)"
initIfaceCheck (text "checkOldIface") hsc_env $
- check_old_iface hsc_env mod_summary source_modified maybe_iface
+ check_old_iface hsc_env mod_summary maybe_iface
check_old_iface
:: HscEnv
-> ModSummary
- -> SourceModified
-> Maybe ModIface
-> IfG (RecompileRequired, Maybe ModIface)
-check_old_iface hsc_env mod_summary src_modified maybe_iface
+check_old_iface hsc_env mod_summary maybe_iface
= let dflags = hsc_dflags hsc_env
logger = hsc_logger hsc_env
getIface =
@@ -180,11 +181,10 @@ check_old_iface hsc_env mod_summary src_modified maybe_iface
src_changed
| gopt Opt_ForceRecomp dflags = True
- | SourceModified <- src_modified = True
| otherwise = False
in do
when src_changed $
- liftIO $ trace_hi_diffs logger dflags (nest 4 $ text "Source file changed or recompilation check turned off")
+ liftIO $ trace_hi_diffs logger dflags (nest 4 $ text "Recompilation check turned off")
case src_changed of
-- If the source has changed and we're in interactive mode,
@@ -209,31 +209,8 @@ check_old_iface hsc_env mod_summary src_modified maybe_iface
-- even in the SourceUnmodifiedAndStable case we
-- should check versions because some packages
-- might have changed or gone away.
- Just iface -> do
- (recomp_reqd, mb_checked_iface) <-
- checkVersions hsc_env mod_summary iface
- return $ case mb_checked_iface of
- Just iface | not (recompileRequired recomp_reqd) ->
- -- If the module used TH splices when it was last
- -- compiled, then the recompilation check is not
- -- accurate enough (#481) and we must ignore
- -- it. However, if the module is stable (none of
- -- the modules it depends on, directly or
- -- indirectly, changed), then we *can* skip
- -- recompilation. This is why the SourceModified
- -- type contains SourceUnmodifiedAndStable, and
- -- it's pretty important: otherwise ghc --make
- -- would always recompile TH modules, even if
- -- nothing at all has changed. Stability is just
- -- the same check that make is doing for us in
- -- one-shot mode.
- let stable = case src_modified of
- SourceUnmodifiedAndStable -> True
- _ -> False
- in if mi_used_th iface && not stable
- then (RecompBecause "TH", mb_checked_iface)
- else (recomp_reqd, mb_checked_iface)
- _ -> (recomp_reqd, mb_checked_iface)
+ Just iface ->
+ checkVersions hsc_env mod_summary iface
-- | Check if a module is still the same 'version'.
--
@@ -259,6 +236,8 @@ checkVersions hsc_env mod_summary iface
-- but we ALSO must make sure the instantiation matches up. See
-- test case bkpcabal04!
; hsc_env <- getTopEnv
+ ; if mi_src_hash iface /= ms_hs_hash mod_summary
+ then return (RecompBecause "Source file changed", Nothing) else do {
; if not (isHomeModule home_unit (mi_module iface))
then return (RecompBecause "-this-unit-id changed", Nothing) else do {
; recomp <- liftIO $ checkFlagHash hsc_env iface
@@ -295,7 +274,7 @@ checkVersions hsc_env mod_summary iface
; recomp <- checkList [checkModUsage (homeUnitAsUnit home_unit) u
| u <- mi_usages iface]
; return (recomp, Just iface)
- }}}}}}}}}}
+ }}}}}}}}}}}
where
logger = hsc_logger hsc_env
dflags = hsc_dflags hsc_env
@@ -389,16 +368,15 @@ checkHsig logger home_unit dflags mod_summary iface = do
checkHie :: DynFlags -> ModSummary -> RecompileRequired
checkHie dflags mod_summary =
let hie_date_opt = ms_hie_date mod_summary
- hs_date = ms_hs_date mod_summary
+ hi_date = ms_iface_date mod_summary
in if not (gopt Opt_WriteHie dflags)
then UpToDate
- else case hie_date_opt of
- Nothing -> RecompBecause "HIE file is missing"
- Just hie_date
- | hie_date < hs_date
+ else case (hie_date_opt, hi_date) of
+ (Nothing, _) -> RecompBecause "HIE file is missing"
+ (Just hie_date, Just hi_date)
+ | hie_date < hi_date
-> RecompBecause "HIE file is out of date"
- | otherwise
- -> UpToDate
+ _ -> UpToDate
-- | Check the flags haven't changed
checkFlagHash :: HscEnv -> ModIface -> IO RecompileRequired
@@ -475,41 +453,69 @@ checkMergedSignatures hsc_env mod_summary iface = do
-- Returns (RecompBecause <textual reason>) if recompilation is required.
checkDependencies :: HscEnv -> ModSummary -> ModIface -> IfG RecompileRequired
checkDependencies hsc_env summary iface
- = liftIO $ checkList (map dep_missing (ms_imps summary ++ ms_srcimps summary))
+ = do
+ res <- liftIO $ fmap sequence $ traverse (\(mb_pkg, L _ mod) ->
+ let reason = moduleNameString mod ++ " changed"
+ in classify reason <$> findImportedModule fc units home_unit dflags mod (mb_pkg))
+ (ms_imps summary ++ ms_srcimps summary)
+ case res of
+ Left recomp -> return recomp
+ Right es -> do
+ let (hs, ps) = partitionEithers es
+ res1 <- liftIO $ check_mods (sort hs) prev_dep_mods
+
+ let allPkgDeps = sortBy (comparing snd) (ps ++ bkpk_units)
+ res2 <- liftIO $ check_packages allPkgDeps prev_dep_pkgs
+ return (res1 `mappend` res2)
where
dflags = hsc_dflags hsc_env
logger = hsc_logger hsc_env
fc = hsc_FC hsc_env
home_unit = hsc_home_unit hsc_env
units = hsc_units hsc_env
- prev_dep_mods = dep_direct_mods (mi_deps iface)
- prev_dep_plgn = dep_plgins (mi_deps iface)
- prev_dep_pkgs = dep_direct_pkgs (mi_deps iface)
-
- dep_missing (mb_pkg, L _ mod) = do
- find_res <- findImportedModule fc units home_unit dflags mod (mb_pkg)
- let reason = moduleNameString mod ++ " changed"
- case find_res of
- Found _ mod
- | isHomeUnit home_unit pkg
- -> if moduleName mod `notElem` map gwib_mod prev_dep_mods ++ prev_dep_plgn
- then do trace_hi_diffs logger dflags $
- text "imported module " <> quotes (ppr mod) <>
- text " not among previous dependencies"
- return (RecompBecause reason)
- else
- return UpToDate
- | otherwise
- -> if toUnitId pkg `notElem` prev_dep_pkgs
- then do trace_hi_diffs logger dflags $
- text "imported module " <> quotes (ppr mod) <>
- text " is from package " <> quotes (ppr pkg) <>
- text ", which is not among previous dependencies"
- return (RecompBecause reason)
- else
- return UpToDate
- where pkg = moduleUnit mod
- _otherwise -> return (RecompBecause reason)
+ prev_dep_mods = map gwib_mod $ dep_direct_mods (mi_deps iface)
+ prev_dep_pkgs = sort (dep_direct_pkgs (mi_deps iface))
+ bkpk_units = map (("Signature",) . indefUnit . instUnitInstanceOf . moduleUnit) (requirementMerges units (moduleName (mi_module iface)))
+
+
+
+ classify _ (Found _ mod)
+ | isHomeUnit home_unit (moduleUnit mod) = Right (Left (moduleName mod))
+ | otherwise = Right (Right (moduleNameString (moduleName mod), toUnitId $ moduleUnit mod))
+ classify reason _ = Left (RecompBecause reason)
+
+ check_mods [] [] = return UpToDate
+ check_mods [] (old:_) = do
+ -- This case can happen when a module is change from HPT to package import
+ trace_hi_diffs logger dflags $
+ text "module no longer " <> quotes (ppr old) <>
+ text "in dependencies"
+ return (RecompBecause (moduleNameString old ++ " removed"))
+ check_mods (new:news) olds
+ | Just (old, olds') <- uncons olds
+ , new == old = check_mods (dropWhile (== new) news) olds'
+ | otherwise = do
+ trace_hi_diffs logger dflags $
+ text "imported module " <> quotes (ppr new) <>
+ text " not among previous dependencies"
+ return (RecompBecause (moduleNameString new ++ " added"))
+
+ check_packages :: [(String, UnitId)] -> [UnitId] -> IO RecompileRequired
+ check_packages [] [] = return UpToDate
+ check_packages [] (old:_) = do
+ trace_hi_diffs logger dflags $
+ text "package " <> quotes (ppr old) <>
+ text "no longer in dependencies"
+ return (RecompBecause (unitString old ++ " removed"))
+ check_packages (new:news) olds
+ | Just (old, olds') <- uncons olds
+ , snd new == old = check_packages (dropWhile ((== (snd new)) . snd) news) olds'
+ | otherwise = do
+ trace_hi_diffs logger dflags $
+ text "imported package " <> quotes (ppr new) <>
+ text " not among previous dependencies"
+ return (RecompBecause ((fst new) ++ " package changed"))
+
needInterface :: Module -> (ModIface -> IO RecompileRequired)
-> IfG RecompileRequired
@@ -569,6 +575,13 @@ checkModUsage _ UsageMergedRequirement{ usg_mod = mod, usg_mod_hash = old_mod_ha
needInterface mod $ \iface -> do
let reason = moduleNameString (moduleName mod) ++ " changed (raw)"
checkModuleFingerprint logger dflags reason old_mod_hash (mi_mod_hash (mi_final_exts iface))
+checkModUsage this_pkg UsageHomeModuleInterface{ usg_mod_name = mod_name, usg_iface_hash = old_mod_hash } = do
+ let mod = mkModule this_pkg mod_name
+ dflags <- getDynFlags
+ logger <- getLogger
+ needInterface mod $ \iface -> do
+ let reason = moduleNameString (moduleName mod) ++ " changed (interface)"
+ checkIfaceFingerprint logger dflags reason old_mod_hash (mi_iface_hash (mi_final_exts iface))
checkModUsage this_pkg UsageHomeModule{
usg_mod_name = mod_name,
@@ -606,7 +619,8 @@ checkModUsage this_pkg UsageHomeModule{
checkModUsage _this_pkg UsageFile{ usg_file_path = file,
- usg_file_hash = old_hash } =
+ usg_file_hash = old_hash,
+ usg_file_label = mlabel } =
liftIO $
handleIO handler $ do
new_hash <- getFileHash file
@@ -614,7 +628,8 @@ checkModUsage _this_pkg UsageFile{ usg_file_path = file,
then return recomp
else return UpToDate
where
- recomp = RecompBecause (file ++ " changed")
+ reason = file ++ " changed"
+ recomp = RecompBecause (fromMaybe reason mlabel)
handler = if debugIsOn
then \e -> pprTrace "UsageFile" (text (show e)) $ return recomp
else \_ -> return recomp -- if we can't find the file, just recompile, don't fail
@@ -635,6 +650,21 @@ checkModuleFingerprint logger dflags reason old_mod_hash new_mod_hash
= out_of_date_hash logger dflags reason (text " Module fingerprint has changed")
old_mod_hash new_mod_hash
+checkIfaceFingerprint
+ :: Logger
+ -> DynFlags
+ -> String
+ -> Fingerprint
+ -> Fingerprint
+ -> IO RecompileRequired
+checkIfaceFingerprint logger dflags reason old_mod_hash new_mod_hash
+ | new_mod_hash == old_mod_hash
+ = up_to_date logger dflags (text "Iface fingerprint unchanged")
+
+ | otherwise
+ = out_of_date_hash logger dflags reason (text " Iface fingerprint has changed")
+ old_mod_hash new_mod_hash
+
------------------------
checkMaybeHash
:: Logger
@@ -1071,12 +1101,14 @@ addFingerprints hsc_env iface0
-- The interface hash depends on:
-- - the ABI hash, plus
+ -- - the source file hash,
-- - the module level annotations,
-- - usages
-- - deps (home and external packages, dependent files)
-- - hpc
iface_hash <- computeFingerprint putNameLiterally
(mod_hash,
+ mi_src_hash iface0,
ann_fn (mkVarOcc "module"), -- See mkIfaceAnnCache
mi_usages iface0,
sorted_deps,
@@ -1171,8 +1203,7 @@ sortDependencies d
dep_trusted_pkgs = sort (dep_trusted_pkgs d),
dep_boot_mods = sort (dep_boot_mods d),
dep_orphs = sortBy stableModuleCmp (dep_orphs d),
- dep_finsts = sortBy stableModuleCmp (dep_finsts d),
- dep_plgins = sortBy (lexicalCompareFS `on` moduleNameFS) (dep_plgins d) }
+ dep_finsts = sortBy stableModuleCmp (dep_finsts d) }
{-
************************************************************************