Skip to content

Commit

Permalink
Add support for loading multiple components into one repl session
Browse files Browse the repository at this point in the history
There are several parts to this patch which are logically distinct but
work together to support the overal goal of starting a GHCi session with
multiple packages loaded at once.

1. When a user writes "cabal repl <target>" then if the user is using a
   compiler > ghc-9.4.* then we will attempt to start a multi-session
   which loads the selected targets into one multi-package session of
   GHC.
1a. The closure property states that in order to load components `p` and `q` into
    the same session that if `p` depends on `z` and `z` depends on `q`
    then `z` must also be loaded into the session.
1b. Only inplace packages are able to be loaded into a multi session (if a component
    `z` exists then it is already made into an inplace package by
    cabal). Therefore cabal has already engineered that there is source
    code locally available for all packages which we will want to load
    into a session.

2. The solver is unmodified, the solver is given the repl targets and
   creates a build plan as before. After the solver is completed then in
   `setRootTargets` and `pruneInstallPlan` we modify the install plan to
   enforce the closure property and mark which dependencies need to be
   promised.

   * Mark the current components as `BuildInPlaceOnly InMemory`, which
     indicates to the compiler that it is to be built in a GHC
     multi-session.
   * Augment the component repl targets to indicate that components
     required by the closure property (in addition to normal targets)
     will be loaded into the repl.
   * Modify the dependency edges in `compLibDependencies` to indicate
     which dependencies are the promised ones (which is precisely
     components which are `BuildInPlaceOnly InMemory` build styles).
     This is the field which is eventually used to populate the
     `--dependency` argument to `./Setup configure`.

Fixes #8491
  • Loading branch information
mpickering authored and fgaz committed May 25, 2023
1 parent 47ffcdb commit 13cf185
Show file tree
Hide file tree
Showing 71 changed files with 1,319 additions and 306 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tests = testGroup "Distribution.Utils.Structured"
, testCase "GenericPackageDescription" $
md5Check (Proxy :: Proxy GenericPackageDescription) 0xa3e9433662ecf0c7a3c26f6d75a53ba1
, testCase "LocalBuildInfo" $
md5Check (Proxy :: Proxy LocalBuildInfo) 0x91ffcd61bbd83525e8edba877435a031
md5Check (Proxy :: Proxy LocalBuildInfo) 0x30ebb8fffa1af2aefa9432ff4028eef8
#endif
]

Expand Down
6 changes: 2 additions & 4 deletions Cabal/src/Distribution/Types/AnnotatedId.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{-# LANGUAGE DeriveFunctor #-}
module Distribution.Types.AnnotatedId (
AnnotatedId(..)
) where
Expand All @@ -19,7 +20,7 @@ data AnnotatedId id = AnnotatedId {
ann_cname :: ComponentName,
ann_id :: id
}
deriving (Show)
deriving (Show, Functor)

instance Eq id => Eq (AnnotatedId id) where
x == y = ann_id x == ann_id y
Expand All @@ -29,6 +30,3 @@ instance Ord id => Ord (AnnotatedId id) where

instance Package (AnnotatedId id) where
packageId = ann_pid

instance Functor AnnotatedId where
fmap f (AnnotatedId pid cn x) = AnnotatedId pid cn (f x)
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module Distribution.Solver.Types.ComponentDeps (
, insert
, zip
, filterDeps
, mapDeps
, fromLibraryDeps
, fromSetupDeps
, fromInstalled
Expand Down Expand Up @@ -149,6 +150,10 @@ zip (ComponentDeps d1) (ComponentDeps d2) =
filterDeps :: (Component -> a -> Bool) -> ComponentDeps a -> ComponentDeps a
filterDeps p = ComponentDeps . Map.filterWithKey p . unComponentDeps

-- | Keep only selected components (and their associated deps info).
mapDeps :: (Component -> a -> b) -> ComponentDeps a -> ComponentDeps b
mapDeps p = ComponentDeps . Map.mapWithKey p . unComponentDeps

-- | ComponentDeps containing library dependencies only
fromLibraryDeps :: a -> ComponentDeps a
fromLibraryDeps = singleton ComponentLib
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ data ConstraintSource =
-- target, when a more specific source is not known.
| ConstraintSourceConfigFlagOrTarget

-- | Constraint introduced by --enable-multi-repl, which requires features
-- from Cabal >= 3.11
| ConstraintSourceMultiRepl

-- | The source of the constraint is not specified.
| ConstraintSourceUnknown

Expand Down Expand Up @@ -65,6 +69,8 @@ showConstraintSource ConstraintSourceNonUpgradeablePackage =
showConstraintSource ConstraintSourceFreeze = "cabal freeze"
showConstraintSource ConstraintSourceConfigFlagOrTarget =
"config file, command line flag, or user target"
showConstraintSource ConstraintSourceMultiRepl =
"--enable-multi-repl"
showConstraintSource ConstraintSourceUnknown = "unknown source"
showConstraintSource ConstraintSetupCabalMinVersion =
"minimum version of Cabal used by Setup.hs"
Expand Down
1 change: 1 addition & 0 deletions cabal-install/cabal-install.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ library
Distribution.Client.ProjectPlanning.Types
Distribution.Client.RebuildMonad
Distribution.Client.Reconfigure
Distribution.Client.ReplFlags
Distribution.Client.Run
Distribution.Client.Sandbox
Distribution.Client.Sandbox.PackageEnvironment
Expand Down
4 changes: 2 additions & 2 deletions cabal-install/src/Distribution/Client/CmdListBin.hs
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,12 @@ listbinAction flags@NixStyleFlags{..} args globalFlags = do
-- here and in PlanOutput,
-- use binDirectoryFor?
bin_file' s =
if elabBuildStyle elab == BuildInplaceOnly
if isInplaceBuildStyle (elabBuildStyle elab)
then dist_dir </> "build" </> prettyShow s </> prettyShow s <.> exeExtension plat
else InstallDirs.bindir (elabInstallDirs elab) </> prettyShow s <.> exeExtension plat

flib_file' s =
if elabBuildStyle elab == BuildInplaceOnly
if isInplaceBuildStyle (elabBuildStyle elab)
then dist_dir </> "build" </> prettyShow s </> ("lib" ++ prettyShow s) <.> dllExtension plat
else InstallDirs.bindir (elabInstallDirs elab) </> ("lib" ++ prettyShow s) <.> dllExtension plat

Expand Down
Loading

0 comments on commit 13cf185

Please sign in to comment.