Repository navigation
Conversation
'StoreDirLayout' keyed every location on the 'Compiler' alone:
store/<compiler-id>-<abi>/<unit-id>
The compiler's id and ABI tag record which compiler built a package, but
not what that compiler produces. With a build stage and a host stage in
one build the two compilers can agree on both while targeting different
architectures, and their outputs are then filed in one directory, under
one package database. The 'UnitId's differ -- cabal hashes the platform
along with the compiler id, see 'PackageHashInputs' -- so the two builds
do not overwrite each other. What they share is the directory, left
holding binaries for two architectures, and the package database, left
holding entries for both and read back by two different ghc-pkgs.
Take the target 'Platform' alongside the 'Compiler' in every
'StoreDirLayout' location, and name it first in the path:
store/<platform>/<compiler-id>-<abi>/<unit-id>
which is the segment order 'distBuildDirectory' has always used. Each
caller passes the platform belonging to the package at hand: the stage's
toolchain for a per-stage database or store entry, 'pkgConfigPlatform'
for the project as a whole, and 'configureCompiler''s platform in 'cabal
path'.
'distPackageDB', the database inplace packages are registered in, takes
the platform too:
dist-newstyle/packagedb/<platform>/<compiler-id>
and for a sharper reason than the store. An inplace 'UnitId' does not
mention the compiler at all, so where the store's two copies merely
shared a directory, the two copies of a local package built at both
stages are registered over one another.
The test harness learns the same layout. 'findDependencyInStore' and the
'--intree-cabal-lib' package-db lookup both descend the extra segment,
and both tolerate a store without it: those libraries are built by the
cabal on PATH rather than the one under test, so they may still be
written in the old layout.
Existing store entries under the old layout are neither migrated nor
read. They are left in place, and packages are rebuilt into the new
layout on first use. The same goes for the inplace package database.
…igShared 'elaborateInstallPlan' called its 'ProjectConfigShared' argument 'sharedPackageConfig', which is the name ProjectBuilding.hs uses for an 'ElaboratedSharedConfig' -- a different type. So the same identifier meant two things depending on the module. Call it 'projectConfigShared', as the field and every other binding of that config are named, which leaves 'sharedPackageConfig' to mean the elaborated config and nothing else. Rename only.
The type is not a path. It records at most one qualifier, not the route by which a goal was reached, and the stage it carries is a summary of that route (how many tool boundaries were crossed, capped at one) rather than an independent coordinate. The old name and the "orthogonal axes" comment suggested otherwise, which made a value like `PackagePath Host ns (QualSetup p)` look contradictory when it is the ordinary shape of every setup dependency in a non-cross build. Rename the type, constructor and module to GoalScope, the twin of the existing ConstraintScope that matches it, and rewrite the comments to state what each field answers and the invariant that ties the stage to the qualifier. No behaviour change.
prevStage used to step Host -> Build unconditionally, inventing a Build stage in builds that have no distinct build toolchain. Every caller then had to undo that by hand: the solver guarded it with qoCross, ProjectBuilding folded the stage back with a local activeStage helper, and the planning call sites relied on getStage aliasing Build to the host value. Give prevStage the toolchains (any Staged) so the clamp happens where the information lives: prevStage tc Host is Build only when isCross tc holds, and Host otherwise. Changing the signature rather than adding a second function makes every stale call a type error. With that, the solver index becomes a Staged StageIndex instead of a Map Stage StageIndex, QualifyOptions carries the active stages instead of a Bool, and the ProjectBuilding collapse helper goes away. A Build stage now exists only when there is a distinct build toolchain, by construction rather than by convention. No behaviour change.
Now that prevStage only produces a Build stage when a distinct build toolchain exists, a plan node is never at Build in a non-cross build. Two places still guarded against that: - elabActiveStage folded a package's stage onto Host for non-cross builds before recording it in the running InstalledPackageIndex. With the invariant in place it is the identity on elabStage, so use elabStage directly. - projectPackageDbsFor only emptied the package-db list for Build when isCross held. Build implies cross now, so the check and the Toolchains parameter go. The projectPackageDbsFor unit tests are reshaped accordingly: the "non-cross Build keeps the databases" case becomes a test that prevStage keeps a non-cross setup script at Host, and two tests pin prevStage itself (Host -> Build under cross, Build clamps). No behaviour change.
Add doc/internal/solver.md, a contributor-facing explanation of how the modular solver works: the lazily built search tree, the pruning, validation and reordering passes, goal scopes and linking, exploration with conflict sets and backjumping, how a solution becomes an install plan, and how error messages are produced. It draws on the HIW 2011 talk that introduced the solver and on the Well-Typed posts about qualified goals and setup dependencies, and notes where the code has moved on from them. Point to the new page from the Distribution.Solver.Modular module header and from 'solve', and fix a comment in Validate that referred to the removed preferEasyGoalChoices.
Make the limitation visible where the toolchains are configured: the program-locations sections, --with-PROG and extra-prog-path apply to both stages, so host and build resolve the same pkg-config and other auxiliary tools. The per-stage pkg-config database read is correct but reads the same tool twice until stage-qualified configuration exists.
…compilation prevStage now yields Build only when there is a distinct build toolchain, so nothing should ever ask a Staged value for a build stage it does not have. Make that an error in getStage instead of a silent fallback to the host value, and remove the two APIs that existed only to paper over the old aliasing: - activeStages, whose last caller iterated the stages to read every store; a traversal of the Staged toolchains does the same without a list-of-stages view. - pkgConfigBuildToolchain and its compiler, platform and program-db projections, literal-Build accessors documented as "equal to the host toolchain unless cross-compiling", with no callers. Reword the Staged documentation to say there is no build stage in an ordinary build, rather than a build stage that reuses the host value, and fix the QualifyOptions comment that still credited convPIs with deciding whether a build stage exists.
… and custom Setup BuildCompilerToolFromSource crosses one tool boundary (host -> build). Nothing covered the second boundary (build -> build), where prevStage has to clamp at the build stage: the build-tool-depends and setup dependencies of a build-stage package. A bug that resolved those at the host stage passed every existing two-stage test. Add BuildCompilerToolOfTool: app (host) has the build tool tool, which has the build tool gen and a custom Setup.hs. The test checks that gen has a build-stage copy in the plan and that gen, tool and tool's Setup all report the build compiler, while app reports the host compiler.
hlint flags `() <$ idx` with "Use void"; the lint CI job runs with fail-on: suggestion, so this fails the PR.
GoalScope already carries the Stage, so keying LinkingState by (PN, I, Stage) stored it twice. Restore the trunk type Map (PN, I) [GoalScope] and filter link targets by stage in linkChoices instead. Behaviour is unchanged: a goal still only links to goals of its own stage.
Under cross-compilation the programs of the build stage can now be configured separately from those of the host stage. --with-PROG, --PROG-options, program-locations and program-options apply to the host stage only, like --with-compiler; the build stage takes its own settings: - the command-line flags --with-build-PROG, --build-PROG-option and --build-PROG-options; - the top-level build-program-locations and build-program-options stanzas; - the build-PROG-location and build-PROG-options fields of a package stanza. Neither stage inherits the other's settings: --with-ar is the ar for host binaries and must never produce build-machine binaries. Each stage's toolchain is configured with its own program locations, and elaboration picks the locations and arguments of the package's stage. The per-package compiler-path check runs per stage against that stage's compiler. Without cross-compilation there is no build stage, so the settings have no effect; cabal warns that they are ignored. This lifts the limitation that program locations were not per stage. extra-prog-path is still shared by both stages.
…nts (C5, part A2)
Give users a way to write the stage-scoped constraints the solver has
supported internally since "make constraint scopes stage-aware":
- UserConstraintScope now pairs an optional build Stage with a
UserConstraintQualifier (the former scope constructors). The common
unstaged case keeps the plain 'UserConstraint qualifier prop' shape
through a pattern synonym, with UserConstraintStaged for the staged
case (COMPLETE pragma provided).
- The constraint parser accepts an optional 'build:' prefix (e.g.
'build:any.rts installed'). The Host stage is the invisible default:
it is never rendered, so non-cross output is unchanged, and
correspondingly there is no 'host:' prefix (it could not round-trip).
Package-qualified forms are tried before the stage prefix, so a package
literally named "build" keeps its meaning ('build:setup.foo' is the
setup dependency of package build).
- The solver's pretty-printer renders a Just Build stage as the same
'build:' prefix, so constraints written back to cabal.project.local
parse again.
Only setup and build-tool dependencies are ever solved for the build
stage, so 'build:' is only meaningful with the any/setup qualifiers; this
is documented in setup-commands.rst. In a non-cross build there are no
build-stage goals, so a 'build:' constraint matches nothing there.
Kept out of the cross-compilation PR proper: the syntax for scoping
constraints to qualified goals is still being settled (haskell#3502), and this
form should be agreed there before it becomes something we have to keep
parsing.
…C5, part B)
Add an executable qualifier alongside the setup one, so a constraint can
target a package as it is depended on via build-tools:
* solver: ScopeAnyExeQualifier, matching goals with a QualExe path;
rendered as 'exe.<pkg>'.
* cabal-install: UserAnyExeQualifier plus parser support for the
'exe.<pkg>' shorthand and the fully-qualified '<pkg>:<tool>:exe.<dep>'
form (mapping to UserQualExe). The latter is the form dispQualifier
already prints for QualExe, so constraints written back to
cabal.project.local parse again; UserQualExe is re-enabled in the
Arbitrary instance and the print/parse round-trip covers it.
Extend the UserConstraint grammar, re-enable the previously-disabled
UserQualExe example, and document both forms in setup-commands.rst
(replacing the long-standing TODO there).
…ackage host:* (C5, part C)
Under cross-compilation a package can be built twice, for the build
machine and for the host, and a project file has no way to configure
the two differently: "package *" applies to both copies, and a stanza
naming the package applies to both as well. GHC's own build needs the
distinction (its build-stage tools are linked statically against the
bootstrap compiler while the host stage ships shared libraries), and
cabal.project.stage2.dynamic in stable-haskell/ghc already writes it.
Add "package build:*" and "package host:*" stanzas, applying to every
package built for that stage. In the layering of per-package options
they sit between the local-package fields and the named-package
stanza:
package * < local packages < package <stage>:* < package <name>
The lookup (lookupPerPkgOption) takes the stage of the package being
elaborated; elaborateSolverToCommon fixes it to the package's own
stage for the many per-package option reads, and the library-way
selection consults the config of each node's own stage.
The stage names are spelled out in the parser rather than parsed as a
Stage: the user only ever writes them here and in constraints, where
"build:" is a prefix as well, and Host stays the invisible default
elsewhere.
To let "build:*" through, section arguments in the fields parser may
now contain colons (adjacent argument tokens joined by ":"). This
accepts strictly more input; no consumer of a .cabal file accepts an
argument with a colon (the library/executable/common names reject it),
so .cabal files gain no new syntax and no cabal-version gate is needed.
The legacy project-file parser does not know the stanzas.
Tests: parser-tests project-config-stage-packages; the ProjectConfig
Arbitrary instance leaves the field empty (neither the legacy format
nor the printer round-trips it). Documented under the package stanza in
the project file reference.
Program locations given in a stage stanza also apply to the tools cabal itself
runs for that stage: configureToolchains layers the stage's package config on
the global and local program locations and extra search paths when it builds
that stage's program database. That is what makes a cross-compilation able to
point the host stage at its own pkg-config (and so at its own pkg-config
database, now read per stage) while the build stage keeps the native one.
`Stage` read as a phase of the build (GHC's stage0/1/2 bootstrap
sequence), but the type names which toolchain a goal or plan node is
compiled with. Its constructors were already autoconf's names for that:
the *build* machine is where the build runs, the *host* machine is where
the artifacts will run. Nothing is ordered by it; it only selects a
toolchain.
Within the solver the value is still route-derived: only `qualifyDeps`
ever yields `Build`, on `QualExe`/`QualSetup` edges, via what is now
`toolMachine` (tools run where the build runs). It is carried in
`GoalScope` because the flattened qualifier cannot always recover it.
Mechanical rename, no behaviour change:
- `Stage`/`Staged`/`getStage`/`prevStage`/`showStage` become
`Machine`/`PerMachine`/`onMachine`/`toolMachine`/`showMachine`;
`Distribution.Solver.Types.Stage` is now `.Machine`
- cabal-install: `WithStage`/`HasStage`/`elabStage` and the rest follow;
`ProjectPlanning.Stage` is now `ProjectPlanning.Machine`
- plan.json: the per-entry key is `machine` (was `stage`); the values
`host`/`build` are unchanged, as are all other user-facing spellings
(`build:` constraints, `package build:` stanzas, `--with-build-PROG`,
the store path segment)
- user guide, changelog entries and internal solver doc say "build
machine"/"host machine"; the sequence wording ("earliest stage",
"clamps", "previous stage") is gone
- `doc/cmd-*-help/*.txt` regenerated from `cabal --help`; this also
picks up the `--with-build-PROG`/`--build-PROG-options` entries that
were missing from the captures
Conditionals in a project file are resolved once, against the host compiler, before the build and host machines are told apart, so there is no way to make a setting depend on the build compiler. Document this as a known limitation, with work-arounds: an unconditional build:-prefixed constraint (which matches nothing in a non-cross build), a per-build- compiler project file, or cabal.project.local / command-line flags.
--with-PROG and --with-build-PROG are chosen by the machine the package being built belongs to (elabProgramPaths uses machineProgramPaths elabMachine), not by the machine the program runs on. A host package that calls alex, which runs on the build machine, still gets --with-alex. Say so in the build-machine programs section.
Bring the user guide in line with the changelog entries of the cross-compilation series: - the build: constraint prefix also combines with the exe qualifier, and matches nothing without cross-compilation; - package-dbs / --package-db apply to the host machine only; - the store is keyed by <platform>/<compiler-id>-<abi>; - the legacy project file parser rejects package build:* and host:*.
depLibraryPaths returns absolute library paths whenever the dep's libdir is not under the package's own install prefix (i.e. almost always, in a cabal-store layout where each package gets its own hash-suffixed subdir). The previous getRPaths only prefixed `@loader_path` / `$ORIGIN` to already-relative paths, so those absolute store paths were baked directly into LC_RPATH (Mach-O) and DT_RUNPATH (ELF). On macOS up to and including Sonoma (macOS 14) dyld silently falls through to subsequent rpath entries when an absolute rpath does not exist. Sequoia (macOS 15) dyld treats the same condition as fatal and aborts the binary on launch. This affected the stable-haskell GHC bindist: a `/Volumes/WorkSpace/_work/ghc/ghc/ _build/stage2/store/host/aarch64-apple-darwin/lib` rpath baked in by the build runner caused `ghc --numeric-version` to SIGABRT when the bindist was installed on any macos-15 host. When the user has opted into relocatable mode (`--enable-relocatable`, or `relocatable: True` in a cabal project), this commit replaces such absolute rpaths with a `shortRelativePath`-computed relative form against the artifact's install directory. The relative form is well-formed (no `/Volumes` prefix to abort dyld on), and harmless when the bindist layout no longer matches the build store (dyld treats it as a normal missing rpath and falls through to subsequent entries). Non-relocatable builds (the default) are unchanged: absolute paths still pass through to preserve the existing semantics for non-relocated installs. The PackageDescription, InstallDirs, and shortRelativePath utility this needs are all already in scope or come from already-imported modules; only `bindir` and `libdir` field accessors are pulled in freshly from `Distribution.Simple.InstallDirs`. Companion to commit 010b365582c in stable-haskell/ghc, which strips the same leaked rpaths post-build with `install_name_tool` while this Cabal-side fix propagates through bindist rebuilds. (cherry picked from commit 39bd62a)
Initial version of this fix gated the new relativization on
`relocatable lbi` to keep non-relocatable builds byte-identical. The
gate doesn't help in practice:
* the stable-haskell GHC bindist build requires the new behavior
(else the darwin host binaries abort-trap on macOS 15);
* setting `relocatable: True` to flip the gate also triggers
`checkRelocatable` (which refuses cabal-store layouts whose deps
live in sibling prefixes) and changes how `library-dirs` are
written into .conf files — neither change is desirable for the
rpath fix, and the latter actively breaks the bindist
post-stage2 .conf rewriting in our Makefile pipeline.
The new always-on behavior is a strict improvement for every
relocatable scenario (cabal-store relocation, bindist relocation,
nix-style closure moves) and only a theoretical regression for the
"copy a single executable to an unrelated host and expect the same
absolute path to still resolve" case, which has never been part of
cabal's documented contract.
Companion to stable-haskell/ghc commit that drops the matching
`relocatable: True` flag from configure.ac.
(cherry picked from commit e7941cd)
…deps) The rpath relativization (added for the darwin LC_RPATH-leak fix) never adds the artifact's own directory to the runpath. depLibraryPaths can return the parent directory for a dependency installed in the same directory as the artifact, so that entry relativizes to "$ORIGIN/.." and the dependency is left unfound. glibc papers over this because GHC sets LD_LIBRARY_PATH at runtime before dlopen and glibc re-reads it per dlopen; musl reads LD_LIBRARY_PATH only at process startup and ignores the runtime change, so the missing self-rpath is fatal there. Concretely, a Backpack signature implementation (libHSp) installed next to the instantiated unit (libHSindef) fails to load under musl (GHC testsuite backpack/cabal/T14304 on Alpine), though it passes on every glibc platform. Always prepend the loader-relative self directory ($ORIGIN, or @loader_path on macOS) to the rpaths so a same-directory sibling is found. This is a relative entry, so it does not reintroduce the absolute build-host path the relativization removed (no macOS regression). (cherry picked from commit 5c09786)
Port 468b554d0 onto the cross2 base (applies cleanly). Remove temporary directories with bounded retries on permission errors: Windows file handles can remain locked briefly after a waited child exits; retry up to three times with a one-second delay and preserve the final error if removal still fails. (cherry picked from commit 5a4fd8f)
Port of 19c5938 (persistent store for installed libraries) and c20f160 (in-library compiler metadata with the toolchain) onto the cross-compilation-2 tip. CmdInstall.hs keeps cross2's stage-aware getPackageDbStack helper and compiler-ex API; only the persistent store layout binding is added for the planner's registration DB. (cherry picked from commit 1620840) Retargeted onto Machine: pass elabToolchain into libraryConfigureInputsFromElabPackage, and use PerMachine in the in-library unit test.
Port 5f97030 (Make profiling an intrinsic target ABI and remove legacy ways) onto the cross-compilation-2 base, keeping cross2's staged architecture instead of PR501's pure-common refactor: - elaborateInstallPlan takes stage/install package configs and merges them via a stage-aware lookupPerPkgOptionStaged (stage + install overlays), instead of replacing the lookup architecture. - PerPkgConfigFlag and the needs*/libraryWayWarnings predicates take the staged lookup so install-target profiling reaches way selection. - withProfExe honours Prof+ProfExe via the staged lookup; fix the swapped withProfLibDetail/withProfExeDetail. - checkBadPerPackageCompilerPaths runs over all toolchains and also covers install-target packages. - Add normaliseUnscopedPackageConfig (exported); keep cross2's shouldBeLocal, elaborateSolverToCommon, instantiate flow. - Tests: extend ProjectConfig Arbitrary/shrink for the two new maps; keep the branch-native coverage test; wire in the install-promotion and profiling-layer test groups. (cherry picked from commit 457d660) Retargeted onto Machine. Kept projectConfigMachinePackages and added the install-target overlay. Profiling defaults follow compilerTargetsProfiling.
Port f405dfa (Use qualified target identity across Cabal planning and paths) onto the cross-compilation-2 base, keeping cross2's per-machine architecture instead of PR501's single-toolchain refactor: - Keep cross2's (Compiler, Platform) store API and DistDirLayout paths; port betterPlatform as a canonical-name helper (exported) with test coverage instead of rewiring store/dist layouts. - Library ways stay in cross2's elaborateLibraryWays; port L3's profiling-aware canBuildSharedLibs into compilerShouldUseSharedLibByDefault, and L3's False profiling defaults into the module-level needsProfilingLib/Shared predicates. - Package hash gains pkgHashTargetName from the package's own machine toolchain (elabCompiler/elabPlatform), not a single global toolchain. - Plan JSON and ghc-env rendering use the machine toolchain's canonical target name; unsupported profiling variants are reported explicitly via profilingTargetVariantError. - Adapt the Store and ProjectPlanning unit tests to branch APIs. Retargeted onto Machine/PerMachine. Build-machine plan JSON fields are emitted only when cross-compiling, because onMachine Build errors otherwise. (cherry picked from commit 9e78589)
…dfdf) Port 5d6dfdf (Split L4: preserve full machine triples through configure) onto the cross-compilation-2 base, keeping cross2's per-machine architecture and runner behavior: - Classify Linux target triples with libc-ABI suffixes without losing ABI identity (System.hs), with unit coverage. - configureTargetArgs/configureTargetDefaults select full machine triples per machine from the compiler Target platform properties; setupHsConfigureFlags keeps its plan argument (live on cross2 via determineCoverageFor) alongside the shared config. - runConfigureScriptWithCompiler threads the selecting compiler (and cross2's program database) into the configure-script runner, which validates --host/--build against profiling target names. - Adapt the configure-target unit tests to cross2 APIs (plan-taking setupHsConfigureFlags, PerMachine toolchains, constructor imports); the synthetic-configure check asserts ordered presence of the triples alongside the runner's own compiler selections. Retargeted onto Machine/PerMachine. The Autoconf build alias uses the build toolchain when one exists and the host toolchain otherwise, so a non-cross plan does not call onMachine Build. (cherry picked from commit 1319a80)
…7e3f8d) Port 37e3f8d (Split L5: preserve configured toolchains and library metadata) onto the cross-compilation-2 base, keeping cross2's per-machine runner and program-database flow: - Configure-script runner keeps its single entry point and program database; port L5's toolchain preservation as GHC/GHC_PKG environment entries and export canonicalisePathSeparator. - Internal build tools propagate the package data directory to the configured GHC program for compile-time child processes. - Install-from-source paths and package registration align internal library Haddock/HTML directories; exe install resolves -o targets. - Add the missing build-package-dbs layer (legacy field, ProjectConfig field, lens, both grammars, combine) so build-machine package databases round-trip through legacy and Parsec project configuration. - Adapt the toolchain roundtrip test to the flat cross2 shared config. Kept cross2's build-machine program paths and arguments alongside the new build-package-dbs fields. (cherry picked from commit edf6fd4)
805164b to
278a24d
Compare
|
Hey Moritz, thanks for pulling this together. Heads up: the base has moved under you. I've dropped the platform segment from the store in haskell#12356. The store is back to upstream's I don't think this hurts the graft:
I did a trial rebase of the whole branch onto 278a24d, up to ebb2865:
The trial is pushed as Before you rebase:
|
Summary
Graft the useful stable-haskell cross-compilation work onto Andrea Bedini's dual-compiler line.
Base is
stable-haskell/feature/cross-compile-2at805164bc45fb64783c343a44d468c42196d511d2, the same commit as haskell/cabal#12356 (andrea/feature/cross-compilation-2). This PR does not mergestable-haskell/masterand does not replay the pre-Machine history that the October split stack still carries.The October stack (PRs #527, #517–#524) was cut from the older Stage-era
cross-compile-2. Thirty-six of its commits replay history that haskell#12356 already replaced. Only the stable-haskell-only commits were brought across, retargeted fromStage/StagedtoMachine/PerMachine.onMachine Buildis not used unless the plan is actually cross-compiling; the build compiler isfromMaybe (onHost toolchains) (onBuild toolchains).plan.jsonkeeps themachinefield (what this base emits) and gains dist-dir / build-info selection.projectConfigInstallPackagesis kept.No full compile has been run on this branch. Do not treat CI as green until it has actually run.
Harvested
9f09d43b2,e16ae1130,95679d789$ORIGIN/@loader_pathfor musl sibling deps.Cabal/src/Distribution/Simple/GHC/Build/Link.hsonly.fcefcaa1aa824795f68ed479b4aBuildWayisStaticWay|DynWay; a profiled compiler iscompilerTargetAbi == "profiling".7295e48b5package build:*/package host:*onMachine).13e10366ce5feb13f3c30f40f97Machine.e8c7b98873dd7d632dplanDistDirForMachine,buildInfoFileForMachine), haddock fixtures. The reader parsesmachine, notstage.38aa45721faa232267(head branch was deleted).guessToolFromGhcPathtries the target prefix (wasm32-unknown-wasi-ghc-pkg) before the unprefixed tool. Applied after the commits that touchGHC.hs.Already on this base, not reapplied
ba5437f66on this base).allow_checks_interruption.Left out on purpose
rebase-CI. Superseded by the GHC/Build/Link: relativize absolute rpaths + self-$ORIGIN (stacked on #378) #385 trio above.reusable-release.yml. The current release workflow on this base already builds alpine 3.21 / musl.binDirectoryFor. Head branch was deleted. Not ported.masterCI and miscellaneous branches. Not part of this line.Test plan
cabalbuild ofCabalandcabal-installagainst the two-compiler project testscabal-testsuiteplan.json reader and the BuildCompilerTool tests (they selectMachineBuild, notStage)