HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Modulecabal-install-3.12.1.0Haskell2010

Distribution.Client.ProjectPlanning

Elaborated: worked out with great care and nicety of detail; executed with great minuteness: elaborate preparations; elaborate care.

In this module we construct an install plan that includes all the information needed to execute it.

Building a project is therefore split into two phases:

  1. The construction of the install plan (which as far as possible should be pure), done here.

  2. The execution of the plan, done in ProjectBuilding

To achieve this we need a representation of this fully elaborated install plan; this representation consists of two parts:

  • A ElaboratedInstallPlan. This is a GenericInstallPlan with a representation of source packages that includes a lot more detail about that package's individual configuration

  • A ElaboratedSharedConfig. Some package configuration is the same for every package in a plan. Rather than duplicate that info every entry in the GenericInstallPlan we keep that separately.

The division between the shared and per-package config is not set in stone for all time. For example if we wanted to generalise the install plan to describe a situation where we want to build some packages with GHC and some with GHCJS then the platform and compiler would no longer be shared between all packages but would have to be per-package (probably with some sanity condition on the graph structure).

  • 14 types
  • 30 values

Types for the elaborated install plan

7 declarations

Constructors

Instances11Eq, Show, Generic, Binary, Structured, IsNode, …

Constructors

Instances5Show, Generic, Binary, Structured, Rep
datadata BuildStyle
#

This is used in the install plan to indicate how the package will be built.

Constructors

  • BuildAndInstall

    The classic approach where the package is built, then the files installed into some location and the result registered in a package db.

    If the package came from a tarball then it's built in a temp dir and the results discarded.

  • BuildInplaceOnly MemoryOrDisk

    For OnDisk: The package is built, but the files are not installed anywhere, rather the build dir is kept and the package is registered inplace.

    Such packages can still subsequently be installed.

    Typically BuildAndInstall packages will only depend on other BuildAndInstall style packages and not on BuildInplaceOnly ones.

    For InMemory: Built in-memory only using GHC multi-repl, they are not built or installed anywhere on disk. BuildInMemory packages can't be depended on by BuildAndInstall nor BuildInplaceOnly packages (because they don't exist on disk) but can depend on other BuildStyles.

    At the moment BuildInplaceOnly InMemory is only used by the repl command.

    We use single constructor BuildInplaceOnly as for most cases inplace packages are handled similarly.

Instances9Eq, Ord, Show, Generic, Semigroup, Monoid, …

Reading the project configuration

1 declaration

The project configuration is assembled into a ProjectConfig as follows:

CLI arguments are converted using "commandLineFlagsToProjectConfig" in the v2 command entrypoints and passed to "establishProjectBaseContext" which then calls "rebuildProjectConfig".

"rebuildProjectConfig" then calls "readProjectConfig" to read the project files. Due to the presence of conditionals, this output is in the form of a ProjectConfigSkeleton and will be resolved by "rebuildProjectConfig" using "instantiateProjectConfigSkeletonFetchingCompiler".

"readProjectConfig" also loads the global configuration, which is read with "loadConfig" and convertd to a ProjectConfig with "convertLegacyGlobalConfig".

  • Important:* You can notice how some project config options are needed to read the project config! This is evident by the fact that "rebuildProjectConfig" takes HttpTransport and DistDirLayout as parameters. Two arguments are infact determined from the CLI alone (in "establishProjectBaseContext"). Consequently, project files (including global configuration) cannot affect those parameters!

Furthermore, the project configuration can specify a compiler to use, which we need to resolve the conditionals in the project configuration! To solve this, we configure the compiler from what is obtained by applying the CLI configuration over the the configuration obtained by "flattening" ProjectConfigSkeleton. This means collapsing all conditionals by taking both branches.

Producing the elaborated install plan

1 declaration

Return an up-to-date elaborated install plan.

Two variants of the install plan are returned: with and without packages from the store. That is, the "improved" plan where source packages are replaced by pre-existing installed packages from the store (when their ids match), and also the original elaborated plan which uses primarily source packages.

Build targets

8 declarations

Given the install plan, produce the set of AvailableTargets for each package-component pair.

Typically there will only be one such target for each component, but for example if we have a plan with both normal and profiling variants of a component then we would get both as available targets, or similarly if we had a plan that contained two instances of the same version of a package. This approach makes it relatively easy to select all instances/variants of a component.

datadata AvailableTarget k
#

An available target represents a component within a package that a user command could plausibly refer to. In this sense, all the components defined within the package are things the user could refer to, whether or not it would actually be possible to build that component.

In particular the available target contains an AvailableTargetStatus which informs us about whether it's actually possible to select this component to be built, and if not why not. This detail makes it possible for command implementations (like build, test etc) to accurately report why a target cannot be used.

Note that the type parameter is used to help enforce that command implementations can only select targets that can actually be built (by forcing them to return the k value for the selected targets). In particular resolveTargets makes use of this (with k as (UnitId, ComponentName')) to identify the targets thus selected.

Instances3Functor, Eq, Show
datadata AvailableTargetStatus k
#

The status of a an AvailableTarget component. This tells us whether it's actually possible to select this component to be built, and if not why not.

Constructors

Instances4Functor, Eq, Ord, Show
datadata TargetRequested
#

This tells us whether a target ought to be built by default, or only if specifically requested. The policy is that components like libraries and executables are built by default by build, but test suites and benchmarks are not, unless this is overridden in the project configuration.

Constructors

Instances3Eq, Ord, Show
  • Eq TargetRequestedDefined in cabal-install-3.12.1.0 · Distribution.Client.ProjectPlanning
  • Ord TargetRequestedDefined in cabal-install-3.12.1.0 · Distribution.Client.ProjectPlanning
  • Show TargetRequestedDefined in cabal-install-3.12.1.0 · Distribution.Client.ProjectPlanning
datadata ComponentTarget
#

Specific targets within a package or component to act on e.g. to build, haddock or open a repl.

Instances7Eq, Ord, Show, Generic, Binary, Structured, …
datadata SubComponentTarget
#

Either the component as a whole or detail about a file or module target within a component.

Constructors

Instances7Eq, Ord, Show, Generic, Binary, Structured, …

Merge component targets that overlap each other. Specially when we have multiple targets for the same component and one of them refers to the whole component (rather than a module or file within) then all the other targets for that component are subsumed.

We also allow for information associated with each component target, and whenever we targets subsume each other we aggregate their associated info.

Selecting a plan subset

4 declarations

Given a set of per-package/per-component targets, take the subset of the install plan needed to build those targets. Also, update the package config to specify which optional stanzas to enable, and which targets within each package to build.

NB: Pruning happens after improvement, which is important because we will prune differently depending on what is already installed (to implement "sticky" test suite enabling behavior).

newtypenewtype CannotPruneDependencies
#

It is not always possible to prune to only the dependencies of a set of targets. It may be the case that removing a package leaves something else that still needed the pruned package.

This lists all the packages that would be broken, and their dependencies that would be missing if we did prune.

Instances1Show

Utils required for building

3 declarations

Setup.hs CLI flags for building

16 declarations

Path construction

4 declarations