This module deals with building and incrementally rebuilding a collection
of packages. It is what backs the cabal build and configure commands,
as well as being a core part of run, test, bench and others.
The primary thing is in fact rebuilding (and trying to make that quick by
not redoing unnecessary work), so building from scratch is just a special
case.
The build process and the code can be understood by breaking it down into
three major parts:
The "what to do" phase, where we look at the all input configuration
(project files, .cabal files, command line etc) and produce a detailed
plan of what to do -- the ElaboratedInstallPlan.
As far as possible, the "what to do" phase embodies all the policy, leaving
the "do it" phase policy free. The first phase contains more of the
complicated logic, but it is contained in code that is either pure or just
has read effects (except cache updates). Then the second phase does all the
actions to build packages, but as far as possible it just follows the
instructions and avoids any logic for deciding what to do (apart from
recompilation avoidance in executing the plan).
This division helps us keep the code under control, making it easier to
understand, test and debug. So when you are extending these modules, please
think about which parts of your change belong in which part. It is
perfectly ok to extend the description of what to do (i.e. the
ElaboratedInstallPlan) if that helps keep the policy decisions in the
first phase. Also, the second phase does not have direct access to any of
the input configuration anyway; all the information has to flow via the
ElaboratedInstallPlan.
Note: these are all the packages mentioned in the project configuration.
Whether or not they will be considered local to the project will be decided
by shouldBeLocal in ProjectPlanning.
Resolved configuration for things that affect how we build and not the
value of the things we build. The idea is that this is easier to use than
the raw configuration because in the raw configuration everything is
optional (monoidial). In the BuildTimeSettings every field is filled in,
if only with the defaults.
Use resolveBuildTimeSettings to make one from the project config (by
applying defaults etc).
Convert configuration from the cabal configure or cabal build command
line into a ProjectConfig value that can combined with configuration from
other sources.
At the moment this uses the legacy command line flag types. See
LegacyProjectConfig for an explanation.
This is the improved plan, before we select a plan subset based on
the build targets, and before we do the dry-run. So this contains
all packages in the project.
This is the elaboratedPlanOriginal after we select a plan subset
and do the dry-run phase to find out what is up-to or out-of date.
This is the plan that will be executed during the build phase. So
this contains only a subset of packages in the project.
The part of the install plan that's shared between all packages in
the plan. This does not change between the two plan variants above,
so there is just the one copy.
This parameter is used when there are ambiguous selectors.
If it is Just, then we attempt to resolve ambiguity
by applying it, since otherwise there is no way to allow
contextually valid yet syntactically ambiguous selectors.
(#4676, #5461)
Parse a bunch of command line args as TargetSelectors, failing with an
error if any are unrecognised. The possible target selectors are based on
the available packages (and their locations).
The idea is that every user target identifies one or more roots in the
ElaboratedInstallPlan, which we will use to determine the closure
of what packages need to be built, dropping everything from the plan
that is unnecessary. This closure and pruning is done by
pruneInstallPlanToTargets and this needs to be told the roots in terms
of UnitIds and the ComponentTargets within those.
This means we first need to translate the TargetSelectors into the
UnitIds and ComponentTargets. This translation has to be different for
the different command line commands, like build, repl etc. For example
the command build pkgfoo could select a different set of components in
pkgfoo than repl pkgfoo. The build command would select any library and
all executables, whereas repl would select the library or a single
executable. Furthermore, both of these examples could fail, and fail in
different ways and each needs to be able to produce helpful error messages.
So resolveTargets takes two helpers: one to select the targets to be used
by user targets that refer to a whole package (TargetPackage), and
another to check user targets that refer to a component (or a module or
file within a component). These helpers can fail, and use their own error
type. Both helpers get given the AvailableTarget info about the
component(s).
While commands vary quite a bit in their behaviour about which components to
select for a whole-package target, most commands have the same behaviour for
checking a user target that refers to a specific component. To help with
this commands can use selectComponentTargetBasic, either directly or as
a basis for their own selectComponentTarget implementation.
The set of components to build, represented as a mapping from UnitIds
to the ComponentTargets within the unit that will be selected
(e.g. selected to build, test or repl).
Associated with each ComponentTarget is the set of TargetSelectors that
matched this target. Typically this is exactly one, but in general it is
possible to for different selectors to match the same target. This extra
information is primarily to help make helpful error messages.
A target selector is expression selecting a set of components (as targets
for a actions like build, run, test etc). A target selector
corresponds to the user syntax for referring to targets on the command line.
From the users point of view a target can be many things: packages, dirs,
component names, files etc. Internally we consider a target to be a specific
component (or module/file within a component), and all the users' notions
of targets are just different ways of referring to these component targets.
So target selectors are expressions in the sense that they are interpreted
to refer to one or more components. For example a TargetPackage gets
interpreted differently by different commands to refer to all or a subset
of components within the package.
The syntax has lots of optional parts:
[ package name | package dir | package .cabal file ]
[ [lib:|exe:] component name ]
[ module name | source file ]
A package specified by name. This may refer to extra-packages from
the cabal.project file, or a dependency of a known project package or
could refer to a package from a hackage archive. It needs further
context to resolve to a specific package.
Does this TargetPackage selector arise from syntax referring to a
package in the current directory (e.g. tests or no giving no explicit
target at all) or does it come from syntax referring to a package name
or location.
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.
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.
A basic selectComponentTarget implementation to use or pass to
resolveTargets, that does the basic checks that the component is
buildable and isn't a test suite or benchmark that is disabled. This
can also be used to do these basic checks as part of a custom impl that
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.