@@ -58,6 +58,7 @@ import GHC.Types.Error (errMsgDiagnostic,
5858 singleMessage )
5959import GHC.Unit.State
6060
61+
6162#if MIN_VERSION_ghc(9,13,0)
6263import GHC.Driver.Make (checkHomeUnitsClosed )
6364#endif
@@ -79,7 +80,18 @@ instance Pretty Log where
7980 " New component cache HscEnvEq:" <+> viaShow componentCache
8081 LogDLLLoadError errorString ->
8182 " Error dynamically loading libm.so.6:" <+> pretty errorString
82-
83+ -- | Configuration info for a particular home unit.
84+ data HomeUnitConfig = HomeUnitConfig
85+ {
86+ -- | The dynamic flags to compile this specific unit.
87+ homeUnitDynFlags :: DynFlags
88+ -- | All the targets for this unit.
89+ , homeUnitTargets :: [GHC. Target ]
90+ -- | Optional hash seed to differentiate home units
91+ -- with same `-this-unit-id`. Used when `-this-unit-id` is "main",
92+ -- which is common when loading a single target.
93+ , homeUnitHash :: Maybe B. ByteString
94+ }
8395-- This is pristine information about a component
8496data RawComponentInfo = RawComponentInfo
8597 { rawComponentUnitId :: UnitId
@@ -95,6 +107,8 @@ data RawComponentInfo = RawComponentInfo
95107 -- | Maps cradle dependencies, such as `stack.yaml`, or `.cabal` file
96108 -- to last modification time. See Note [Multi Cradle Dependency Info].
97109 , rawComponentDependencyInfo :: DependencyInfo
110+ -- | An optional hash seed generated in 'setOptions' for the unit id "main".
111+ , rawComponentHash :: Maybe B. ByteString
98112 }
99113
100114-- This is processed information about the component, in particular the dynflags will be modified.
@@ -209,13 +223,13 @@ setOptions :: GhcMonad m
209223 -> ComponentOptions
210224 -> DynFlags
211225 -> FilePath -- ^ root dir, see Note [Root Directory]
212- -> m (NonEmpty ( DynFlags , [ GHC. Target ]) )
226+ -> m (NonEmpty HomeUnitConfig )
213227setOptions haddockOpt cfp (ComponentOptions theOpts compRoot _) dflags rootDir = do
214228 ((theOpts',_errs,_warns),units) <- processCmdLineP unit_flags [] (map noLoc theOpts)
215229 case NE. nonEmpty units of
216230 Just us -> initMulti us
217231 Nothing -> do
218- (df, targets) <- initOne (map unLoc theOpts')
232+ (HomeUnitConfig df targets mHash ) <- initOne (map unLoc theOpts')
219233 -- A special target for the file which caused this wonderful
220234 -- component to be created. In case the cradle doesn't list all the targets for
221235 -- the component, in which case things will be horribly broken anyway.
@@ -235,7 +249,7 @@ setOptions haddockOpt cfp (ComponentOptions theOpts compRoot _) dflags rootDir =
235249 -- we will report it as an error for that file
236250 let abs_fp = toAbsolute rootDir (fromNormalizedFilePath cfp)
237251 let special_target = Compat. mkSimpleTarget df abs_fp
238- pure $ (df, special_target : targets) :| []
252+ pure $ HomeUnitConfig df ( special_target : targets) mHash :| []
239253 where
240254 initMulti unitArgFiles =
241255 forM unitArgFiles $ \ f -> do
@@ -246,7 +260,7 @@ setOptions haddockOpt cfp (ComponentOptions theOpts compRoot _) dflags rootDir =
246260 initOne $ HieBios. removeRTS $ HieBios. removeVerbosityOpts args
247261 initOne this_opts = do
248262 (dflags', targets') <- addCmdOpts this_opts dflags
249- let dflags'' =
263+ let ( dflags'',mHash) =
250264 case unitIdString (homeUnitId_ dflags') of
251265 -- cabal uses main for the unit id of all executable packages
252266 -- This makes multi-component sessions confused about what
@@ -255,10 +269,11 @@ setOptions haddockOpt cfp (ComponentOptions theOpts compRoot _) dflags rootDir =
255269 -- This works because there won't be any dependencies on the
256270 -- executable unit.
257271 " main" ->
258- let hash = B. unpack $ B16. encode $ H. finalize $ H. updates H. init (map B. pack this_opts)
272+ let hashBytes = H. finalize $ H. updates H. init (map B. pack this_opts)
273+ hash = B. unpack $ B16. encode hashBytes
259274 hashed_uid = Compat. toUnitId (Compat. stringToUnit (" main-" ++ hash))
260- in setHomeUnitId_ hashed_uid dflags'
261- _ -> dflags'
275+ in ( setHomeUnitId_ hashed_uid dflags', Just hashBytes)
276+ _ -> ( dflags', Nothing )
262277
263278 let targets = makeTargetsAbsolute root targets'
264279 root = case workingDirectory dflags'' of
@@ -279,14 +294,14 @@ setOptions haddockOpt cfp (ComponentOptions theOpts compRoot _) dflags rootDir =
279294 Compat. setUpTypedHoles $
280295 makeDynFlagsAbsolute compRoot -- makeDynFlagsAbsolute already accounts for workingDirectory
281296 dflags''
282- return (dflags''', targets)
297+ return (HomeUnitConfig dflags''' targets mHash )
283298
284299addComponentInfo ::
285300 MonadUnliftIO m =>
286301 Recorder (WithPriority Log ) ->
287- (String -> [String ] -> IO CacheDirs ) ->
302+ (String -> Maybe B. ByteString -> [String ] -> IO CacheDirs ) ->
288303 DependencyInfo ->
289- NonEmpty ( DynFlags , [ GHC. Target ]) ->
304+ NonEmpty HomeUnitConfig ->
290305 (Maybe FilePath , NormalizedFilePath , ComponentOptions ) ->
291306 Map. Map (Maybe FilePath ) [RawComponentInfo ] ->
292307 m (Map. Map (Maybe FilePath ) [RawComponentInfo ], ([ComponentInfo ], [ComponentInfo ]))
@@ -298,15 +313,15 @@ addComponentInfo recorder getCacheDirs dep_info newDynFlags (hieYaml, cfp, opts)
298313 -- We will modify the unitId and DynFlags used for
299314 -- compilation but these are the true source of
300315 -- information.
301- new_deps = fmap (\ (df, targets) -> RawComponentInfo (homeUnitId_ df) df targets cfp opts dep_info) newDynFlags
316+ new_deps = fmap (\ (HomeUnitConfig df targets mHash ) -> RawComponentInfo (homeUnitId_ df) df targets cfp opts dep_info mHash ) newDynFlags
302317 all_deps = new_deps `NE.appendList` fromMaybe [] oldDeps
303318 -- Get all the unit-ids for things in this component
304319
305320 all_deps' <- forM all_deps $ \ RawComponentInfo {.. } -> do
306321 let prefix = show rawComponentUnitId
307322 -- See Note [Avoiding bad interface files]
308323 let cacheDirOpts = componentOptions opts
309- cacheDirs <- liftIO $ getCacheDirs prefix cacheDirOpts
324+ cacheDirs <- liftIO $ getCacheDirs prefix rawComponentHash cacheDirOpts
310325 processed_df <- setCacheDirs recorder cacheDirs rawComponentDynFlags
311326 -- The final component information, mostly the same but the DynFlags don't
312327 -- contain any packages which are also loaded
@@ -422,14 +437,28 @@ setCacheDirs recorder CacheDirs{..} dflags = do
422437 & maybe id setHieDir hieCacheDir
423438 & maybe id setODir oCacheDir
424439
425- getCacheDirsDefault :: String -> [String ] -> IO CacheDirs
426- getCacheDirsDefault prefix opts = do
427- dir <- Just <$> getXdgDirectory XdgCache (cacheDir </> prefix ++ " -" ++ opts_hash)
440+ -- | Append the hash to the unit id to create unique cache folders.
441+ --
442+ -- This function generates a single, unified hash.
443+ -- If an optional base hash (@mFirstHash@) is provided—which
444+ -- is common for a single target with `-this-unit-id` as "main"-
445+ -- we set the prefix to "main", extract the context generated
446+ -- from the @mFirstHash@, and update the @opts@ into the same hash.
447+ --
448+ -- This guarantees a unique cache folder for different GHC
449+ -- options(avoiding incompatible interface files) while
450+ -- keeping the path short and clean.
451+ getCacheDirsDefault :: String -> Maybe B. ByteString -> [String ] -> IO CacheDirs
452+ getCacheDirsDefault prefix mFirstHash opts = do
453+ dir <- Just <$> getXdgDirectory XdgCache (cacheDir </> prefix' ++ " -" ++ opts_hash)
428454 return $ CacheDirs dir dir dir
429455 where
430- -- Create a unique folder per set of different GHC options, assuming that each different set of
431- -- GHC options will create incompatible interface files.
432- opts_hash = B. unpack $ B16. encode $ H. finalize $ H. updates H. init (map B. pack opts)
456+ -- Create a unique folder per set of different GHC options.
457+ prefix' = if isJust mFirstHash then " main" else prefix
458+ basectx = case mFirstHash of
459+ Just h -> H. updates H. init [h]
460+ Nothing -> H. init
461+ opts_hash = B. unpack $ B16. encode $ H. finalize $ H. updates basectx (map B. pack opts)
433462
434463setNameCache :: NameCache -> HscEnv -> HscEnv
435464setNameCache nc hsc = hsc { hsc_NC = nc }
0 commit comments