@@ -36,6 +36,8 @@ import Distribution.Client.CmdErrorMessages
36
36
targetSelectorRefersToPkgs ,
37
37
renderComponentKind , renderListCommaAnd , renderListSemiAnd ,
38
38
componentKind , sortGroupOn , Plural (.. ) )
39
+ import Distribution.Client.Targets
40
+ ( UserConstraint (.. ), UserConstraintScope (.. ) )
39
41
import Distribution.Client.TargetProblem
40
42
( TargetProblem (.. ) )
41
43
import qualified Distribution.Client.InstallPlan as InstallPlan
@@ -65,9 +67,13 @@ import Distribution.Compiler
65
67
import Distribution.Simple.Compiler
66
68
( Compiler , compilerCompatVersion )
67
69
import Distribution.Package
68
- ( Package (.. ), packageName , UnitId , installedUnitId )
70
+ ( Package (.. ), packageName , mkPackageName , UnitId , installedUnitId )
69
71
import Distribution.Solver.Types.SourcePackage
70
72
( SourcePackage (.. ) )
73
+ import Distribution.Solver.Types.ConstraintSource
74
+ ( ConstraintSource (ConstraintSourceMultiRepl ) )
75
+ import Distribution.Solver.Types.PackageConstraint
76
+ ( PackageProperty (PackagePropertyVersion ) )
71
77
import Distribution.Types.BuildInfo
72
78
( BuildInfo (.. ), emptyBuildInfo )
73
79
import Distribution.Types.ComponentName
@@ -81,7 +87,7 @@ import Distribution.Types.Library
81
87
import Distribution.Types.Version
82
88
( Version , mkVersion )
83
89
import Distribution.Types.VersionRange
84
- ( anyVersion )
90
+ ( anyVersion , orLaterVersion )
85
91
import Distribution.Utils.Generic
86
92
( safeHead )
87
93
import Distribution.Verbosity
@@ -115,7 +121,7 @@ import Distribution.Client.ReplFlags
115
121
topReplOptions )
116
122
import Distribution.Simple.Flag ( Flag (Flag ), fromFlagOrDefault )
117
123
import Distribution.Client.ProjectConfig
118
- ( ProjectConfigShared (projectConfigMultiRepl ),
124
+ ( ProjectConfigShared (projectConfigMultiRepl , projectConfigConstraints ),
119
125
ProjectConfig (projectConfigShared ) )
120
126
121
127
@@ -183,8 +189,8 @@ multiReplDecision ctx compiler flags =
183
189
-- up to date, selects that part of the plan needed by the given or implicit
184
190
-- repl target and then executes the plan.
185
191
--
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
188
194
-- general plan execution infrastructure handles both build and repl targets.
189
195
--
190
196
-- For more details on how this works, see the module
@@ -228,13 +234,24 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
228
234
229
235
updateContextAndWriteProjectFile ctx scriptPath scriptExecutable
230
236
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')
233
250
else
234
251
-- Unfortunately, the best way to do this is to let the normal solver
235
252
-- help us resolve the targets, but that isn't ideal for performance,
236
253
-- especially in the no-project case.
237
- withInstallPlan (lessVerbose verbosity) baseCtx $ \ elaboratedPlan sharedConfig -> do
254
+ withInstallPlan (lessVerbose verbosity) baseCtx' $ \ elaboratedPlan sharedConfig -> do
238
255
-- targets should be non-empty map, but there's no NonEmptyMap yet.
239
256
targets <- validatedTargets (projectConfigShared (projectConfig ctx)) (pkgConfigCompiler sharedConfig) elaboratedPlan targetSelectors
240
257
@@ -243,9 +260,9 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
243
260
originalDeps = installedUnitId <$> InstallPlan. directDeps elaboratedPlan unitId
244
261
oci = OriginalComponentInfo unitId originalDeps
245
262
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'
247
264
248
- return (Just oci, baseCtx')
265
+ return (Just oci, baseCtx'' )
249
266
250
267
-- Now, we run the solver again with the added packages. While the graph
251
268
-- won't actually reflect the addition of transitive dependencies,
@@ -255,9 +272,9 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
255
272
-- In addition, to avoid a *third* trip through the solver, we are
256
273
-- replicating the second half of 'runProjectPreBuildPhase' by hand
257
274
-- here.
258
- (buildCtx, compiler, replOpts', targets) <- withInstallPlan verbosity baseCtx' $
275
+ (buildCtx, compiler, replOpts', targets) <- withInstallPlan verbosity baseCtx'' $
259
276
\ elaboratedPlan elaboratedShared' -> do
260
- let ProjectBaseContext {.. } = baseCtx'
277
+ let ProjectBaseContext {.. } = baseCtx''
261
278
262
279
-- Recalculate with updated project.
263
280
targets <- validatedTargets (projectConfigShared projectConfig) (pkgConfigCompiler elaboratedShared') elaboratedPlan targetSelectors
@@ -296,7 +313,7 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
296
313
-- Multi Repl implemention see: https://well-typed.com/blog/2023/03/cabal-multi-unit/ for
297
314
-- a high-level overview about how everything fits together.
298
315
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
300
317
-- multi target repl
301
318
dir <- makeAbsolute dir'
302
319
-- Modify the replOptions so that the ./Setup repl command will write options
@@ -306,12 +323,12 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
306
323
_ -> usingGhciScript compiler projectRoot replOpts'
307
324
308
325
let buildCtx' = buildCtx & lElaboratedShared . lPkgConfigReplOptions .~ replOpts''
309
- printPlan verbosity baseCtx' buildCtx'
326
+ printPlan verbosity baseCtx'' buildCtx'
310
327
311
328
-- The project build phase will call `./Setup repl` but write the options
312
329
-- 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
315
332
316
333
-- calculate PATH, we construct a PATH which is the union of all paths from
317
334
-- 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
354
371
_ -> usingGhciScript compiler projectRoot replOpts'
355
372
356
373
let buildCtx' = buildCtx & lElaboratedShared . lPkgConfigReplOptions .~ replOpts''
357
- printPlan verbosity baseCtx' buildCtx'
374
+ printPlan verbosity baseCtx'' buildCtx'
358
375
359
- buildOutcomes <- runProjectBuildPhase verbosity baseCtx' buildCtx'
360
- runProjectPostBuildPhase verbosity baseCtx' buildCtx' buildOutcomes
376
+ buildOutcomes <- runProjectBuildPhase verbosity baseCtx'' buildCtx'
377
+ runProjectPostBuildPhase verbosity baseCtx'' buildCtx' buildOutcomes
361
378
where
362
379
363
380
combine_search_paths paths =
@@ -391,6 +408,17 @@ replAction flags@NixStyleFlags { extraFlags = r@ReplFlags{..} , ..} targetString
391
408
392
409
return targets
393
410
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
+
394
422
-- | First version of GHC which supports multiple home packages
395
423
minMultipleHomeUnitsVersion :: Version
396
424
minMultipleHomeUnitsVersion = mkVersion [9 , 4 ]
@@ -685,3 +713,15 @@ lPkgConfigReplOptions f s = fmap (\x -> s { pkgConfigReplOptions = x }) (f (pkgC
685
713
lReplOptionsFlags :: Lens' ReplOptions [String ]
686
714
lReplOptionsFlags f s = fmap (\ x -> s { replOptionsFlags = x }) (f (replOptionsFlags s))
687
715
{-# 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