@@ -36,6 +36,8 @@ import Distribution.Client.CmdErrorMessages
3636 targetSelectorRefersToPkgs ,
3737 renderComponentKind , renderListCommaAnd , renderListSemiAnd ,
3838 componentKind , sortGroupOn , Plural (.. ) )
39+ import Distribution.Client.Targets
40+ ( UserConstraint (.. ), UserConstraintScope (.. ) )
3941import Distribution.Client.TargetProblem
4042 ( TargetProblem (.. ) )
4143import qualified Distribution.Client.InstallPlan as InstallPlan
@@ -65,9 +67,13 @@ import Distribution.Compiler
6567import Distribution.Simple.Compiler
6668 ( Compiler , compilerCompatVersion )
6769import Distribution.Package
68- ( Package (.. ), packageName , UnitId , installedUnitId )
70+ ( Package (.. ), packageName , mkPackageName , UnitId , installedUnitId )
6971import Distribution.Solver.Types.SourcePackage
7072 ( SourcePackage (.. ) )
73+ import Distribution.Solver.Types.ConstraintSource
74+ ( ConstraintSource (ConstraintSourceMultiRepl ) )
75+ import Distribution.Solver.Types.PackageConstraint
76+ ( PackageProperty (PackagePropertyVersion ) )
7177import Distribution.Types.BuildInfo
7278 ( BuildInfo (.. ), emptyBuildInfo )
7379import Distribution.Types.ComponentName
@@ -81,7 +87,7 @@ import Distribution.Types.Library
8187import Distribution.Types.Version
8288 ( Version , mkVersion )
8389import Distribution.Types.VersionRange
84- ( anyVersion )
90+ ( anyVersion , orLaterVersion )
8591import Distribution.Utils.Generic
8692 ( safeHead )
8793import Distribution.Verbosity
@@ -115,7 +121,7 @@ import Distribution.Client.ReplFlags
115121 topReplOptions )
116122import Distribution.Simple.Flag ( Flag (Flag ), fromFlagOrDefault )
117123import Distribution.Client.ProjectConfig
118- ( ProjectConfigShared (projectConfigMultiRepl ),
124+ ( ProjectConfigShared (projectConfigMultiRepl , projectConfigConstraints ),
119125 ProjectConfig (projectConfigShared ) )
120126
121127
@@ -183,8 +189,8 @@ multiReplDecision ctx compiler flags =
183189-- up to date, selects that part of the plan needed by the given or implicit
184190-- repl target and then executes the plan.
185191--
186- -- Compared to @build@ the difference is that only one target is allowed
187- -- (given or implicit) and the target type is repl rather than build. The
192+ -- Compared to @build@ the difference is that multiple targets are handled
193+ -- specially and the target type is repl rather than build. The
188194-- general plan execution infrastructure handles both build and repl targets.
189195--
190196-- For more details on how this works, see the module
@@ -228,13 +234,24 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
228234
229235 updateContextAndWriteProjectFile ctx scriptPath scriptExecutable
230236
231- (originalComponent, baseCtx') <- if null (envPackages replEnvFlags)
232- then return (Nothing , baseCtx)
237+ -- If multi-repl is used, we need a Cabal recent enough to handle it.
238+ -- We need to do this before solving, but the compiler version is only known
239+ -- after solving (phaseConfigureCompiler), so instead of using
240+ -- multiReplDecision we just check the flag.
241+ let baseCtx' = if fromFlagOrDefault False $
242+ projectConfigMultiRepl (projectConfigShared $ projectConfig baseCtx)
243+ <> replUseMulti
244+ then baseCtx & lProjectConfig . lProjectConfigShared . lProjectConfigConstraints
245+ %~ (multiReplCabalConstraint: )
246+ else baseCtx
247+
248+ (originalComponent, baseCtx'') <- if null (envPackages replEnvFlags)
249+ then return (Nothing , baseCtx')
233250 else
234251 -- Unfortunately, the best way to do this is to let the normal solver
235252 -- help us resolve the targets, but that isn't ideal for performance,
236253 -- especially in the no-project case.
237- withInstallPlan (lessVerbose verbosity) baseCtx $ \ elaboratedPlan sharedConfig -> do
254+ withInstallPlan (lessVerbose verbosity) baseCtx' $ \ elaboratedPlan sharedConfig -> do
238255 -- targets should be non-empty map, but there's no NonEmptyMap yet.
239256 targets <- validatedTargets (projectConfigShared (projectConfig ctx)) (pkgConfigCompiler sharedConfig) elaboratedPlan targetSelectors
240257
@@ -243,9 +260,9 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
243260 originalDeps = installedUnitId <$> InstallPlan. directDeps elaboratedPlan unitId
244261 oci = OriginalComponentInfo unitId originalDeps
245262 pkgId = fromMaybe (error $ " cannot find " ++ prettyShow unitId) $ packageId <$> InstallPlan. lookup elaboratedPlan unitId
246- baseCtx' = addDepsToProjectTarget (envPackages replEnvFlags) pkgId baseCtx
263+ baseCtx'' = addDepsToProjectTarget (envPackages replEnvFlags) pkgId baseCtx'
247264
248- return (Just oci, baseCtx')
265+ return (Just oci, baseCtx'' )
249266
250267 -- Now, we run the solver again with the added packages. While the graph
251268 -- won't actually reflect the addition of transitive dependencies,
@@ -255,9 +272,9 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
255272 -- In addition, to avoid a *third* trip through the solver, we are
256273 -- replicating the second half of 'runProjectPreBuildPhase' by hand
257274 -- here.
258- (buildCtx, compiler, replOpts', targets) <- withInstallPlan verbosity baseCtx' $
275+ (buildCtx, compiler, replOpts', targets) <- withInstallPlan verbosity baseCtx'' $
259276 \ elaboratedPlan elaboratedShared' -> do
260- let ProjectBaseContext {.. } = baseCtx'
277+ let ProjectBaseContext {.. } = baseCtx''
261278
262279 -- Recalculate with updated project.
263280 targets <- validatedTargets (projectConfigShared projectConfig) (pkgConfigCompiler elaboratedShared') elaboratedPlan targetSelectors
@@ -296,7 +313,7 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
296313 -- Multi Repl implemention see: https://well-typed.com/blog/2023/03/cabal-multi-unit/ for
297314 -- a high-level overview about how everything fits together.
298315 if Set. size (distinctTargetComponents targets) > 1
299- then withTempDirectoryEx verbosity (TempFileOptions keepTempFiles) distDir " multi-out- " $ \ dir' -> do
316+ then withTempDirectoryEx verbosity (TempFileOptions keepTempFiles) distDir " multi-out" $ \ dir' -> do
300317 -- multi target repl
301318 dir <- makeAbsolute dir'
302319 -- Modify the replOptions so that the ./Setup repl command will write options
@@ -306,12 +323,12 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
306323 _ -> usingGhciScript compiler projectRoot replOpts'
307324
308325 let buildCtx' = buildCtx & lElaboratedShared . lPkgConfigReplOptions .~ replOpts''
309- printPlan verbosity baseCtx' buildCtx'
326+ printPlan verbosity baseCtx'' buildCtx'
310327
311328 -- The project build phase will call `./Setup repl` but write the options
312329 -- out into a file without starting a repl.
313- buildOutcomes <- runProjectBuildPhase verbosity baseCtx' buildCtx'
314- runProjectPostBuildPhase verbosity baseCtx' buildCtx' buildOutcomes
330+ buildOutcomes <- runProjectBuildPhase verbosity baseCtx'' buildCtx'
331+ runProjectPostBuildPhase verbosity baseCtx'' buildCtx' buildOutcomes
315332
316333 -- calculate PATH, we construct a PATH which is the union of all paths from
317334 -- the units which have been loaded. This is not quite right but usually works fine.
@@ -354,10 +371,10 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
354371 _ -> usingGhciScript compiler projectRoot replOpts'
355372
356373 let buildCtx' = buildCtx & lElaboratedShared . lPkgConfigReplOptions .~ replOpts''
357- printPlan verbosity baseCtx' buildCtx'
374+ printPlan verbosity baseCtx'' buildCtx'
358375
359- buildOutcomes <- runProjectBuildPhase verbosity baseCtx' buildCtx'
360- runProjectPostBuildPhase verbosity baseCtx' buildCtx' buildOutcomes
376+ buildOutcomes <- runProjectBuildPhase verbosity baseCtx'' buildCtx'
377+ runProjectPostBuildPhase verbosity baseCtx'' buildCtx' buildOutcomes
361378 where
362379
363380 combine_search_paths paths =
@@ -391,6 +408,17 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
391408
392409 return targets
393410
411+ -- This is the constraint setup.Cabal>=3.11. 3.11 is when Cabal options
412+ -- used for multi-repl were introduced.
413+ -- Idelly we'd apply this constraint only on the closure of repl targets,
414+ -- but that would require another solver run for marginal advantages that
415+ -- will further shrink as 3.11 is adopted.
416+ multiReplCabalConstraint =
417+ ( UserConstraint
418+ (UserAnySetupQualifier (mkPackageName " Cabal" ))
419+ (PackagePropertyVersion $ orLaterVersion $ mkVersion [3 ,11 ])
420+ , ConstraintSourceMultiRepl )
421+
394422-- | First version of GHC which supports multiple home packages
395423minMultipleHomeUnitsVersion :: Version
396424minMultipleHomeUnitsVersion = mkVersion [9 , 4 ]
@@ -685,3 +713,15 @@ lPkgConfigReplOptions f s = fmap (\x -> s { pkgConfigReplOptions = x }) (f (pkgC
685713lReplOptionsFlags :: Lens' ReplOptions [String ]
686714lReplOptionsFlags f s = fmap (\ x -> s { replOptionsFlags = x }) (f (replOptionsFlags s))
687715{-# inline lReplOptionsFlags #-}
716+
717+ lProjectConfig :: Lens' ProjectBaseContext ProjectConfig
718+ lProjectConfig f s = fmap (\ x -> s { projectConfig = x }) (f (projectConfig s))
719+ {-# inline lProjectConfig #-}
720+
721+ lProjectConfigShared :: Lens' ProjectConfig ProjectConfigShared
722+ lProjectConfigShared f s = fmap (\ x -> s { projectConfigShared = x }) (f (projectConfigShared s))
723+ {-# inline lProjectConfigShared #-}
724+
725+ lProjectConfigConstraints :: Lens' ProjectConfigShared [(UserConstraint , ConstraintSource )]
726+ lProjectConfigConstraints f s = fmap (\ x -> s { projectConfigConstraints = x }) (f (projectConfigConstraints s))
727+ {-# inline lProjectConfigConstraints #-}
0 commit comments