Torsten Schmits pushed to branch wip/torsten.schmits/mercury-ghc910-mhu-transitive-th-deps at Glasgow Haskell Compiler / GHC
Commits:
-
1c80ba27
by Torsten Schmits at 2025-10-30T17:58:26+01:00
3 changed files:
Changes:
| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | module GHC.Linker.Deps
|
| 12 | 12 | ( LinkDepsOpts (..)
|
| 13 | 13 | , LinkDeps (..)
|
| 14 | + , LibraryUnits (..)
|
|
| 14 | 15 | , getLinkDeps
|
| 15 | 16 | )
|
| 16 | 17 | where
|
| ... | ... | @@ -83,10 +84,16 @@ data LinkDepsOpts = LinkDepsOpts |
| 83 | 84 | data LinkDeps = LinkDeps
|
| 84 | 85 | { ldNeededLinkables :: [Linkable]
|
| 85 | 86 | , ldAllLinkables :: [Linkable]
|
| 86 | - , ldNeededUnits :: [UnitId]
|
|
| 87 | + , ldNeededUnits :: [LibraryUnits]
|
|
| 87 | 88 | , ldAllUnits :: UniqDSet UnitId
|
| 88 | 89 | }
|
| 89 | 90 | |
| 91 | +data LibraryUnits
|
|
| 92 | + = LibraryUnits
|
|
| 93 | + { home_unit :: !UnitId
|
|
| 94 | + , library_unit :: !UnitId
|
|
| 95 | + }
|
|
| 96 | + |
|
| 90 | 97 | -- | Find all the packages and linkables that a set of modules depends on
|
| 91 | 98 | --
|
| 92 | 99 | -- Return the module and package dependencies for the needed modules.
|
| ... | ... | @@ -155,10 +162,10 @@ get_link_deps opts pls maybe_normal_osuf span mods = do |
| 155 | 162 | link_mods =
|
| 156 | 163 | listToUDFM [(moduleName (mi_module (hm_iface m)), m) | m <- mmods]
|
| 157 | 164 | link_libs =
|
| 158 | - uniqDSetToList (unionManyUniqDSets (init_pkg_set : pkgs))
|
|
| 165 | + eltsUDFM (foldl' plusUDFM emptyUDFM (init_pkg_set : pkgs))
|
|
| 159 | 166 | pure $
|
| 160 | 167 | LinkModules (LinkHomeModule <$> link_mods) :
|
| 161 | - (LinkLibrary <$> link_libs)
|
|
| 168 | + link_libs
|
|
| 162 | 169 | |
| 163 | 170 | -- This code is used in `--make` mode to calculate the home package and unit dependencies
|
| 164 | 171 | -- for a set of modules.
|
| ... | ... | @@ -168,7 +175,7 @@ get_link_deps opts pls maybe_normal_osuf span mods = do |
| 168 | 175 | |
| 169 | 176 | -- It is also a matter of correctness to use the module graph so that dependencies between home units
|
| 170 | 177 | -- is resolved correctly.
|
| 171 | - make_deps_loop :: (UniqDSet UnitId, Set.Set NodeKey) -> [ModNodeKeyWithUid] -> (UniqDSet UnitId, Set.Set NodeKey)
|
|
| 178 | + make_deps_loop :: (UniqDFM UnitId LinkDep, Set.Set NodeKey) -> [ModNodeKeyWithUid] -> (UniqDFM UnitId LinkDep, Set.Set NodeKey)
|
|
| 172 | 179 | make_deps_loop found [] = found
|
| 173 | 180 | make_deps_loop found@(found_units, found_mods) (nk:nexts)
|
| 174 | 181 | | NodeKey_Module nk `Set.member` found_mods = make_deps_loop found nexts
|
| ... | ... | @@ -176,7 +183,7 @@ get_link_deps opts pls maybe_normal_osuf span mods = do |
| 176 | 183 | case fmap mkNodeKey <$> mgReachable mod_graph (NodeKey_Module nk) of
|
| 177 | 184 | Nothing ->
|
| 178 | 185 | let (ModNodeKeyWithUid _ uid) = nk
|
| 179 | - in make_deps_loop (addOneToUniqDSet found_units uid, found_mods) nexts
|
|
| 186 | + in make_deps_loop (addToUDFM found_units uid (LinkLibrary LibraryUnits {library_unit = uid, home_unit = (ue_current_unit (ldUnitEnv opts))}), found_mods) nexts
|
|
| 180 | 187 | Just trans_deps ->
|
| 181 | 188 | let deps = Set.insert (NodeKey_Module nk) (Set.fromList trans_deps)
|
| 182 | 189 | -- See #936 and the ghci.prog007 test for why we have to continue traversing through
|
| ... | ... | @@ -185,7 +192,7 @@ get_link_deps opts pls maybe_normal_osuf span mods = do |
| 185 | 192 | in make_deps_loop (found_units, deps `Set.union` found_mods) (todo_boot_mods ++ nexts)
|
| 186 | 193 | |
| 187 | 194 | mkNk m = ModNodeKeyWithUid (GWIB (moduleName m) NotBoot) (moduleUnitId m)
|
| 188 | - (init_pkg_set, all_deps) = make_deps_loop (emptyUniqDSet, Set.empty) $ map mkNk (filterOut isInteractiveModule mods)
|
|
| 195 | + (init_pkg_set, all_deps) = make_deps_loop (emptyUDFM, Set.empty) $ map mkNk (filterOut isInteractiveModule mods)
|
|
| 189 | 196 | |
| 190 | 197 | all_home_mods = [with_uid | NodeKey_Module with_uid <- Set.toList all_deps]
|
| 191 | 198 | |
| ... | ... | @@ -195,7 +202,7 @@ get_link_deps opts pls maybe_normal_osuf span mods = do |
| 195 | 202 | let iface = hm_iface hmi
|
| 196 | 203 | case mi_hsc_src iface of
|
| 197 | 204 | HsBootFile -> throwProgramError opts $ link_boot_mod_error (mi_module iface)
|
| 198 | - _ -> pure (mkUniqDSet $ Set.toList $ dep_direct_pkgs (mi_deps iface), hmi)
|
|
| 205 | + _ -> pure (listToUDFM [(u, LinkLibrary LibraryUnits {library_unit = u, home_unit = (moduleUnitId (mi_module iface))}) | u <- Set.toList $ dep_direct_pkgs (mi_deps iface)], hmi)
|
|
| 199 | 206 | Nothing -> throwProgramError opts $
|
| 200 | 207 | text "getLinkDeps: Home module not loaded" <+> ppr (gwib_mod gwib) <+> ppr uid
|
| 201 | 208 | |
| ... | ... | @@ -279,12 +286,13 @@ instance Outputable LinkModule where |
| 279 | 286 | data LinkDep =
|
| 280 | 287 | LinkModules (UniqDFM ModuleName LinkModule)
|
| 281 | 288 | |
|
| 282 | - LinkLibrary UnitId
|
|
| 289 | + LinkLibrary LibraryUnits
|
|
| 283 | 290 | |
| 284 | 291 | instance Outputable LinkDep where
|
| 285 | 292 | ppr = \case
|
| 286 | 293 | LinkModules mods -> text "modules:" <+> ppr (eltsUDFM mods)
|
| 287 | - LinkLibrary uid -> text "library:" <+> ppr uid
|
|
| 294 | + LinkLibrary (LibraryUnits {home_unit, library_unit}) ->
|
|
| 295 | + text "library:" <+> ppr library_unit <+> parens (ppr home_unit)
|
|
| 288 | 296 | |
| 289 | 297 | data OneshotError =
|
| 290 | 298 | NoLocation Module
|
| ... | ... | @@ -337,7 +345,7 @@ oneshot_deps_loop opts (mod : mods) acc = do |
| 337 | 345 | already_seen
|
| 338 | 346 | | Just (LinkModules mods) <- mod_dep
|
| 339 | 347 | = elemUDFM mod_name mods
|
| 340 | - | Just (LinkLibrary _) <- mod_dep
|
|
| 348 | + | Just (LinkLibrary {}) <- mod_dep
|
|
| 341 | 349 | = True
|
| 342 | 350 | | otherwise
|
| 343 | 351 | = False
|
| ... | ... | @@ -362,7 +370,7 @@ oneshot_deps_loop opts (mod : mods) acc = do |
| 362 | 370 | | otherwise
|
| 363 | 371 | = add_library
|
| 364 | 372 | |
| 365 | - add_library = pure (addToUDFM acc mod_unit_id (LinkLibrary mod_unit_id), [])
|
|
| 373 | + add_library = pure (addToUDFM acc mod_unit_id (LinkLibrary LibraryUnits {library_unit = mod_unit_id, home_unit}), [])
|
|
| 366 | 374 | |
| 367 | 375 | add_module iface lmod =
|
| 368 | 376 | (addListToUDFM with_mod (direct_pkgs iface), new_deps iface)
|
| ... | ... | @@ -378,7 +386,7 @@ oneshot_deps_loop opts (mod : mods) acc = do |
| 378 | 386 | | bytecode
|
| 379 | 387 | = []
|
| 380 | 388 | | otherwise
|
| 381 | - = [(u, LinkLibrary u) | u <- Set.toList (dep_direct_pkgs (mi_deps iface))]
|
|
| 389 | + = [(u, LinkLibrary LibraryUnits {library_unit = u, home_unit}) | u <- Set.toList (dep_direct_pkgs (mi_deps iface))]
|
|
| 382 | 390 | |
| 383 | 391 | new_deps iface
|
| 384 | 392 | | bytecode
|
| ... | ... | @@ -418,6 +426,7 @@ oneshot_deps_loop opts (mod : mods) acc = do |
| 418 | 426 | text "due to use of Template Haskell"
|
| 419 | 427 | |
| 420 | 428 | bytecode = ldUseByteCode opts
|
| 429 | + home_unit = homeUnitId (expectJust "oneshot_deps" mb_home)
|
|
| 421 | 430 | mb_home = ue_homeUnit (ldUnitEnv opts)
|
| 422 | 431 | |
| 423 | 432 | link_boot_mod_error :: Module -> SDoc
|
| ... | ... | @@ -428,7 +437,7 @@ link_boot_mod_error mod = |
| 428 | 437 | classify_deps ::
|
| 429 | 438 | LoaderState ->
|
| 430 | 439 | [LinkDep] ->
|
| 431 | - ([Linkable], [LinkModule], UniqDSet UnitId, [UnitId])
|
|
| 440 | + ([Linkable], [LinkModule], UniqDSet UnitId, [LibraryUnits])
|
|
| 432 | 441 | classify_deps pls deps =
|
| 433 | 442 | (loaded_modules, needed_modules, all_packages, needed_packages)
|
| 434 | 443 | where
|
| ... | ... | @@ -436,13 +445,15 @@ classify_deps pls deps = |
| 436 | 445 | partitionWith loaded_or_needed (concatMap eltsUDFM modules)
|
| 437 | 446 | |
| 438 | 447 | needed_packages =
|
| 439 | - eltsUDFM (getUniqDSet all_packages `minusUDFM` pkgs_loaded pls)
|
|
| 448 | + eltsUDFM (packages `minusUDFM` pkgs_loaded pls)
|
|
| 449 | + |
|
| 450 | + packages = listToUDFM [(library_unit p, p) | p <- packages_with_home_units]
|
|
| 440 | 451 | |
| 441 | - all_packages = mkUniqDSet packages
|
|
| 452 | + all_packages = mkUniqDSet (map library_unit packages_with_home_units)
|
|
| 442 | 453 | |
| 443 | - (modules, packages) = flip partitionWith deps $ \case
|
|
| 454 | + (modules, packages_with_home_units) = flip partitionWith deps $ \case
|
|
| 444 | 455 | LinkModules mods -> Left mods
|
| 445 | - LinkLibrary lib -> Right lib
|
|
| 456 | + LinkLibrary units -> Right units
|
|
| 446 | 457 | |
| 447 | 458 | loaded_or_needed lm =
|
| 448 | 459 | maybe (Right lm) Left (loaded_linkable (mi_module (link_module_iface lm)))
|
| ... | ... | @@ -93,8 +93,9 @@ import Control.Monad |
| 93 | 93 | |
| 94 | 94 | import qualified Data.Set as Set
|
| 95 | 95 | import Data.Char (isSpace)
|
| 96 | +import Data.Foldable (for_)
|
|
| 96 | 97 | import Data.IORef
|
| 97 | -import Data.List (intercalate, isPrefixOf, nub, partition)
|
|
| 98 | +import Data.List (intercalate, isPrefixOf, nub, partition, sortOn)
|
|
| 98 | 99 | import Data.Maybe
|
| 99 | 100 | import Control.Concurrent.MVar
|
| 100 | 101 | import qualified Control.Monad.Catch as MC
|
| ... | ... | @@ -109,6 +110,7 @@ import System.Win32.Info (getSystemDirectory) |
| 109 | 110 | #endif
|
| 110 | 111 | |
| 111 | 112 | import GHC.Utils.Exception
|
| 113 | +import qualified Data.List.NonEmpty as NE
|
|
| 112 | 114 | |
| 113 | 115 | -- Note [Linkers and loaders]
|
| 114 | 116 | -- ~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -173,7 +175,7 @@ emptyLoaderState = LoaderState |
| 173 | 175 | --
|
| 174 | 176 | -- The linker's symbol table is populated with RTS symbols using an
|
| 175 | 177 | -- explicit list. See rts/Linker.c for details.
|
| 176 | - where init_pkgs = unitUDFM rtsUnitId (LoadedPkgInfo rtsUnitId [] [] [] emptyUniqDSet)
|
|
| 178 | + where init_pkgs = unitUDFM rtsUnitId (LoadedPkgInfo rtsUnitId Nothing [] [] [] emptyUniqDSet)
|
|
| 177 | 179 | |
| 178 | 180 | extendLoadedEnv :: Interp -> [(Name,ForeignHValue)] -> IO ()
|
| 179 | 181 | extendLoadedEnv interp new_bindings =
|
| ... | ... | @@ -325,9 +327,8 @@ reallyInitLoaderState interp hsc_env = do |
| 325 | 327 | -- (a) initialise the C dynamic linker
|
| 326 | 328 | initObjLinker interp
|
| 327 | 329 | |
| 328 | - |
|
| 329 | 330 | -- (b) Load packages from the command-line (Note [preload packages])
|
| 330 | - pls <- unitEnv_foldWithKey (\k u env -> k >>= \pls' -> loadPackages' interp (hscSetActiveUnitId u hsc_env) (preloadUnits (homeUnitEnv_units env)) pls') (return pls0) (hsc_HUG hsc_env)
|
|
| 331 | + pls <- unitEnv_foldWithKey (\k u env -> k >>= \pls' -> loadPackages' interp hsc_env [LibraryUnits {home_unit = u, library_unit = pre} | pre <- preloadUnits (homeUnitEnv_units env)] pls') (return pls0) (hsc_HUG hsc_env)
|
|
| 331 | 332 | |
| 332 | 333 | -- steps (c), (d) and (e)
|
| 333 | 334 | loadCmdLineLibs' interp hsc_env pls
|
| ... | ... | @@ -855,7 +856,13 @@ dynLoadObjs interp hsc_env pls@LoaderState{..} objs = do |
| 855 | 856 | -- link all "loaded packages" so symbols in those can be resolved
|
| 856 | 857 | -- Note: We are loading packages with local scope, so to see the
|
| 857 | 858 | -- symbols in this link we must link all loaded packages again.
|
| 858 | - linkDynLib logger tmpfs dflags2 unit_env objs (loaded_pkg_uid <$> eltsUDFM pkgs_loaded)
|
|
| 859 | + do
|
|
| 860 | + let groupedLoadedPackageInfos = groupLoadedPackageInfosByParent pkgs_loaded
|
|
| 861 | + for_ groupedLoadedPackageInfos $ \(mParent, loaded_pkg_uids) -> do
|
|
| 862 | + let unit_env' = case mParent of
|
|
| 863 | + Nothing -> unit_env
|
|
| 864 | + Just parent -> ue_setActiveUnit parent unit_env
|
|
| 865 | + linkDynLib logger tmpfs dflags2 unit_env' objs loaded_pkg_uids
|
|
| 859 | 866 | |
| 860 | 867 | -- if we got this far, extend the lifetime of the library file
|
| 861 | 868 | changeTempFilesLifetime tmpfs TFL_GhcSession [soFile]
|
| ... | ... | @@ -866,6 +873,19 @@ dynLoadObjs interp hsc_env pls@LoaderState{..} objs = do |
| 866 | 873 | where
|
| 867 | 874 | msg = "GHC.Linker.Loader.dynLoadObjs: Loading temp shared object failed"
|
| 868 | 875 | |
| 876 | + groupOn :: Eq k => (a -> k) -> [a] -> [NE.NonEmpty a]
|
|
| 877 | + groupOn f = NE.groupBy ((==) `on2` f)
|
|
| 878 | + -- redefine on so we avoid duplicate computation for most values.
|
|
| 879 | + where (.*.) `on2` f = \x -> let fx = f x in \y -> fx .*. f y
|
|
| 880 | + |
|
| 881 | + groupLoadedPackageInfosByParent :: PkgsLoaded -> [(Maybe UnitId, [UnitId])]
|
|
| 882 | + groupLoadedPackageInfosByParent pkgs =
|
|
| 883 | + map (\l -> (loaded_pkg_parent (NE.head l), NE.toList $ NE.map loaded_pkg_uid l))
|
|
| 884 | + $ groupOn loaded_pkg_parent
|
|
| 885 | + $ sortOn loaded_pkg_parent
|
|
| 886 | + $ eltsUDFM pkgs
|
|
| 887 | + |
|
| 888 | + |
|
| 869 | 889 | rmDupLinkables :: LinkableSet -- Already loaded
|
| 870 | 890 | -> [Linkable] -- New linkables
|
| 871 | 891 | -> (LinkableSet, -- New loaded set (including new ones)
|
| ... | ... | @@ -1075,36 +1095,39 @@ loadPackages interp hsc_env new_pkgs = do |
| 1075 | 1095 | -- a lock.
|
| 1076 | 1096 | initLoaderState interp hsc_env
|
| 1077 | 1097 | modifyLoaderState_ interp $ \pls ->
|
| 1078 | - loadPackages' interp hsc_env new_pkgs pls
|
|
| 1098 | + loadPackages' interp hsc_env [LibraryUnits {home_unit = hscActiveUnitId hsc_env, library_unit} | library_unit <- new_pkgs] pls
|
|
| 1079 | 1099 | |
| 1080 | -loadPackages' :: Interp -> HscEnv -> [UnitId] -> LoaderState -> IO LoaderState
|
|
| 1081 | -loadPackages' interp hsc_env new_pks pls = do
|
|
| 1100 | +loadPackages' :: Interp -> HscEnv -> [LibraryUnits] -> LoaderState -> IO LoaderState
|
|
| 1101 | +loadPackages' interp hsc_env0 new_pks pls = do
|
|
| 1082 | 1102 | pkgs' <- link (pkgs_loaded pls) new_pks
|
| 1083 | 1103 | return $! pls { pkgs_loaded = pkgs'
|
| 1084 | 1104 | }
|
| 1085 | 1105 | where
|
| 1086 | - link :: PkgsLoaded -> [UnitId] -> IO PkgsLoaded
|
|
| 1106 | + link :: PkgsLoaded -> [LibraryUnits] -> IO PkgsLoaded
|
|
| 1087 | 1107 | link pkgs new_pkgs =
|
| 1088 | 1108 | foldM link_one pkgs new_pkgs
|
| 1089 | 1109 | |
| 1090 | - link_one pkgs new_pkg
|
|
| 1091 | - | new_pkg `elemUDFM` pkgs -- Already linked
|
|
| 1110 | + link_one pkgs (LibraryUnits {home_unit, library_unit})
|
|
| 1111 | + | library_unit `elemUDFM` pkgs -- Already linked
|
|
| 1092 | 1112 | = return pkgs
|
| 1093 | 1113 | |
| 1094 | - | Just pkg_cfg <- lookupUnitId (hsc_units hsc_env) new_pkg
|
|
| 1114 | + | Just pkg_cfg <- lookupUnitId (hsc_units (hscSetActiveUnitId home_unit hsc_env)) library_unit
|
|
| 1095 | 1115 | = do { let deps = unitDepends pkg_cfg
|
| 1096 | 1116 | -- Link dependents first
|
| 1097 | - ; pkgs' <- link pkgs deps
|
|
| 1117 | + ; pkgs' <- link pkgs [LibraryUnits {home_unit, library_unit} | library_unit <- deps]
|
|
| 1118 | + |
|
| 1098 | 1119 | -- Now link the package itself
|
| 1099 | 1120 | ; (hs_cls, extra_cls, loaded_dlls) <- loadPackage interp hsc_env pkg_cfg
|
| 1100 | 1121 | ; let trans_deps = unionManyUniqDSets [ addOneToUniqDSet (loaded_pkg_trans_deps loaded_pkg_info) dep_pkg
|
| 1101 | 1122 | | dep_pkg <- deps
|
| 1102 | 1123 | , Just loaded_pkg_info <- pure (lookupUDFM pkgs' dep_pkg)
|
| 1103 | 1124 | ]
|
| 1104 | - ; return (addToUDFM pkgs' new_pkg (LoadedPkgInfo new_pkg hs_cls extra_cls loaded_dlls trans_deps)) }
|
|
| 1125 | + ; return (addToUDFM pkgs' library_unit (LoadedPkgInfo library_unit (Just home_unit) hs_cls extra_cls loaded_dlls trans_deps)) }
|
|
| 1105 | 1126 | |
| 1106 | 1127 | | otherwise
|
| 1107 | - = throwGhcExceptionIO (CmdLineError ("unknown package: " ++ unpackFS (unitIdFS new_pkg)))
|
|
| 1128 | + = throwGhcExceptionIO (CmdLineError ("unknown package: " ++ unpackFS (unitIdFS library_unit)))
|
|
| 1129 | + where
|
|
| 1130 | + hsc_env = hscSetActiveUnitId home_unit hsc_env0
|
|
| 1108 | 1131 | |
| 1109 | 1132 | |
| 1110 | 1133 | loadPackage :: Interp -> HscEnv -> UnitInfo -> IO ([LibrarySpec], [LibrarySpec], [RemotePtr LoadedDLL])
|
| ... | ... | @@ -192,6 +192,7 @@ type PkgsLoaded = UniqDFM UnitId LoadedPkgInfo |
| 192 | 192 | data LoadedPkgInfo
|
| 193 | 193 | = LoadedPkgInfo
|
| 194 | 194 | { loaded_pkg_uid :: !UnitId
|
| 195 | + , loaded_pkg_parent :: !(Maybe UnitId)
|
|
| 195 | 196 | , loaded_pkg_hs_objs :: ![LibrarySpec]
|
| 196 | 197 | , loaded_pkg_non_hs_objs :: ![LibrarySpec]
|
| 197 | 198 | , loaded_pkg_hs_dlls :: ![RemotePtr LoadedDLL]
|
| ... | ... | @@ -200,8 +201,9 @@ data LoadedPkgInfo |
| 200 | 201 | }
|
| 201 | 202 | |
| 202 | 203 | instance Outputable LoadedPkgInfo where
|
| 203 | - ppr (LoadedPkgInfo uid hs_objs non_hs_objs _ trans_deps) =
|
|
| 204 | - vcat [ppr uid
|
|
| 204 | + ppr (LoadedPkgInfo uid parent_uid hs_objs non_hs_objs _ trans_deps) =
|
|
| 205 | + vcat [ ppr uid
|
|
| 206 | + , ppr parent_uid
|
|
| 205 | 207 | , ppr hs_objs
|
| 206 | 208 | , ppr non_hs_objs
|
| 207 | 209 | , ppr trans_deps ]
|