Skip to content

Commit cf36960

Browse files
authored
Fixes redundant hash in ghcide cache path (getCacheDirsDefault) (#4854)
1 parent 298cf98 commit cf36960

2 files changed

Lines changed: 49 additions & 20 deletions

File tree

ghcide/session-loader/Development/IDE/Session.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ data SessionLoadingOptions = SessionLoadingOptions
223223
-- | Given the project name and a set of command line flags,
224224
-- return the path for storing generated GHC artifacts,
225225
-- or 'Nothing' to respect the cradle setting
226-
, getCacheDirs :: String -> [String] -> IO CacheDirs
226+
, getCacheDirs :: String -> Maybe B.ByteString -> [String] -> IO CacheDirs
227227
-- | Return the GHC lib dir to use for the 'unsafeGlobalDynFlags'
228228
, getInitialGhcLibDir :: Recorder (WithPriority Log) -> FilePath -> IO (Maybe LibDir)
229229
}

ghcide/session-loader/Development/IDE/Session/Ghc.hs

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import GHC.Types.Error (errMsgDiagnostic,
5858
singleMessage)
5959
import GHC.Unit.State
6060

61+
6162
#if MIN_VERSION_ghc(9,13,0)
6263
import 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
8496
data 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)
213227
setOptions 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

284299
addComponentInfo ::
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

434463
setNameCache :: NameCache -> HscEnv -> HscEnv
435464
setNameCache nc hsc = hsc { hsc_NC = nc }

0 commit comments

Comments
 (0)