packages feed

stack 3.9.3 → 3.11.1

raw patch · 88 files changed

+2028/−835 lines, 88 filesdep +semaphore-compatdep ~asyncdep ~cryptondep ~filelockPVP ok

version bump matches the API change (PVP)

Dependencies added: semaphore-compat

Dependency ranges changed: async, crypton, filelock, generic-deriving, hashable, hspec, optparse-generic

API changes (from Hackage documentation)

- Stack.Config.Nix: data ConfigNixException
- Stack.Config.Nix: instance GHC.Internal.Exception.Type.Exception Stack.Config.Nix.ConfigNixException
- Stack.Config.Nix: instance GHC.Internal.Show.Show Stack.Config.Nix.ConfigNixException
- Stack.ConfigCmd: instance GHC.Internal.Exception.Type.Exception Stack.ConfigCmd.ConfigCmdException
- Stack.ConfigCmd: instance GHC.Internal.Show.Show Stack.ConfigCmd.ConfigCmdException
- Stack.Ls: instance GHC.Internal.Exception.Type.Exception Stack.Ls.LsException
- Stack.Ls: instance GHC.Internal.Show.Show Stack.Ls.LsException
- Stack.Nix: instance GHC.Internal.Exception.Type.Exception Stack.Nix.NixException
- Stack.Nix: instance GHC.Internal.Show.Show Stack.Nix.NixException
+ Stack.Build.ExecuteEnv: [semaphore] :: ExecuteEnv -> !Maybe Semaphore
+ Stack.Config: withConfigExtra :: forall a env. (HasConfig env, HasTerm env) => Bool -> (ConfigExtra -> RIO env a) -> RIO env a
+ Stack.Config.Nix: data ConfigNixPrettyException
+ Stack.Config.Nix: instance GHC.Internal.Exception.Type.Exception Stack.Config.Nix.ConfigNixPrettyException
+ Stack.Config.Nix: instance GHC.Internal.Show.Show Stack.Config.Nix.ConfigNixPrettyException
+ Stack.Config.Nix: instance Text.PrettyPrint.Leijen.Extended.Pretty Stack.Config.Nix.ConfigNixPrettyException
+ Stack.ConfigCmd: cfgCmdCompilerTools :: () -> RIO EnvConfig ()
+ Stack.ConfigCmd: cfgCmdCompilerToolsName :: String
+ Stack.ConfigCmd: instance GHC.Internal.Exception.Type.Exception Stack.ConfigCmd.ConfigCmdPrettyException
+ Stack.ConfigCmd: instance GHC.Internal.Show.Show Stack.ConfigCmd.ConfigCmdPrettyException
+ Stack.ConfigCmd: instance Text.PrettyPrint.Leijen.Extended.Pretty Stack.ConfigCmd.ConfigCmdPrettyException
+ Stack.ConfigCmd: yamlContainsInclude :: Text -> Bool
+ Stack.Ls: instance GHC.Internal.Exception.Type.Exception Stack.Ls.LsPrettyException
+ Stack.Ls: instance GHC.Internal.Show.Show Stack.Ls.LsPrettyException
+ Stack.Ls: instance Text.PrettyPrint.Leijen.Extended.Pretty Stack.Ls.LsPrettyException
+ Stack.Nix: instance GHC.Internal.Exception.Type.Exception Stack.Nix.NixPrettyException
+ Stack.Nix: instance GHC.Internal.Show.Show Stack.Nix.NixPrettyException
+ Stack.Nix: instance Text.PrettyPrint.Leijen.Extended.Pretty Stack.Nix.NixPrettyException
+ Stack.Prelude: prettyImpureThrow :: (Exception e, Pretty e) => e -> a
+ Stack.Types.Build.ConstructPlan: type LibraryMap = Map PackageName Either ConstructPlanException AddDepRes
+ Stack.Types.Build.ConstructPlan: type PackageLoader (m :: Type -> Type) = PackageLocationImmutable -> Map FlagName Bool -> [Text] -> [Text] -> m Package
+ Stack.Types.BuildOpts: [semaphore] :: BuildOpts -> !Bool
+ Stack.Types.BuildOpts: [timeoutGraceSeconds] :: TestOpts -> !Maybe Int
+ Stack.Types.BuildOpts: buildOptsSemaphoreL :: Lens' BuildOpts Bool
+ Stack.Types.BuildOptsMonoid: [semaphore] :: BuildOptsMonoid -> !FirstFalse
+ Stack.Types.BuildOptsMonoid: [timeoutGraceSeconds] :: TestOptsMonoid -> !First (Maybe Int)
+ Stack.Types.BuildOptsMonoid: buildOptsMonoidSemaphoreL :: Lens' BuildOptsMonoid (Maybe Bool)
+ Stack.Types.Config: [recentSnapshots] :: Config -> !Text
+ Stack.Types.Config: askRecentSnapshotsUrl :: (MonadReader env m, HasConfig env) => m Text
+ Stack.Types.ConfigExtra: ConfigExtra :: !Config -> !Maybe RawSnapshotLocation -> !Project -> !Either (Path Abs File) (Path Abs File) -> ConfigExtra
+ Stack.Types.ConfigExtra: [configFile] :: ConfigExtra -> !Either (Path Abs File) (Path Abs File)
+ Stack.Types.ConfigExtra: [config] :: ConfigExtra -> !Config
+ Stack.Types.ConfigExtra: [mSnapshot] :: ConfigExtra -> !Maybe RawSnapshotLocation
+ Stack.Types.ConfigExtra: [project] :: ConfigExtra -> !Project
+ Stack.Types.ConfigExtra: data ConfigExtra
+ Stack.Types.ConfigMonoid: [recentSnapshots] :: ConfigMonoid -> !First Text
+ Stack.Types.ConfigMonoid: instance Data.Aeson.Types.FromJSON.FromJSON (Data.Aeson.WarningParser.WithJSONWarnings Stack.Types.ConfigMonoid.UrlsOptsMonoid)
+ Stack.Types.ConfigMonoid: instance GHC.Internal.Base.Monoid Stack.Types.ConfigMonoid.UrlsOptsMonoid
+ Stack.Types.ConfigMonoid: instance GHC.Internal.Base.Semigroup Stack.Types.ConfigMonoid.UrlsOptsMonoid
+ Stack.Types.ConfigMonoid: instance GHC.Internal.Generics.Generic Stack.Types.ConfigMonoid.UrlsOptsMonoid
+ Stack.Types.DotOpts: [reach] :: DotOpts -> !Set PackageName
- Stack.Build: loadPackage :: (HasBuildConfig env, HasSourceMap env) => PackageLocationImmutable -> Map FlagName Bool -> [Text] -> [Text] -> RIO env Package
+ Stack.Build: loadPackage :: (HasBuildConfig env, HasSourceMap env) => PackageLoader (RIO env)
- Stack.Build.ConstructPlan: constructPlan :: HasEnvConfig env => BaseConfigOpts -> [DumpPackage] -> (PackageLocationImmutable -> Map FlagName Bool -> [Text] -> [Text] -> RIO EnvConfig Package) -> SourceMap -> InstalledMap -> Bool -> RIO env Plan
+ Stack.Build.ConstructPlan: constructPlan :: HasEnvConfig env => BaseConfigOpts -> [DumpPackage] -> PackageLoader (RIO EnvConfig) -> SourceMap -> InstalledMap -> Bool -> RIO env Plan
- Stack.Build.ExecuteEnv: ExecuteEnv :: !MVar () -> !BuildOpts -> !BuildOptsCLI -> !BaseConfigOpts -> !TVar (Map PackageIdentifier Installed) -> !Path Abs Dir -> !Path Abs File -> !Path Abs File -> !Maybe (Path Abs File) -> !Version -> !Int -> ![LocalPackage] -> !Path Abs Dir -> !Map GhcPkgId DumpPackage -> !TVar (Map GhcPkgId DumpPackage) -> !TVar (Map GhcPkgId DumpPackage) -> !TChan (Path Abs Dir, Path Abs File) -> !IORef (Set PackageName) -> !Maybe Int -> !Text -> ExecuteEnv
+ Stack.Build.ExecuteEnv: ExecuteEnv :: !MVar () -> !BuildOpts -> !BuildOptsCLI -> !BaseConfigOpts -> !TVar (Map PackageIdentifier Installed) -> !Path Abs Dir -> !Path Abs File -> !Path Abs File -> !Maybe (Path Abs File) -> !Version -> !Int -> ![LocalPackage] -> !Path Abs Dir -> !Map GhcPkgId DumpPackage -> !TVar (Map GhcPkgId DumpPackage) -> !TVar (Map GhcPkgId DumpPackage) -> !TChan (Path Abs Dir, Path Abs File) -> !IORef (Set PackageName) -> !Maybe Int -> !Text -> !Maybe Semaphore -> ExecuteEnv
- Stack.Config.ConfigureScript: ensureConfigureScript :: (HasProcessContext env, HasTerm env) => Path b Dir -> RIO env ()
+ Stack.Config.ConfigureScript: ensureConfigureScript :: HasConfig env => Path b Dir -> RIO env ()
- Stack.Config.Nix: nixCompiler :: WantedCompiler -> Either ConfigNixException Text
+ Stack.Config.Nix: nixCompiler :: WantedCompiler -> Either ConfigNixPrettyException Text
- Stack.Config.Nix: nixCompilerVersion :: WantedCompiler -> Either ConfigNixException Text
+ Stack.Config.Nix: nixCompilerVersion :: WantedCompiler -> Either ConfigNixPrettyException Text
- Stack.Types.Build.ConstructPlan: Ctx :: !BaseConfigOpts -> !PackageLocationImmutable -> Map FlagName Bool -> [Text] -> [Text] -> M Package -> !CombinedMap -> !EnvConfig -> ![PackageName] -> !Set PackageName -> !Set PackageName -> !Maybe Curator -> !Text -> Ctx
+ Stack.Types.Build.ConstructPlan: Ctx :: !BaseConfigOpts -> !PackageLoader M -> !CombinedMap -> !EnvConfig -> ![PackageName] -> !Set PackageName -> !Set PackageName -> !Maybe Curator -> !Text -> Ctx
- Stack.Types.Build.ConstructPlan: [loadPackage] :: Ctx -> !PackageLocationImmutable -> Map FlagName Bool -> [Text] -> [Text] -> M Package
+ Stack.Types.Build.ConstructPlan: [loadPackage] :: Ctx -> !PackageLoader M
- Stack.Types.Build.ConstructPlan: type M = WriterT W StateT Map PackageName Either ConstructPlanException AddDepRes RIO Ctx
+ Stack.Types.Build.ConstructPlan: type M = WriterT W StateT LibraryMap RIO Ctx
- Stack.Types.Build.Exception: CabalCopyFailed :: Bool -> String -> BuildException
+ Stack.Types.Build.Exception: CabalCopyFailed :: !Bool -> !BuildPrettyException -> BuildPrettyException
- Stack.Types.Build.Exception: TestSuiteExeMissing :: Bool -> String -> String -> String -> BuildException
+ Stack.Types.Build.Exception: TestSuiteExeMissing :: !Bool -> !String -> !PackageName -> !StackUnqualCompName -> BuildPrettyException
- Stack.Types.BuildOpts: BuildOpts :: !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !HaddockOpts -> !Bool -> !Maybe Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Maybe Bool -> !Bool -> !Bool -> !Bool -> !TestOpts -> !Bool -> !BenchmarkOpts -> !Bool -> !CabalVerbosity -> !Bool -> ![StackUnqualCompName] -> !Bool -> !ProgressBarFormat -> !Maybe Text -> BuildOpts
+ Stack.Types.BuildOpts: BuildOpts :: !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !HaddockOpts -> !Bool -> !Maybe Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Maybe Bool -> !Bool -> !Bool -> !Bool -> !TestOpts -> !Bool -> !BenchmarkOpts -> !Bool -> !CabalVerbosity -> !Bool -> ![StackUnqualCompName] -> !Bool -> !ProgressBarFormat -> !Maybe Text -> !Bool -> BuildOpts
- Stack.Types.BuildOpts: TestOpts :: !Bool -> ![String] -> !Bool -> !Bool -> !Maybe Int -> !Bool -> TestOpts
+ Stack.Types.BuildOpts: TestOpts :: !Bool -> ![String] -> !Bool -> !Bool -> !Maybe Int -> !Maybe Int -> !Bool -> TestOpts
- Stack.Types.BuildOptsMonoid: BuildOptsMonoid :: !Any -> !Any -> !Any -> !FirstFalse -> !FirstFalse -> !FirstTrue -> !FirstTrue -> !FirstFalse -> !HaddockOptsMonoid -> !FirstFalse -> !First Bool -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !FirstTrue -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !First Bool -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !TestOptsMonoid -> !FirstFalse -> !BenchmarkOptsMonoid -> !FirstFalse -> !First CabalVerbosity -> !FirstFalse -> ![StackUnqualCompName] -> !FirstTrue -> !First ProgressBarFormat -> !First Text -> BuildOptsMonoid
+ Stack.Types.BuildOptsMonoid: BuildOptsMonoid :: !FirstFalse -> !Any -> !Any -> !Any -> !FirstFalse -> !FirstFalse -> !FirstTrue -> !FirstTrue -> !FirstFalse -> !HaddockOptsMonoid -> !FirstFalse -> !First Bool -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !FirstTrue -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !First Bool -> !FirstFalse -> !FirstFalse -> !FirstFalse -> !TestOptsMonoid -> !FirstFalse -> !BenchmarkOptsMonoid -> !FirstFalse -> !First CabalVerbosity -> !FirstFalse -> ![StackUnqualCompName] -> !FirstTrue -> !First ProgressBarFormat -> !First Text -> BuildOptsMonoid
- Stack.Types.BuildOptsMonoid: TestOptsMonoid :: !FirstTrue -> ![String] -> !FirstFalse -> !FirstTrue -> !First (Maybe Int) -> !FirstTrue -> TestOptsMonoid
+ Stack.Types.BuildOptsMonoid: TestOptsMonoid :: !FirstTrue -> ![String] -> !FirstFalse -> !FirstTrue -> !First (Maybe Int) -> !First (Maybe Int) -> !FirstTrue -> TestOptsMonoid
- Stack.Types.Config: Config :: !Path Rel Dir -> !Path Abs File -> !BuildOpts -> !DockerOpts -> !NixOpts -> !EnvSettings -> IO ProcessContext -> !Path Abs Dir -> !Path Abs Dir -> !Bool -> !Bool -> !Platform -> !PlatformVariant -> !Maybe GHCVariant -> !Maybe CompilerBuild -> !Text -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Maybe MsysEnvironment -> !VersionCheck -> !CompilerRepository -> !CompilerTarget -> !CompilerBindistPath -> !Path Abs Dir -> !Maybe (Path Abs File) -> !VersionRange -> !Int -> !Maybe (Path Abs File) -> ![FilePath] -> ![FilePath] -> ![Text] -> !Bool -> !Map Text Text -> !Maybe SCM -> !Map PackageName [Text] -> !Map ApplyGhcOptions [Text] -> !Map CabalConfigKey [Text] -> ![String] -> !SetupInfo -> !PvpBounds -> !Bool -> !Bool -> !ApplyGhcOptions -> !ApplyProgOptions -> !First Bool -> !Maybe [PackageName] -> !First AbstractSnapshot -> !Maybe TemplateName -> !Bool -> !DumpLogs -> !ProjectConfig (Project, Path Abs File) -> !Bool -> !FirstTrue -> !Text -> !Runner -> !PantryConfig -> !Path Abs Dir -> !Maybe AbstractSnapshot -> !UserStorage -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Maybe (CasaRepoPrefix, Int) -> Config
+ Stack.Types.Config: Config :: !Path Rel Dir -> !Path Abs File -> !BuildOpts -> !DockerOpts -> !NixOpts -> !EnvSettings -> IO ProcessContext -> !Path Abs Dir -> !Path Abs Dir -> !Bool -> !Bool -> !Platform -> !PlatformVariant -> !Maybe GHCVariant -> !Maybe CompilerBuild -> !Text -> !Text -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Maybe MsysEnvironment -> !VersionCheck -> !CompilerRepository -> !CompilerTarget -> !CompilerBindistPath -> !Path Abs Dir -> !Maybe (Path Abs File) -> !VersionRange -> !Int -> !Maybe (Path Abs File) -> ![FilePath] -> ![FilePath] -> ![Text] -> !Bool -> !Map Text Text -> !Maybe SCM -> !Map PackageName [Text] -> !Map ApplyGhcOptions [Text] -> !Map CabalConfigKey [Text] -> ![String] -> !SetupInfo -> !PvpBounds -> !Bool -> !Bool -> !ApplyGhcOptions -> !ApplyProgOptions -> !First Bool -> !Maybe [PackageName] -> !First AbstractSnapshot -> !Maybe TemplateName -> !Bool -> !DumpLogs -> !ProjectConfig (Project, Path Abs File) -> !Bool -> !FirstTrue -> !Text -> !Runner -> !PantryConfig -> !Path Abs Dir -> !Maybe AbstractSnapshot -> !UserStorage -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Bool -> !Maybe (CasaRepoPrefix, Int) -> Config
- Stack.Types.ConfigMonoid: ConfigMonoid :: !First (Path Abs Dir) -> !First (Path Rel Dir) -> !BuildOptsMonoid -> !DockerOptsMonoid -> !NixOptsMonoid -> !First Int -> !FirstTrue -> !First Bool -> !First Text -> !First PackageIndexConfig -> !First Bool -> !FirstTrue -> !First Bool -> !FirstFalse -> !FirstFalse -> !First MsysEnvironment -> !First VersionCheck -> !First CompilerRepository -> !First CompilerTarget -> !First CompilerBindistPath -> !IntersectingVersionRange -> !First String -> !First GHCVariant -> !First CompilerBuild -> !First Int -> ![FilePath] -> ![FilePath] -> ![Text] -> !First (Path Abs File) -> !First FilePath -> !FirstFalse -> !First Bool -> !First FilePath -> !First FilePath -> !Map Text Text -> !First SCM -> !MonoidMap PackageName (Dual [Text]) -> !MonoidMap ApplyGhcOptions (Dual [Text]) -> !MonoidMap CabalConfigKey (Dual [Text]) -> ![Path Abs Dir] -> ![String] -> !SetupInfo -> !First (Path Abs Dir) -> !First PvpBounds -> !FirstTrue -> !FirstFalse -> !First ApplyGhcOptions -> !First ApplyProgOptions -> !First Bool -> !Maybe AllowNewerDeps -> !First (Unresolved AbstractSnapshot) -> !First TemplateName -> !First Bool -> !First DumpLogs -> !FirstTrue -> !First Text -> !First ColorWhen -> !StylesUpdate -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !CasaOptsMonoid -> !First CasaRepoPrefix -> !First Text -> !First (Unresolved GlobalHintsLocation) -> !FirstFalse -> !First Bool -> ConfigMonoid
+ Stack.Types.ConfigMonoid: ConfigMonoid :: !First (Path Abs Dir) -> !First (Path Rel Dir) -> !BuildOptsMonoid -> !DockerOptsMonoid -> !NixOptsMonoid -> !First Int -> !FirstTrue -> !First Bool -> !First Text -> !First Text -> !First PackageIndexConfig -> !First Bool -> !FirstTrue -> !First Bool -> !FirstFalse -> !FirstFalse -> !First MsysEnvironment -> !First VersionCheck -> !First CompilerRepository -> !First CompilerTarget -> !First CompilerBindistPath -> !IntersectingVersionRange -> !First String -> !First GHCVariant -> !First CompilerBuild -> !First Int -> ![FilePath] -> ![FilePath] -> ![Text] -> !First (Path Abs File) -> !First FilePath -> !FirstFalse -> !First Bool -> !First FilePath -> !First FilePath -> !Map Text Text -> !First SCM -> !MonoidMap PackageName (Dual [Text]) -> !MonoidMap ApplyGhcOptions (Dual [Text]) -> !MonoidMap CabalConfigKey (Dual [Text]) -> ![Path Abs Dir] -> ![String] -> !SetupInfo -> !First (Path Abs Dir) -> !First PvpBounds -> !FirstTrue -> !FirstFalse -> !First ApplyGhcOptions -> !First ApplyProgOptions -> !First Bool -> !Maybe AllowNewerDeps -> !First (Unresolved AbstractSnapshot) -> !First TemplateName -> !First Bool -> !First DumpLogs -> !FirstTrue -> !First Text -> !First ColorWhen -> !StylesUpdate -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !FirstTrue -> !CasaOptsMonoid -> !First CasaRepoPrefix -> !First Text -> !First (Unresolved GlobalHintsLocation) -> !FirstFalse -> !First Bool -> ConfigMonoid
- Stack.Types.DotOpts: DotOpts :: !Bool -> !Bool -> !Maybe Int -> !Set PackageName -> [Text] -> !Map ApplyCLIFlag (Map FlagName Bool) -> Bool -> Bool -> Bool -> DotOpts
+ Stack.Types.DotOpts: DotOpts :: !Bool -> !Bool -> !Maybe Int -> !Set PackageName -> !Set PackageName -> [Text] -> !Map ApplyCLIFlag (Map FlagName Bool) -> Bool -> Bool -> Bool -> DotOpts

Files

CONTRIBUTING.md view
@@ -351,10 +351,11 @@ Stack aims to depend on well-known packages. The specific versions on which it
 depends at any time are specified by `package.yaml` and `stack.yaml`. It does
 not aim to be compatible with more than one version of the `Cabal` package at
-any time. At the time of writing (January 2026) the package versions are
-primarily ones in Stackage snapshot LTS Haskell 24.24 (for GHC 9.10.3), the
-latest version of `Cabal` released on Hackage (`Cabal-3.16.0.0`),
-`pantry-0.11.2`, and `persistent-2.18.0.0`.
+any time. At the time of writing (May 2026) the package versions are
+primarily ones in Stackage snapshot LTS Haskell 24.43 (for GHC 9.10.3), the
+latest version of `Cabal` released on Hackage (`Cabal-3.16.1.0`),
+`pantry-0.11.2`, `persistent-2.18.1.0` and the latest version of packages in
+the `tls` family (which reduce dependencies on unmaintained packages).
 
 A Stack executable makes use of Cabal (the library) through a small 'Setup'
 executable that it compiles from Haskell source code. The executable compiles
ChangeLog.md view
@@ -1,5 +1,85 @@ # Changelog
 
+## v3.11.1 - 2026-06-13
+
+**Changes since v3.9.3:**
+
+Major changes:
+
+* On 64-bit Windows, the default `msys-environment` configuration option is now
+  `CLANG64`, rather than `MINGW64` (which remains an option). The MSYS2 project
+  deprecated the latter environment on 15 March 2026. The GHC project has used
+  the former toolchain from GHC 9.4.1. No default is provided for 32-bit
+  Windows, rather than `MINGW32` (which remains an option). The MSYS2 project
+  ceased to actively support it on 17 May 2020. 32-bit Windows is not supported
+  by the GHC project from GHC 8.12.
+
+Behavior changes:
+
+* Stack's default Nix integration now includes the `cacert` Nix package, in
+  order to support Stack's use of `crypton-x509-system >= 1.6.8`.
+* Following a change to the Stackage project's server API, the default value of
+  the `urls` key includes
+  `recent-snapshots: https://stackage.org/api/v1/snapshots`.
+* The `--[no-]keep-ghc-rts` flag of Stack's `config env` command is now enabled
+  by default, consistent with Stack's `exec` command.
+* On Windows, in the Stack environment, the MSYS2 `usr/local/bin` directory (if
+  it exists) is now searched before the MSYS2 `usr/bin` directory, rather than
+  after.
+
+Other enhancements:
+
+* Bump to Hpack 0.39.6.
+* Experimental: Add flag `--[no-]semaphore` (default: disabled) to Stack's
+  `build` command, to allow GHC to use a system semaphore to perform compilation
+  in parallel when possible. Supported, by default, by GHC 9.10.1 or later. The
+  option is considered experiemental because, on Linux only, musl and non-musl
+  semaphores are incompatible.
+* Add option `--reach <packages>` to Stack's `dot` and `ls dependencies`
+  commands, to prune packages that cannot reach any of the specified packages in
+  the dependency graph.
+* Add option `--test-suite-timeout-grace=SECONDS` to Stack's `build` command to
+  request termination of a timed-out test suite process and, after the specified
+  grace period, force termination. Used together with the existing
+  `--test-suite-timeout=SECONDS` option.
+* In YAML configuration files, the `recent-snapshots` key is introduced (under
+  the `urls` key), to specify the URL used by Stack's `ls snapshots remote`
+  command.
+* In YAML configuration files (`stack.yaml` and `config.yaml`), an
+  `!include <file path>` directive is now supported. This allows common
+  configuration to be shared across multiple files. For example, a project that
+  maintains multiple project-level configuration files for testing against
+  different snapshots can use `!include` to avoid duplicating shared settings.
+* Stack's `config set` command raises an error if the target configuration file
+  excludes the key being set and includes an `!include` directive.
+* Stack's `config set snapshot` command now works with other snapshot values
+  in addition to snapshot synonymns.
+* Add Stack's `config compiler-tools` command to create (when applicable) the
+  compiler tools directory for the specified compiler version (implies Stack's
+  `config build-files` command).
+
+Bug fixes:
+
+* Stack's `dot` and `ls dependencies` commands no longer prune a package with
+  dependencies only because all its direct dependencies are to be pruned.
+* After March 2026, Hackage requires Stack's user agent to be set when applying
+  digest authentication to a request. Stack's `upload` command now does that,
+  re-establishing authentication by Hackage username and password.
+* Stack 3.9.3 and earlier fail to construct a build plan if project package A
+  depends on project package B and package B's executables (only) depend on
+  package A and the name of A is before that of B, alphabetically. That bug is
+  fixed.
+* Stack's `config set` commands will recreate the `global-project` directory
+  contents, if Stack needs to consult its project-level configuration file and
+  there is no file.
+* The output of Stack's `path --bin-path` command is now consistent with the
+  Stack environment in Stack's `exec` command and includes the `bin` directory
+  of Stack's local install root directory.
+* Stack now builds packages that depend directly on packages with the same name
+  as a sublibrary or foreign library of the package.
+* On Windows, Stack's `build` command now accepts a build directory that is a
+  long path.
+
 ## v3.9.3 - 2026-02-19
 
 Release notes:
@@ -128,7 +208,7 @@   documentation.
 * `stack sdist` and `stack upload` report the version of Cabal (the library)
   being used to check packages.
-* Add the `stack config build-files` command to generate (when applicable) a
+* Add Stack's `config build-files` command to generate (when applicable) a
   Cabal file from a package description in the Hpack format and/or a lock file
   for Stack's project-level configuration, without taking any other build steps.
 
cabal.config view
@@ -1,42 +1,41 @@ constraints:
-  , Cabal ==3.16.0.0
-  , Cabal-syntax ==3.16.0.0
+  , Cabal ==3.16.1.0
+  , Cabal-syntax ==3.16.1.0
   , Glob ==0.10.2
-  , OneTuple ==0.4.2
+  , OneTuple ==0.4.3
   , QuickCheck ==2.15.0.1
   , StateVar ==1.2.2
   , Win32 ==2.14.1.0
-  , aeson ==2.2.3.0
+  , aeson ==2.2.5.0
   , aeson-warning-parser ==0.1.1
-  , alex ==3.5.4.0
+  , alex ==3.5.4.2
   , annotated-wl-pprint ==0.7.0
-  , ansi-terminal ==1.1.4
+  , ansi-terminal ==1.1.5
   , ansi-terminal-types ==1.1.3
   , appar ==0.1.8
   , array ==0.5.8.0
-  , asn1-encoding ==0.9.6
-  , asn1-parse ==0.9.5
-  , asn1-types ==0.3.4
   , assoc ==1.1.1
-  , async ==2.2.5
+  , async ==2.2.6
   , atomic-counter ==0.1.2.4
   , attoparsec ==0.14.4
   , attoparsec-aeson ==2.2.2.0
   , auto-update ==0.2.6
   , base ==4.20.2.0
-  , base-orphans ==0.9.3
+  , base-orphans ==0.9.4
+  , base16 ==1.0
   , base16-bytestring ==1.0.2.0
+  , base64 ==1.0
   , base64-bytestring ==1.2.1.0
   , basement ==0.0.16
-  , bifunctors ==5.6.2
+  , bifunctors ==5.6.3
   , binary ==0.8.9.3
-  , bitvec ==1.1.5.0
+  , bitvec ==1.1.6.0
   , blaze-builder ==0.4.4.1
   , blaze-html ==0.9.2.0
   , blaze-markup ==0.8.3.0
   , byteorder ==1.0.4
   , bytestring ==0.12.2.0
-  , casa-client ==0.0.3
+  , casa-client ==0.0.4
   , casa-types ==0.0.3
   , case-insensitive ==1.2.1.0
   , cborg ==0.2.10.0
@@ -44,46 +43,50 @@   , character-ps ==0.1
   , clock ==0.8.4
   , cmdargs ==0.10.22
-  , colour ==2.3.6
-  , comonad ==5.0.9
+  , colour ==2.3.7
+  , comonad ==5.0.10
   , companion ==0.1.0
   , conduit ==1.3.6.1
   , conduit-combinators ==1.3.0
   , conduit-extra ==1.3.8
   , containers ==0.7
-  , contravariant ==1.5.5
+  , contravariant ==1.5.6
   , cookie ==0.5.1
   , cryptohash-sha256 ==0.11.102.1
-  , crypton ==1.0.4
+  , crypton ==1.0.6
+  , crypton-asn1-encoding ==0.10.0
+  , crypton-asn1-parse ==0.10.0
+  , crypton-asn1-types ==0.4.1
   , crypton-conduit ==0.2.3
   , crypton-connection ==0.4.5
+  , crypton-pem ==0.3.0
   , crypton-socks ==0.6.2
-  , crypton-x509 ==1.7.7
-  , crypton-x509-store ==1.6.12
-  , crypton-x509-system ==1.6.7
-  , crypton-x509-validation ==1.6.14
-  , data-default ==0.8.0.1
+  , crypton-x509 ==1.8.0
+  , crypton-x509-store ==1.8.0
+  , crypton-x509-system ==1.8.0
+  , crypton-x509-validation ==1.8.0
+  , data-default ==0.8.0.2
   , data-default-class ==0.2.0.0
   , data-fix ==0.3.4
   , deepseq ==1.5.0.0
   , digest ==0.0.2.1
   , directory ==1.3.8.5
   , directory-ospath-streaming ==0.2.2
-  , distributive ==0.6.2.1
+  , distributive ==0.6.3
   , dlist ==1.0
   , easy-file ==0.2.5
+  , ech-config ==0.0.1
   , echo ==0.1.4
   , ed25519 ==0.0.5.0
   , exceptions ==0.10.9
   , extra ==1.8.1
   , fast-logger ==3.2.6
   , file-embed ==0.0.16.0
-  , file-io ==0.1.5
-  , filelock ==0.1.1.8
+  , file-io ==0.1.6
+  , filelock ==0.1.1.9
   , filepath ==1.5.4.0
   , fsnotify ==0.4.4.0
-  , generic-deriving ==1.14.6
-  , generically ==0.1.1
+  , generic-deriving ==1.14.7
   , ghc-bignum ==1.3
   , ghc-boot ==9.10.3
   , ghc-boot-th ==9.10.3
@@ -95,25 +98,25 @@   , half ==0.3.3
   , happy ==2.1.7
   , happy-lib ==2.1.7
-  , hashable ==1.5.0.0
+  , hashable ==1.5.1.0
   , haskell-src-exts ==1.23.1
   , haskell-src-meta ==0.8.15
   , hi-file-parser ==0.1.8.0
-  , hourglass ==0.2.12
-  , hpack ==0.39.1
+  , hpack ==0.39.6
   , hpc ==0.7.0.2
-  , http-api-data ==0.6.2
+  , hpke ==0.0.0
+  , http-api-data ==0.6.3
   , http-client ==0.7.19
   , http-client-tls ==0.3.6.4
   , http-conduit ==2.3.9.1
   , http-download ==0.2.1.0
   , http-types ==0.12.4
-  , indexed-traversable ==0.1.4
-  , indexed-traversable-instances ==0.1.2
+  , indexed-traversable ==0.1.5
+  , indexed-traversable-instances ==0.1.2.1
   , infer-license ==0.2.0
   , integer-conversion ==0.1.1
   , integer-gmp ==1.1
-  , integer-logarithms ==1.0.4
+  , integer-logarithms ==1.0.5
   , iproute ==1.7.15
   , libyaml ==0.1.4
   , libyaml-clib ==0.2.5
@@ -124,7 +127,7 @@   , microlens ==0.4.14.0
   , microlens-mtl ==0.2.1.0
   , microlens-th ==0.4.3.17
-  , mime-types ==0.1.2.0
+  , mime-types ==0.1.2.2
   , mintty ==0.1.4
   , monad-control ==1.0.3.1
   , monad-logger ==0.3.42
@@ -135,26 +138,26 @@   , mustache ==2.4.3.1
   , neat-interpolation ==0.5.1.4
   , network ==3.2.8.0
+  , network-byte-order ==0.1.8
   , network-uri ==2.6.4.2
   , old-locale ==1.0.0.7
-  , old-time ==1.1.0.4
+  , old-time ==1.1.1.0
   , open-browser ==0.4.0.0
   , optparse-applicative ==0.18.1.0
   , optparse-simple ==0.1.1.4
   , os-string ==2.0.7
   , pantry ==0.11.2
   , parsec ==3.1.18.0
-  , parser-combinators ==1.3.0
+  , parser-combinators ==1.3.1
   , path ==0.9.6
   , path-io ==1.8.2
   , path-pieces ==0.2.1
-  , pem ==0.2.4
-  , persistent ==2.18.0.0
+  , persistent ==2.18.1.0
   , persistent-sqlite ==2.13.3.1
   , persistent-template ==2.12.0.0
   , pretty ==1.1.3.6
-  , prettyprinter ==1.7.1
-  , prettyprinter-ansi-terminal ==1.1.3
+  , prettyprinter ==1.7.2
+  , prettyprinter-ansi-terminal ==1.1.4
   , primitive ==0.9.1.0
   , process ==1.6.26.1
   , project-template ==0.2.1.0
@@ -165,21 +168,22 @@   , retry ==0.9.3.1
   , rio ==0.1.24.0
   , rio-orphans ==0.1.2.0
-  , rio-prettyprint ==0.1.8.0
+  , rio-prettyprint ==0.1.9.0
   , rts ==1.0.2
   , safe ==0.3.21
   , safe-exceptions ==0.1.7.4
-  , scientific ==0.3.8.0
-  , semialign ==1.3.1
-  , semigroupoids ==6.0.1
+  , scientific ==0.3.8.1
+  , semaphore-compat ==1.0.0
+  , semialign ==1.3.1.1
+  , semigroupoids ==6.0.2
   , serialise ==0.2.6.1
   , silently ==1.2.5.4
   , split ==0.2.5
-  , splitmix ==0.1.3.1
-  , stack ==3.9.3
+  , splitmix ==0.1.3.2
+  , stack ==3.11.1
   , static-bytes ==0.1.1
   , stm ==2.5.3.1
-  , stm-chans ==3.0.0.9
+  , stm-chans ==3.0.0.11
   , streaming-commons ==0.2.3.1
   , strict ==0.5.1
   , string-interpolate ==0.3.4.0
@@ -187,27 +191,28 @@   , tagged ==0.8.9
   , tar ==0.6.4.0
   , tar-conduit ==0.4.1
-  , tasty ==1.5.3
+  , tasty ==1.5.4
   , template-haskell ==2.22.0.0
   , temporary ==1.3
   , text ==2.1.3
   , text-conversions ==0.3.1.1
-  , text-iso8601 ==0.1.1
+  , text-iso8601 ==0.1.1.1
   , text-metrics ==0.3.3
-  , text-short ==0.1.6
-  , th-abstraction ==0.7.1.0
-  , th-compat ==0.1.6
+  , text-short ==0.1.6.1
+  , th-abstraction ==0.7.2.0
+  , th-compat ==0.1.7
   , th-expand-syns ==0.4.12.0
-  , th-lift ==0.8.6
+  , th-lift ==0.8.7
   , th-lift-instances ==0.1.20
-  , th-orphans ==0.13.16
+  , th-orphans ==0.13.17
   , th-reify-many ==0.1.10
   , these ==1.2.1
   , time ==1.12.2
-  , time-compat ==1.9.8
-  , tls ==2.1.8
+  , time-compat ==1.9.9
+  , time-hourglass ==0.3.0
+  , tls ==2.2.2
   , transformers ==0.6.1.1
-  , transformers-base ==0.4.6
+  , transformers-base ==0.4.6.1
   , transformers-compat ==0.7.2
   , typed-process ==0.2.13.0
   , unix ==2.8.6.0
@@ -217,8 +222,8 @@   , unliftio-core ==0.2.1.0
   , unordered-containers ==0.2.20.1
   , utf8-string ==1.0.2
-  , uuid-types ==1.0.6
-  , vault ==0.3.1.5
+  , uuid-types ==1.0.6.1
+  , vault ==0.3.1.6
   , vector ==0.13.2.0
   , vector-algorithms ==0.9.1.0
   , vector-stream ==0.1.0.1
@@ -226,4 +231,4 @@   , yaml ==0.11.11.2
   , zip-archive ==0.4.3.2
   , zlib ==0.7.1.1
-  , zlib-clib ==1.3.1
+  , zlib-clib ==1.3.2
cabal.project view
@@ -33,7 +33,7 @@ -- specified by the snapshot specifed in Stack's project-level YAML
 -- configuration file (`stack.yaml`). The relevant version of GHC can be
 -- confirmed by reviewing the snapshot on Stackage. For example, at:
--- https://www.stackage.org/lts-24.24/cabal.config.
+-- https://www.stackage.org/lts-24.43/cabal.config.
 --
 with-compiler: ghc-9.10.3
 import: cabal.config
doc/CONTRIBUTING.md view
@@ -351,10 +351,11 @@ Stack aims to depend on well-known packages. The specific versions on which it
 depends at any time are specified by `package.yaml` and `stack.yaml`. It does
 not aim to be compatible with more than one version of the `Cabal` package at
-any time. At the time of writing (January 2026) the package versions are
-primarily ones in Stackage snapshot LTS Haskell 24.24 (for GHC 9.10.3), the
-latest version of `Cabal` released on Hackage (`Cabal-3.16.0.0`),
-`pantry-0.11.2`, and `persistent-2.18.0.0`.
+any time. At the time of writing (May 2026) the package versions are
+primarily ones in Stackage snapshot LTS Haskell 24.43 (for GHC 9.10.3), the
+latest version of `Cabal` released on Hackage (`Cabal-3.16.1.0`),
+`pantry-0.11.2`, `persistent-2.18.1.0` and the latest version of packages in
+the `tls` family (which reduce dependencies on unmaintained packages).
 
 A Stack executable makes use of Cabal (the library) through a small 'Setup'
 executable that it compiles from Haskell source code. The executable compiles
doc/ChangeLog.md view
@@ -1,5 +1,85 @@ # Changelog
 
+## v3.11.1 - 2026-06-13
+
+**Changes since v3.9.3:**
+
+Major changes:
+
+* On 64-bit Windows, the default `msys-environment` configuration option is now
+  `CLANG64`, rather than `MINGW64` (which remains an option). The MSYS2 project
+  deprecated the latter environment on 15 March 2026. The GHC project has used
+  the former toolchain from GHC 9.4.1. No default is provided for 32-bit
+  Windows, rather than `MINGW32` (which remains an option). The MSYS2 project
+  ceased to actively support it on 17 May 2020. 32-bit Windows is not supported
+  by the GHC project from GHC 8.12.
+
+Behavior changes:
+
+* Stack's default Nix integration now includes the `cacert` Nix package, in
+  order to support Stack's use of `crypton-x509-system >= 1.6.8`.
+* Following a change to the Stackage project's server API, the default value of
+  the `urls` key includes
+  `recent-snapshots: https://stackage.org/api/v1/snapshots`.
+* The `--[no-]keep-ghc-rts` flag of Stack's `config env` command is now enabled
+  by default, consistent with Stack's `exec` command.
+* On Windows, in the Stack environment, the MSYS2 `usr/local/bin` directory (if
+  it exists) is now searched before the MSYS2 `usr/bin` directory, rather than
+  after.
+
+Other enhancements:
+
+* Bump to Hpack 0.39.6.
+* Experimental: Add flag `--[no-]semaphore` (default: disabled) to Stack's
+  `build` command, to allow GHC to use a system semaphore to perform compilation
+  in parallel when possible. Supported, by default, by GHC 9.10.1 or later. The
+  option is considered experiemental because, on Linux only, musl and non-musl
+  semaphores are incompatible.
+* Add option `--reach <packages>` to Stack's `dot` and `ls dependencies`
+  commands, to prune packages that cannot reach any of the specified packages in
+  the dependency graph.
+* Add option `--test-suite-timeout-grace=SECONDS` to Stack's `build` command to
+  request termination of a timed-out test suite process and, after the specified
+  grace period, force termination. Used together with the existing
+  `--test-suite-timeout=SECONDS` option.
+* In YAML configuration files, the `recent-snapshots` key is introduced (under
+  the `urls` key), to specify the URL used by Stack's `ls snapshots remote`
+  command.
+* In YAML configuration files (`stack.yaml` and `config.yaml`), an
+  `!include <file path>` directive is now supported. This allows common
+  configuration to be shared across multiple files. For example, a project that
+  maintains multiple project-level configuration files for testing against
+  different snapshots can use `!include` to avoid duplicating shared settings.
+* Stack's `config set` command raises an error if the target configuration file
+  excludes the key being set and includes an `!include` directive.
+* Stack's `config set snapshot` command now works with other snapshot values
+  in addition to snapshot synonymns.
+* Add Stack's `config compiler-tools` command to create (when applicable) the
+  compiler tools directory for the specified compiler version (implies Stack's
+  `config build-files` command).
+
+Bug fixes:
+
+* Stack's `dot` and `ls dependencies` commands no longer prune a package with
+  dependencies only because all its direct dependencies are to be pruned.
+* After March 2026, Hackage requires Stack's user agent to be set when applying
+  digest authentication to a request. Stack's `upload` command now does that,
+  re-establishing authentication by Hackage username and password.
+* Stack 3.9.3 and earlier fail to construct a build plan if project package A
+  depends on project package B and package B's executables (only) depend on
+  package A and the name of A is before that of B, alphabetically. That bug is
+  fixed.
+* Stack's `config set` commands will recreate the `global-project` directory
+  contents, if Stack needs to consult its project-level configuration file and
+  there is no file.
+* The output of Stack's `path --bin-path` command is now consistent with the
+  Stack environment in Stack's `exec` command and includes the `bin` directory
+  of Stack's local install root directory.
+* Stack now builds packages that depend directly on packages with the same name
+  as a sublibrary or foreign library of the package.
+* On Windows, Stack's `build` command now accepts a build directory that is a
+  long path.
+
 ## v3.9.3 - 2026-02-19
 
 Release notes:
@@ -128,7 +208,7 @@   documentation.
 * `stack sdist` and `stack upload` report the version of Cabal (the library)
   being used to check packages.
-* Add the `stack config build-files` command to generate (when applicable) a
+* Add Stack's `config build-files` command to generate (when applicable) a
   Cabal file from a package description in the Hpack format and/or a lock file
   for Stack's project-level configuration, without taking any other build steps.
 
doc/commands/bench_command.md view
@@ -16,12 +16,13 @@             [--[no-]copy-bins] [--[no-]copy-compiler-tool] [--[no-]prefetch]
             [--[no-]keep-going] [--[no-]keep-tmp-files] [--[no-]force-dirty]
             [--[no-]test] [--[no-]rerun-tests] [--ta|--test-arguments TEST_ARGS]
-            [--coverage] [--[no-]run-tests] [--test-suite-timeout ARG]
-            [--[no-]tests-allow-stdin] [--[no-]bench]
-            [--ba|--benchmark-arguments BENCH_ARGS] [--[no-]run-benchmarks]
-            [--[no-]reconfigure] [--cabal-verbosity VERBOSITY |
-              --[no-]cabal-verbose] [--[no-]split-objs] [--skip ARG]
-            [--[no-]interleaved-output] [--ddump-dir ARG]
+            [--coverage] [--[no-]run-tests] [--test-suite-timeout SECONDS]
+            [--test-suite-timeout-grace SECONDS] [--[no-]tests-allow-stdin]
+            [--[no-]bench] [--ba|--benchmark-arguments BENCH_ARGS]
+            [--[no-]run-benchmarks] [--[no-]reconfigure]
+            [--cabal-verbosity VERBOSITY | --[no-]cabal-verbose]
+            [--[no-]split-objs] [--skip ARG] [--[no-]interleaved-output]
+            [--ddump-dir ARG]
 ~~~
 
 `stack bench` is a synonym for `stack build --bench`. For further information,
doc/commands/build_command.md view
@@ -7,21 +7,23 @@             [--flag PACKAGE:[-]FLAG] [--dependencies-only | --only-snapshot |
               --only-dependencies | --only-locals] [--file-watch |
               --file-watch-poll] [--watch-all] [--exec COMMAND [ARGUMENT(S)]]
-            [--only-configure] [--trace] [--profile] [--no-strip]
-            [--[no-]library-profiling] [--[no-]executable-profiling]
-            [--[no-]library-stripping] [--[no-]executable-stripping]
-            [--[no-]haddock] [--haddock-arguments HADDOCK_ARGS]
-            [--[no-]open] [--[no-]haddock-deps] [--[no-]haddock-internal]
+            [--only-configure] [--[no-]semaphore] [--trace] [--profile]
+            [--no-strip] [--[no-]library-profiling]
+            [--[no-]executable-profiling] [--[no-]library-stripping]
+            [--[no-]executable-stripping] [--[no-]haddock]
+            [--haddock-arguments HADDOCK_ARGS] [--[no-]open]
+            [--[no-]haddock-deps] [--[no-]haddock-internal]
             [--[no-]haddock-hyperlink-source] [--[no-]haddock-for-hackage]
             [--[no-]copy-bins] [--[no-]copy-compiler-tool] [--[no-]prefetch]
             [--[no-]keep-going] [--[no-]keep-tmp-files] [--[no-]force-dirty]
             [--[no-]test] [--[no-]rerun-tests] [--ta|--test-arguments TEST_ARGS]
-            [--coverage] [--[no-]run-tests] [--test-suite-timeout ARG]
-            [--[no-]tests-allow-stdin] [--[no-]bench]
-            [--ba|--benchmark-arguments BENCH_ARGS] [--[no-]run-benchmarks]
-            [--[no-]reconfigure] [--cabal-verbosity VERBOSITY |
-              --[no-]cabal-verbose] [--[no-]split-objs] [--skip ARG]
-            [--[no-]interleaved-output] [--ddump-dir ARG]
+            [--coverage] [--[no-]run-tests] [--test-suite-timeout SECONDS]
+            [--test-suite-timeout-grace SECONDS] [--[no-]tests-allow-stdin]
+            [--[no-]bench] [--ba|--benchmark-arguments BENCH_ARGS]
+            [--[no-]run-benchmarks] [--[no-]reconfigure]
+            [--cabal-verbosity VERBOSITY | --[no-]cabal-verbose]
+            [--[no-]split-objs] [--skip ARG] [--[no-]interleaved-output]
+            [--ddump-dir ARG]
 ~~~
 
 `stack build` and its synonyms (`stack test`, `stack bench`, `stack haddock` and
@@ -256,10 +258,11 @@ Pass the flag to enable or disable the ignoring of lower and upper version
 bounds in Cabal files.
 
-!!! info
+!!! warning
 
-    The name `allow-newer` was chosen to match a commonly-used Cabal option
-    which ignored only upper version bounds.
+    This command line flag is misnamed. It causes Stack to ignore all the
+    bounds in the relevant Cabal file(s), not only upper bounds. The name was
+    chosen to match the `--allow-newer` option introduced in `Cabal-1.20.0.0`.
 
 ### `--bench` flag
 
@@ -816,6 +819,33 @@     RTS options must be quoted to prevent the RTS extracting them as its own
     when the Stack executable is run.
 
+### `--test-suite-timeout` option
+
+Default: None
+
+`stack build --test --test-suite-timeout=<seconds>` wraps each running test
+suite in a timeout so that the test suite fails if no result is available within
+the specified number of seconds. The option is ignored if the number of seconds
+is not positive.
+
+!!! note
+
+    The `--test-suite-timeout` option, in isolation, is not guaranteed to
+    terminate a timed-out test suite process. In that regard, see the
+    [`--test-suite-timeout-grace`](#-test-suite-timeout-option).
+
+### `--test-suite-timeout-grace` option
+
+Default: None
+
+`stack build --test --test-suite-timeout=<seconds> --test-suite-timeout-grace=<seconds>`
+uses staged timeout termination for each running test suite: if
+[`--test-suite-timeout`](#-test-suite-timeout-option) causes the test suite to
+fail, Stack requests the termination of the test suite process and waits the
+specified number of seconds as a grace period before termination of the
+process is forced. The option is ignored if the number of seconds is not
+positive.
+
 ## Flags affecting GHC's behaviour
 
 ### `--[no-]executable-profiling` flag
@@ -916,6 +946,32 @@ The flag affects the location of the local project installation directory. See
 the [`stack path --local-install-root`](path_command.md) command.
 
+### `--[no]-semaphore` flag
+
+:octicons-beaker-24: Experimental
+
+[:octicons-tag-24: 3.11.1](https://github.com/commercialhaskell/stack/releases/tag/v3.11.1)
+
+Default: Disabled
+
+This flag allows GHC to use a system semaphore to perform compilation in
+parallel when possible.
+
+!!! info
+
+    GHC 9.8.1 and later can act as a jobserver client, which enables two or more
+    GHC processes running at once to share system resources with each other,
+    communicating via a system semaphore. This GHC feature is supported by
+    Cabal 3.12.0.0 (a boot package of GHC 9.10.1) and later. The flag is ignored
+    with a warning when the feature is unsupported.
+
+!!! warning
+
+    On Linux, musl and non-musl system semaphores are incompatible. That means
+    that a Stack executable built on Alpine Linux (such as the official Stack
+    for Linux) creates system semaphores that cannot be used by a GHC executable
+    built on non-musl Linux distributions.
+
 ### `--[no-]split-objs` flag
 
 :octicons-beaker-24: Experimental
@@ -1017,8 +1073,10 @@ Default: Disabled
 
 Set the flag to enable copying of built executable files (binaries) of targets
-to Stack's compiler tools binary directory (see
-`stack path --compiler-tools-bin`).
+to Stack's
+[compiler tools directory](../topics/stack_root.md#compiler-tools-directory-optional)
+for the specified compiler version (see Stack's
+[`path --compiler-tools-bin` command](path_command.md)).
 
 ### `--coverage` flag
 
@@ -1140,7 +1198,7 @@ nothing on the standard input stream (`stdin`). Pass this flag to override that
 specification and allow the executable to receive input on that stream. If you
 pass `--no-tests-allow-stdin` and the executable seeks input on the standard
-input stream, an exception will be thown.
+input stream, an exception will be thrown.
 
 ## Examples
 
doc/commands/config_command.md view
@@ -9,6 +9,9 @@   build-files              Generate (when applicable) a Cabal file from a
                            package description in the Hpack format and/or a lock
                            file for Stack's project-level configuration.
+  compiler-tools-bin       Create (when applicable) the compiler tools
+                           directory for the specified compiler version (implies
+                           'config build-files').
   env                      Print environment variables for use in a shell.
   set                      Set a key in a configuration file to value.
 ~~~
@@ -32,6 +35,19 @@ 
 without taking any other build steps.
 
+## The `stack config compiler-tools` command
+
+[:octicons-tag-24: 3.11.1](https://github.com/commercialhaskell/stack/releases/tag/v3.11.1)
+
+~~~text
+stack config compiler-tools
+~~~
+
+`stack config compiler-tools` creates (when applicable) the
+[compiler tools directory](../topics/stack_root.md#compiler-tools-directory-optional)
+for the specified compiler version. Implies Stack's
+[`config build-files` command](#the-stack-config-build-files-command).
+
 ## The `stack config env` command
 
 ~~~text
@@ -40,7 +56,8 @@ ~~~
 
 `stack config env` outputs a script that sets or unsets environment variables
-for a Stack environment. Flags modify the script that is output:
+for a [Stack environment](../topics/stack_environment.md). Flags modify the
+script that is output:
 
 * `--[no-]locals` (enabled by default) include/exclude project package
   information
@@ -50,7 +67,7 @@   or not
 * `--[no-]locale-utf8` (disabled by default) set the `GHC_CHARENC`
   environment variable to `UTF-8` or not
-* `--[no-]keep-ghc-rts` (disabled by default) keep/discard any `GHCRTS`
+* `--[no-]keep-ghc-rts` (enabled by default) keep/discard any `GHCRTS`
   environment variable
 
 The command also accepts flags and options of the
@@ -87,6 +104,14 @@     The `config set` commands support an existing key only in the form
     `key: value` on a single line.
 
+!!! warning
+
+    The `config set` commands cannot add a new key to a configuration file that
+    uses [`!include`](../configure/yaml/include.md) directives. Stack will report
+    an error if it detects `!include` directives in the target configuration file
+    and the key being set is not already present. Existing keys can be modified
+    even in files that use `!include`.
+
 ## The `stack config set install-ghc` command
 
 ~~~text
@@ -170,6 +195,9 @@ A snapshot of `lts` or `nightly` will be translated into the most recent
 available. A snapshot of `lts-22` will be translated into the most recent
 available in the `lts-22` sequence.
+
+Snapshot values that are compiler versions, a URL or a local file path are also
+accepted.
 
 If a (deprecated) `resolver` key is present, it will be replaced by a `snapshot`
 key.
doc/commands/dot_command.md view
@@ -4,8 +4,8 @@ 
 ~~~text
 stack dot [--[no-]external] [--[no-]include-base] [--depth DEPTH]
-          [--prune PACKAGES] [TARGET] [--flag PACKAGE:[-]FLAG]
-          [--test] [--bench] [--global-hints]
+          [--prune PACKAGES] [--reach PACKAGES] [TARGET]
+          [--flag PACKAGE:[-]FLAG] [--test] [--bench] [--global-hints]
 ~~~
 
 A package and its dependencies and the direct dependency relationships between
@@ -28,8 +28,10 @@     `--depth <depth>` option to limit the depth;
 *   all relevant packages are included in the output. Pass the
     `--prune <packages>` option to exclude the specified packages (including
-    project packages), where `<packages>` is a list of package names separated
-    by commas;
+    project packages). Pass the `--reach <packages>` option to exclude packages
+    (including project packages) that cannot reach any of the specified packages
+    in the dependency graph. In both cases, `<packages>` is a list of package
+    names separated by commas;
 *   for all relevant project packages, relevant dependencies are included in the
     output. However, each project package for which dependencies are included
     can be specified as a target argument. The argument uses the same format as
@@ -113,3 +115,12 @@     ~~~
 
     [![wreq-example6.svg](https://cdn.jsdelivr.net/gh/commercialhaskell/stack@master/doc/img/dot_command/wreq-example6.svg)](https://cdn.jsdelivr.net/gh/commercialhaskell/stack@master/doc/img/dot_command/wreq-example6.svg)
+
+*   Include external dependencies and prune packages that cannot reach any of
+    `memory` and `basement` in the dependency graph:
+
+    ~~~text
+    stack dot --external --reach memory,basement | dot -Tsvg -o wreq-example7.svg
+    ~~~
+
+    [![wreq-example7.svg](https://cdn.jsdelivr.net/gh/commercialhaskell/stack@master/doc/img/dot_command/wreq-example7.svg)](https://cdn.jsdelivr.net/gh/commercialhaskell/stack@master/doc/img/dot_command/wreq-example7.svg)
doc/commands/exec_command.md view
@@ -9,10 +9,11 @@            [--rts-options RTSFLAG] [--cwd DIR]
 ~~~
 
-`stack exec` executes the specified executable as a command in the Stack
-environment. If an executable is not specified, the first argument after `--` is
-taken to be the executable. Otherwise, all arguments after `--` are taken to be
-command line arguments for the specified executable.
+`stack exec` executes the specified executable as a command in the
+[Stack environment](../topics/stack_environment.md). If an executable is not
+specified, the first argument after `--` is taken to be the executable.
+Otherwise, all arguments after `--` are taken to be command line arguments for
+the specified executable.
 
 By default:
 
doc/commands/haddock_command.md view
@@ -17,7 +17,8 @@               [--[no-]keep-going] [--[no-]keep-tmp-files] [--[no-]force-dirty]
               [--[no-]test] [--[no-]rerun-tests]
               [--ta|--test-arguments TEST_ARGS] [--coverage] [--[no-]run-tests]
-              [--test-suite-timeout ARG] [--[no-]tests-allow-stdin]
+              [--test-suite-timeout SECONDS]
+              [--test-suite-timeout-grace SECONDS] [--[no-]tests-allow-stdin]
               [--[no-]bench] [--ba|--benchmark-arguments BENCH_ARGS]
               [--[no-]run-benchmarks] [--[no-]reconfigure]
               [--cabal-verbosity VERBOSITY | --[no-]cabal-verbose]
doc/commands/index.md view
@@ -65,7 +65,8 @@ 
 ### Executing in the Stack environment
 
-* [`exec`](exec_command.md) - executate a command in the Stack environment
+* [`exec`](exec_command.md) - executate a command in the
+  [Stack environment](../topics/stack_environment.md)
 * [`ghc`](ghc_command.md) - run `ghc`
 * [`eval`](eval_command.md) - evaluate some Haskell code inline
 * [`runghc`](runghc_command.md) - run `runghc`
@@ -130,7 +131,8 @@ * [`docker`](docker_command.md) - use Stack with Docker
 * [`dot`](dot_command.md) - dependency visualization
 * [`eval`](eval_command.md) - evaluate some Haskell code inline
-* [`exec`](exec_command.md) - executate a command in the Stack environment
+* [`exec`](exec_command.md) - executate a command in the
+  [Stack environment](../topics/stack_environment.md)
 * [`haddock`](build_command.md) - a synonym for `stack build --haddock`
 * [`hoogle`](hoogle_command.md) - run `hoogle`
 * [`hpc`](hpc_command.md) - generate Haskell Program Coverage (HPC) code
doc/commands/install_command.md view
@@ -17,7 +17,8 @@               [--[no-]keep-going] [--[no-]keep-tmp-files] [--[no-]force-dirty]
               [--[no-]test] [--[no-]rerun-tests]
               [--ta|--test-arguments TEST_ARGS] [--coverage] [--[no-]run-tests]
-              [--test-suite-timeout ARG] [--[no-]tests-allow-stdin]
+              [--test-suite-timeout SECONDS]
+              [--test-suite-timeout-grace SECONDS] [--[no-]tests-allow-stdin]
               [--[no-]bench] [--ba|--benchmark-arguments BENCH_ARGS]
               [--[no-]run-benchmarks] [--[no-]reconfigure]
               [--cabal-verbosity VERBOSITY | --[no-]cabal-verbose]
doc/commands/list_command.md view
@@ -45,17 +45,17 @@          tasty, retry, path, pretty, pasty, xattr, alloy, para, pappy and
          alure.
 
-stack --snapshot lts-24.24 list base unix Win32 acme-missiles pantry
+stack --snapshot lts-24.43 list base unix Win32 acme-missiles pantry
 Error: [S-4926]
        * Package does not appear in snapshot (directly or indirectly): acme-missiles.
 
-stack --snapshot lts-24.24 list base unix Win32 pantry
+stack --snapshot lts-24.43 list base unix Win32 pantry
 base-4.20.2.0
 unix-2.8.7.0
 Win32-2.14.1.0
 pantry-0.10.1
 
-stack --snapshot lts-24.24 list
+stack --snapshot lts-24.43 list
 AC-Angle-1.0
 ALUT-2.4.0.3
 ...
doc/commands/ls_command.md view
@@ -69,8 +69,10 @@     `--depth <depth>` option to limit the depth;
 *   all relevant packages are included in the output. Pass the
     `--prune <packages>` option to exclude the specified packages (including
-    project packages), where `<packages>` is a list of package names separated
-    by commas;
+    project packages). Pass the `--reach <packages>` option to exclude packages
+    (including project packages) that cannot reach any of the specified packages
+    in the dependency graph. In both cases, `<packages>` is a list of package
+    names separated by commas;
 *   for all relevant project packages, relevant dependencies are included in the
     output. However, each project package for which dependencies are included
     can be specified as a target argument. The argument uses the same format as
doc/commands/path_command.md view
@@ -18,10 +18,10 @@ 
 |Flag                   |File or location                                      |
 |-----------------------|------------------------------------------------------|
-|--bin-path             |The PATH in the Stack environment.                    |
+|--bin-path             |The PATH in the [Stack environment](../topics/stack_environment.md).|
 |--compiler-bin         |The directory containing the GHC executable.          |
 |--compiler-exe         |The GHC executable.                                   |
-|--compiler-tools-bin   |The directory containing binaries specific to a particular compiler.|
+|--compiler-tools-bin   |The [compiler tools directory](../topics/stack_root.md#compiler-tools-directory-optional) for the specified compiler version.|
 |--config-location      |Stack's project-level configuration file (`stack.yaml`, by default).|
 |--dist-dir             |The dist work directory, relative to the package directory.|
 |--extra-include-dirs   |Extra include directories.                            |
@@ -36,11 +36,11 @@ |--local-install-root   |The root directory for local project installation.    |
 |--local-pkg-db         |The local package database.                           |
 |--programs             |The root directory for GHC and other Stack-supplied tools.|
-|--project-root         |The project root directory.|
+|--project-root         |The project root directory.                           |
 |--snapshot-doc-root    |The root directory for snapshot documentation.        |
 |--snapshot-install-root|The root directory for snapshot installation.         |
 |--snapshot-pkg-db      |The snapshot package database.                        |
-|--stack-root           |The Stack root.                                       |
+|--stack-root           |The [Stack root](../topics/stack_root.md).            |
 
 The command also accepts flags and options of the
 [`stack build`](build_command.md#flags-affecting-ghcs-behaviour) command that
doc/commands/script_command.md view
@@ -49,7 +49,7 @@ For example:
 
 ~~~text
-stack script --snapshot lts-24.24 MyScript.hs
+stack script --snapshot lts-24.43 MyScript.hs
 ~~~
 
 An immutable extra-dep can be added to the snapshot on the command line with the
@@ -211,7 +211,7 @@ can be compiled and run, with arguments, with:
 
 ~~~text
-stack --snapshot lts-24.24 script --package acme-missiles --compile MyScript.hs -- "Don't panic!" "Duck and cover!"
+stack --snapshot lts-24.43 script --package acme-missiles --compile MyScript.hs -- "Don't panic!" "Duck and cover!"
 ~~~
 
 `acme-missiles-0.3` (the most recent version in the package index) will be used.
@@ -231,7 +231,7 @@ 
 ~~~haskell
 {- stack script
-   -- snapshot lts-24.24
+   -- snapshot lts-24.43
    -- extra-dep acme-missiles-0.2
    -- package acme-missiles
 -}
@@ -333,7 +333,7 @@ 
 ~~~haskell
 {- stack script
-   --snapshot lts-24.24
+   --snapshot lts-24.43
 -}
 
 {-# LANGUAGE OverloadedStrings #-}
doc/commands/test_command.md view
@@ -16,12 +16,13 @@             [--[no-]copy-bins] [--[no-]copy-compiler-tool] [--[no-]prefetch]
             [--[no-]keep-going] [--[no-]keep-tmp-files] [--[no-]force-dirty]
             [--[no-]test] [--[no-]rerun-tests] [--ta|--test-arguments TEST_ARGS]
-            [--coverage] [--[no-]run-tests] [--test-suite-timeout ARG]
-            [--[no-]tests-allow-stdin] [--[no-]bench]
-            [--ba|--benchmark-arguments BENCH_ARGS] [--[no-]run-benchmarks]
-            [--[no-]reconfigure] [--cabal-verbosity VERBOSITY |
-              --[no-]cabal-verbose] [--[no-]split-objs] [--skip ARG]
-            [--[no-]interleaved-output] [--ddump-dir ARG]
+            [--coverage] [--[no-]run-tests] [--test-suite-timeout SECONDS]
+            [--test-suite-timeout-grace SECONDS] [--[no-]tests-allow-stdin]
+            [--[no-]bench] [--ba|--benchmark-arguments BENCH_ARGS]
+            [--[no-]run-benchmarks] [--[no-]reconfigure]
+            [--cabal-verbosity VERBOSITY | --[no-]cabal-verbose]
+            [--[no-]split-objs] [--skip ARG] [--[no-]interleaved-output]
+            [--ddump-dir ARG]
 ~~~
 
 `stack test` is a synonym for `stack build --test`. For further information,
doc/configure/global_flags.md view
@@ -145,13 +145,22 @@ ## `--[no-]install-ghc` flag
 
 Default: Enabled
+([:octicons-tag-24: 1.6.1](https://github.com/commercialhaskell/stack/releases/tag/v1.6.1))
 
-Enables/disables the download and installation of GHC when necessary. On
-Windows, `--no-install-ghc` also disables the download and installation of the
-Stack-supplied MSYS2 when necessary. For further information, see the
+If the specified GHC version is not available, enables/disables Stack seeking to
+download and install that version if it is needed. On Windows,
+`--no-install-ghc` also disables the download and installation of the
+Stack-supplied MSYS2 when it is needed. For further information, see the
 documentation for the corresponding non-project specific configuration
 [option](yaml/non-project.md#install-ghc).
 
+!!! note
+
+    The `--[no-]install-ghc` flag does not specify whether Stack checks the
+    availability of either a 'system' GHC executable on the PATH or a
+    Stack-supplied GHC executable. In that regard, see the
+    [`system-ghc`](yaml/non-project.md#system-ghc) option.
+
 ## `--[no-]install-msys` flag
 
 [:octicons-tag-24: 3.5.1](https://github.com/commercialhaskell/stack/releases/tag/v3.5.1)
@@ -329,9 +338,18 @@ ## `--[no-]system-ghc` flag
 
 Default: Disabled
+([:octicons-tag-24: 1.3.0](https://github.com/commercialhaskell/stack/releases/tag/v1.3.0))
 
-Enables/disables the use of a GHC executable on the PATH, if one is available
-and its version matches.
+Enables/disables Stack seeking to use a 'system' GHC executable (that is, one on
+the PATH) rather than a Stack-supplied GHC executable (or vice versa, if
+disabled). For further information, see the documentation for the corresponding
+non-project specific configuration [option](yaml/non-project.md#system-ghc).
+
+!!! note
+
+    The `--[no-]system-ghc` flag does not specify Stack's behaviour if the
+    specified GHC version is not already available. In that regard, see the
+    [`install-ghc`](yaml/non-project.md#install-ghc) option.
 
 ## `--[no-]terminal` flag
 
+ doc/configure/yaml/include.md view
@@ -0,0 +1,117 @@+<div class="hidden-warning"><a href="https://docs.haskellstack.org/"><img src="https://cdn.jsdelivr.net/gh/commercialhaskell/stack/doc/img/hidden-warning.svg"></a></div>
+
+# The `!include` directive
+
+Stack's configuration files are in the [YAML](https://yaml.org/) format. Stack
+also supports the use of an `!include` local tag together with scalar content
+that represents an absolute or relative path to another file. This provides a
+directive that allows the content of one YAML file to be included in another.
+
+The directive can be used in both
+[project-level and global](index.md#project-level-and-global-configuration-files)
+configuration files.
+
+!!! note
+
+    An included relative file path is relative to the directory containing the
+    file with the `!include` directive.
+
+!!! warning
+
+    The [`stack config set`](../../commands/config_command.md#the-stack-config-set-commands)
+    commands cannot modify a configuration file that excludes the relevant key
+    and uses `!include` directives.
+
+## Including a value
+
+A value for a key can be provided by an included file. For example, given a file
+`snapshot.yaml` in the project directory with the content:
+
+~~~yaml
+lts-24.43
+~~~
+
+the following project-level configuration file would use `lts-24.43` as the
+snapshot:
+
+~~~yaml
+snapshot: !include snapshot.yaml
+~~~
+
+The included file replaces the `!include` directive with its content, so this is
+equivalent to:
+
+~~~yaml
+snapshot: lts-24.43
+~~~
+
+## Including a sequence
+
+The value provided by an included file is not limited to scalar content. It can
+be a YAML sequence. For example, given a file `extra-deps.yaml` in the project
+directory with the content:
+
+~~~yaml
+- acme-missiles-0.3
+- text-short-0.1.6
+~~~
+
+the following project-level configuration file would use those as extra-deps:
+
+~~~yaml
+snapshot: lts-24.43
+extra-deps: !include extra-deps.yaml
+~~~
+
+## Merging mappings
+
+YAML's merge key (`<<`) is used to indicate that all of the keys of one or more
+specified mappings should be inserted into the current mapping.
+
+YAML's merge key can be combined with an `!include` directive to merge the
+content of an included file into the current mapping. For example, given a file
+`shared-config.yaml` in the project directory with the content:
+
+~~~yaml
+ghc-options:
+  "$everything": -Wall
+flags:
+  my-package:
+    my-flag: true
+~~~
+
+the following project-level configuration file would merge those options:
+
+~~~yaml
+snapshot: lts-24.43
+<<: !include shared-config.yaml
+~~~
+
+This is equivalent to:
+
+~~~yaml
+snapshot: lts-24.43
+ghc-options:
+  "$everything": -Wall
+flags:
+  my-package:
+    my-flag: true
+~~~
+
+The `!include` directive can also be placed on the line after the merge key:
+
+~~~yaml
+snapshot: lts-24.43
+<<:
+  !include shared-config.yaml
+~~~
+
+## Nested includes
+
+Included files can themselves contain `!include` directives, allowing for nested
+composition of configuration.
+
+!!! note
+
+    A file cannot include itself or a file that has already included the file.
+    Stack detects and raises an error for cyclic includes.
doc/configure/yaml/index.md view
@@ -6,7 +6,8 @@ # Configuration files
 
 Stack is configured by the content of files in the [YAML](https://yaml.org/)
-format.
+format. Stack also supports an [`!include` directive](include.md) that allows a
+configuration file to include the contents of another file.
 
 ## Project-specific and non-project specific options
 
doc/configure/yaml/non-project.md view
@@ -48,12 +48,15 @@ [`stack build --[no-]allow-newer`](../../commands/build_command.md#-no-allow-newer-flag)
 flag
 
-Whether to ignore lower and upper version bounds in Cabal files.
+!!! warning
 
-!!! info
+    This configuration option is misnamed. It causes Stack to ignore all the
+    bounds in the relevant Cabal file(s), not only upper bounds. The name was
+    chosen to match the `--allow-newer` option introduced in `Cabal-1.20.0.0`.
 
-    The name `allow-newer` was chosen to match a commonly-used Cabal option
-    which ignored only upper bounds.
+Whether to ignore all version bounds (upper and lower) in Cabal files. See the
+[`allow-newer-deps`](#allow-newer-deps) configuration option to specify the
+scope of application when `allow-newer` is `true`.
 
 ~~~yaml
 allow-newer: true
@@ -63,15 +66,20 @@ 
 [:octicons-tag-24: 2.9.3](https://github.com/commercialhaskell/stack/releases/tag/v2.9.3)
 
-Default: `none`
+Default: all packages (if `allow-newer` is `true`)
 
-Determines a subset of packages to which `allow-newer` should apply. This option
-has no effect (but warns) if `allow-newer` is `false`.
+See the [`allow-newer`](#allow-newer) configuration option.
 
+When `allow-newer` is `false`, this option has no effect (but warns).
+
+When `allow-newer` is `true`, this option specifies the scope of application
+for `allow-newer`. That is, the set of packages for which all version bounds
+(upper and lower) should be ignored in the packages' Cabal files.
+
 ~~~yaml
 allow-newer-deps:
-  - foo
-  - bar
+- myPackageA
+- myPackageB
 ~~~
 
 ## apply-ghc-options
@@ -157,6 +165,11 @@ 
 ~~~yaml
 build:
+  # Experimental. Since Stack 3.11.1. Supported by GHC 9.8.1 or later with
+  # Cabal 3.12.0.0 (a boot package of GHC 9.10.1) or later. Ignored with a
+  # warning when unsupported.
+  semaphore: false
+
   library-profiling: false
   executable-profiling: false
   library-stripping: true
@@ -209,6 +222,10 @@     additional-args: []
     coverage: false
     no-run-tests: false
+    # The option is ignored if the specified number of seconds is not positive:
+    test-suite-timeout: 0
+    # The option is ignored if the specified number of seconds is not positive:
+    test-suite-timeout-grace: 0
   bench: false
   benchmark-opts:
 
@@ -300,7 +317,7 @@ Stackage snapshot, like this:
 
 ~~~yaml
-snapshot: lts-24.24
+snapshot: lts-24.43
 compiler: ghc-9.10.2
 compiler-check: match-exact
 ~~~
@@ -622,7 +639,7 @@   so `stack setup` knows where to download it,
   or pass the `stack setup --ghc-bindist` argument on the command-line
 
-This option is incompatible with `system-ghc: true`.
+This option is incompatible with [`system-ghc: true`](#system-ghc).
 
 ## global-hints-location
 
@@ -727,15 +744,30 @@ ## install-ghc
 
 Default: `true`
-([:octicons-tag-24: 1.5.0](https://github.com/commercialhaskell/stack/releases/tag/v1.5.0))
+([:octicons-tag-24: 1.6.1](https://github.com/commercialhaskell/stack/releases/tag/v1.6.1))
 
 Command line equivalent (takes precedence):
 [`--[no-]install-ghc`](../global_flags.md#-no-install-ghc-flag) flag
 
-Whether or not to download and install GHC when necessary. On Windows,
-`install-ghc: false` also disables the download and installation of the
-Stack-supplied MSYS2 when necessary.
+If the specified GHC version is not available, (if `true`) should Stack seek to
+download and install that version when it is needed or (if `false`) fail
+(reporting that the specified compiler is not available)?
 
+~~~yaml
+# Even if needed, do not seek to download and install a Stack-supplied GHC:
+install-ghc: false
+~~~
+
+On Windows, `install-ghc: false` also disables the download and installation of
+the Stack-supplied MSYS2 when it is needed.
+
+!!! note
+
+    The `install-ghc` option does not specify whether Stack checks the
+    availability of either a 'system' GHC executable on the PATH or a
+    Stack-supplied GHC executable. In that regard, see the
+    [`system-ghc`](#system-ghc) option.
+
 ## install-msys
 
 [:octicons-tag-24: 3.5.1](https://github.com/commercialhaskell/stack/releases/tag/v3.5.1)
@@ -749,7 +781,7 @@ [`--[no-]install-msys`](../global_flags.md#-no-install-msys-flag) flag
 
 If Stack is checking for the Stack-supplied MSYS2 when Stack is setting up the
-environment, whether or not to download and install MSYS2 when necessary.
+environment, whether or not to download and install MSYS2 when it is needed.
 
 To skip entirely checking for the Stack-supplied MSYS2, see the documentation
 for the [`skip-msys`](#skip-msys) configuration option.
@@ -922,7 +954,9 @@ 
 Restrictions: Windows systems only.
 
-Default: `MINGW64` (64-bit Windows) or `MINGW32` (32-bit Windows)
+Default:
+([:octicons-tag-24: 3.11.1](https://github.com/commercialhaskell/stack/releases/tag/v3.11.1))
+`CLANG64` (64-bit Windows)
 
 The name of the MSYS2 environment (case-sensitive) used in the Stack
 environment. Valid environments are `CLANG32`, `CLANG64`, `CLANGARM64`,
@@ -1471,22 +1505,30 @@ 
 ## system-ghc
 
-Default: `false`, unless the [Docker](../../topics/docker_integration.md) or
+Default: `false`
+([:octicons-tag-24: 1.3.0](https://github.com/commercialhaskell/stack/releases/tag/v1.3.0)),
+unless the [Docker](../../topics/docker_integration.md) or
 [Nix](../../topics/nix_integration.md) integration is enabled.
 
 Command line equivalent (takes precedence): `--[no-]system-ghc` flag
 
-Enables or disables using the GHC available on the PATH. (Make sure PATH is
-explicit, i.e., do not use ~.) Useful to enable if you want to save the time,
-bandwidth or storage space needed to setup an isolated GHC.
-
-In a Nix-enabled configuration, Stack is incompatible with `system-ghc: false`.
+Should Stack seek to use (if `true`) a 'system' GHC executable (that is, one on
+the PATH) or (if `false`) a Stack-supplied GHC executable?
 
 ~~~yaml
-# Turn on system GHC
+# Seek to use a 'system' GHC on the PATH rather than a Stack-supplied GHC:
 system-ghc: true
 ~~~
 
+Stack's [Nix integration](../../topics/nix_integration.md), when enabled, is
+incompatible with `system-ghc: false`.
+
+!!! note
+
+    The `system-ghc` option does not specify Stack's behaviour if the specified
+    GHC version is not already available. In that regard, see the
+    [`install-ghc`](#install-ghc) option.
+
 ## templates
 
 Command line equivalent (takes precedence): `stack new --param <key>:<value>`
@@ -1554,17 +1596,29 @@ ~~~yaml
 urls:
   latest-snapshot: https://stackage-haddock.haskell.org/snapshots.json
+  recent-snapshots: https://www.stackage.org/api/v1/snapshots
 ~~~
 
-Customize the URLs where Stack looks for snapshot build plans.
+Customize the URLs where Stack looks for information about available snapshots,
+either
+([:octicons-tag-24: 1.1.0](https://github.com/commercialhaskell/stack/releases/tag/v1.1.0))
+the latest LTS and Nightly snapshots (`latest-snapshots`) or
+([:octicons-tag-24: 3.11.1](https://github.com/commercialhaskell/stack/releases/tag/v3.11.1))
+recently-published snapshots (`recent-snapshots`).
 
 !!! note
 
-    The default for Stack 1.3.0 to 2.15.3 was
+    The default for `latest-snapshots` for Stack 1.3.0 to 2.15.3 was
     https://s3.amazonaws.com/haddock.stackage.org/snapshots.json. Following the
     handover of the Stackage project to the Haskell Foundation in
     early 2024, the file at that URL may not be up to date. Users of those
     versions of Stack should configure the URL to be the default above.
+
+!!! note
+
+    The default for `recent-snapshots` for Stack 1.7.1 to 3.9.3 was
+    https://www.stackage.org/snapshots. The Stackage server API may cease to use
+    that end point in the future.
 
 ## with-gcc
 
doc/configure/yaml/project.md view
@@ -39,13 +39,13 @@ installation, and various settings like build flags. For example:
 
 ~~~yaml
-snapshot: lts-24-30 # A Stackage LTS Haskell snapshot
+snapshot: lts-24.43 # A Stackage LTS Haskell snapshot
 ~~~
 
 or
 
 ~~~yaml
-snapshot: nightly-2026-02-09 # A Stackage Nightly snapshot
+snapshot: nightly-2026-05-29 # A Stackage Nightly snapshot
 ~~~
 
 For further information about how to specify the location of a snapshot, see the
doc/faq.md view
@@ -59,7 +59,8 @@ ??? question "Can I run `cabal` commands inside `stack exec`?"
 
     Yes. Some `cabal` commands are inconsistent with the `GHC_PACKAGE_PATH`
-    environment variable in the Stack environment. Command, for example:
+    environment variable in the
+    [Stack environment](topics/stack_environment.md). Command, for example:
 
     ~~~text
     stack exec --no-ghc-package-path -- cabal build
doc/maintainers/stack_errors.md view
@@ -5,7 +5,7 @@ In connection with considering Stack's support of the
 [Haskell Error Index](https://errors.haskell.org/) initiative, this page seeks
 to take stock of the errors that Stack itself can raise, by reference to the
-`master` branch of the Stack repository. Last updated: 2025-08-16.
+`master` branch of the Stack repository. Last updated: 2026-04-24.
 
 *   `Stack.main`: catches exceptions from action `commandLineHandler`.
 
@@ -78,18 +78,19 @@         [S-8575] = SnapshotNotSupportedException (Maybe Project) (Maybe AbstractSnapshot)
         ~~~
 
-    -   `Stack.Config.Nix.ConfigNixException`
+    -   `Stack.Config.Nix.ConfigNixPrettyException`
 
         ~~~haskell
-        [S-2726] = NixCannotUseShellFileAndPackagesException
+        [S-2726] = NixCannotUseShellFileAndPackagesException FilePath [Text]
         [S-9317] | GHCMajorVersionUnspecified
         [S-8605] | OnlyGHCSupported
         ~~~
 
-    -   `Stack.ConfigCmd.ConfigCmdException`
+    -   `Stack.ConfigCmd.ConfigCmdPrettyException`
 
         ~~~haskell
         [S-3136] = NoProjectConfigAvailable
+        [S-6088] | ConfigFileContainsIncludes (Path Abs File)
         ~~~
 
     -   `Stack.Constants.ConstantsException`
@@ -190,10 +191,11 @@         [S-1353] = WritingLockFileError (Path Abs File) Locked
         ~~~
 
-    -   `Stack.Ls.LsException` *
+    -   `Stack.Ls.LsPrettyException`
 
         ~~~haskell
         [S-3421] = ParseFailure [Value]
+        [S-9131] | ParseRecentSnapshotsUrlFailed HttpException
         ~~~
 
     -   `Stack.New.NewPrettyException`
@@ -208,7 +210,7 @@         [S-3113] | AttemptedOverwrites [Path Abs File]
         ~~~
 
-    -   `Stack.Nix.NixException`
+    -   `Stack.Nix.NixPrettyException`
 
         ~~~haskell
         [S-7384] = CannotDetermineProjectRoot
@@ -349,8 +351,6 @@         [S-5797] | LocalPackageDoesn'tMatchTarget PackageName Version Version
         [S-3118] | NoSetupHsFound (Path Abs Dir)
         [S-4925] | InvalidGhcOptionsSpecification [PackageName]
-        [S-7987] | TestSuiteExeMissing Bool String String String
-        [S-8027] | CabalCopyFailed Bool String
         [S-5510] | LocalPackagesPresent [PackageIdentifier]
         [S-7168] | CouldNotLockDistDir (Path Abs File)
         [S-7868] | TaskCycleBug PackageIdentifier
@@ -377,6 +377,8 @@         [S-1727] | NotOnlyLocal [PackageName] [Text]
         [S-6362] | CompilerVersionMismatch (Maybe (ActualCompiler, Arch)) (WantedCompiler, Arch) GHCVariant CompilerBuild VersionCheck WantedCompilerSetter Text
         [S-4660] | ActionNotFilteredBug StyleDoc
+        [S-7987] | TestSuiteExeMissing Bool String PackageName StackUnqualCompName
+        [S-8027] | CabalCopyFailed Bool BuildPrettyException
         ~~~
 
     -   `Stack.Types.Compiler.CompilerException`
doc/topics/GHC_from_source.md view
@@ -167,25 +167,25 @@     ~~~pwsh
     stack exec -- pacman --sync --refresh
     # Synchronize MSYS2 package databases
-    stack exec -- pacman --sync mingw-w64-x86_64-python-pip
+    stack exec -- pacman --sync mingw-w64-clang-x86_64-python-pip
     # The PyPA recommended tool (pip) for installing Python packages. Also
     # installs Python as a dependency. GHC uses a Python script named `boot`.
-    # The package must be the one from the `mingw64` MSYS2 repository, as Python
+    # The package must be the one from the `clang64` MSYS2 repository, as Python
     # from the `msys` repository cannot interpret Windows file paths correctly.
-    stack exec -- pacman --sync mingw-w64-x86_64-autotools
+    stack exec -- pacman --sync mingw-w64-clang-x86_64-autotools
     # The GNU autotools build system, including `autoreconf`, `aclocal`
     # and `make`. GHC uses a sh script named `configure` which is itself created
     # from a file named `configure.ac`.
     stack exec -- pacman --sync patch
     # A utility to apply patch files to original sources.
-    stack exec -- pacman --sync texinfo
+    stack exec -- pacman --sync mingw-w64-clang-x86_64-texinfo
     # Utilities to work with and produce manuals, ASCII text, and on-line
     # documentation from a single source file, including `makeinfo`.
-    stack exec -- pacman --sync mingw-w64-x86_64-ca-certificates
+    stack exec -- pacman --sync mingw-w64-clang-x86_64-ca-certificates
     # Common CA (certificate authority) certificates.
-    stack exec -- pacman -sync mingw-w64-x86_64-python-sphinx
+    stack exec -- pacman -sync mingw-w64-clang-x86_64-python-sphinx
     # Sphinx is the Python documentation generator.
-    stack exec -- pacman -sync mingw-w64-x86_64-texlive-full
+    stack exec -- pacman -sync mingw-w64-clang-x86_64-texlive-full
     # The TeX Live distribution.
     ~~~
 
doc/topics/Stack_and_VS_Code.md view
@@ -150,7 +150,7 @@ 
         Each time that a snapshot is used that references a different version of
         GHC, then GHCup must be used to install it (if GHCup has not already
-        installed that version). For example, to use `snapshot: lts-24.24`
+        installed that version). For example, to use `snapshot: lts-24.43`
         (GHC 9.10.3), the command `ghcup install ghc 9.10.3` must have been used
         to install GHC 9.10.3. That may be a minor inconvenience for some people,
         as one the primary benefits of Stack over other tools for building
doc/topics/custom_snapshot.md view
@@ -29,7 +29,7 @@ ~~~yaml
 # Inherits a specific GHC version and, implicitly, its boot packages and
 # specific versions of a set of other packages:
-snapshot: lts-24.24
+snapshot: lts-24.43
 # Overwrites the version of GHC (and, implicitly, its boot packages) specified
 # in the snapshot (optional):
 compiler: ghc-9.10.2
@@ -75,36 +75,36 @@ 
 ### Overriding the compiler
 
-The following snapshot specification will be identical to `lts-24.24`, but
+The following snapshot specification will be identical to `lts-24.43`, but
 instead use `ghc-9.10.2` and its boot packages instead of `ghc-9.10.3` and its
 boot packages:
 
 ~~~yaml
-snapshot: lts-24.24 # GHC 9.10.3
+snapshot: lts-24.43 # GHC 9.10.3
 compiler: ghc-9.10.2
 ~~~
 
 ### Dropping packages
 
-The following snapshot specification will be identical to `lts-24.24`, but
+The following snapshot specification will be identical to `lts-24.43`, but
 without the `text` package in our snapshot. Removing this package will cause all
 the packages that depend on `text` to be unbuildable, but they will still be
 present in the snapshot.
 
 ~~~yaml
-snapshot: lts-24.24
+snapshot: lts-24.43
 drop-packages:
 - text
 ~~~
 
 ### Hiding packages
 
-The following snapshot specification will be identical to `lts-24.24`, but the
+The following snapshot specification will be identical to `lts-24.43`, but the
 `text` package will be hidden when registering. This will affect, for example,
 the import parser in the script command.
 
 ~~~yaml
-snapshot: lts-24.24
+snapshot: lts-24.43
 hidden:
 - text
 ~~~
@@ -115,11 +115,11 @@ [ghc-options](../configure/yaml/non-project.md#ghc-options) key for build
 configuration.
 
-The following snapshot specification will be identical to `lts-24.24`, but
+The following snapshot specification will be identical to `lts-24.43`, but
 provides `-O1` as a ghc-option for `text`:
 
 ~~~yaml
-snapshot: lts-24.24
+snapshot: lts-24.43
 packages:
 - text-2.1.2
 ghc-options:
@@ -138,11 +138,11 @@ 
 In order to specify Cabal flags for a package, you use the same syntax as the
 [flags](../configure/yaml/project.md#flags) key for build configuration. The
-following snapshot specification will be identical to `lts-24.24`, but
+following snapshot specification will be identical to `lts-24.43`, but
 it enables the `developer` Cabal flag:
 
 ~~~yaml
-snapshot: lts-24.24
+snapshot: lts-24.43
 packages:
 - text-2.1.2
 flags:
doc/topics/developing_on_windows.md view
@@ -3,11 +3,11 @@ # Developing on Windows #
 
 On Windows, Stack comes with an installation of [MSYS2](https://www.msys2.org/).
-An environment of MSYS2 (by default, `MINGW64` on 64-bit Windows or `MINGW32` on
-32-bit Windows) will be used by Stack to provide a Unix-like shell and
-environment for Stack. This may be necessary for installing some Haskell
-packages, such as those which use `configure` scripts, or if your project needs
-some additional tools during the build phase.
+An environment of MSYS2 (by default, `CLANG64` on 64-bit Windows) will be used
+by Stack to provide a Unix-like shell and environment for Stack. This may be
+necessary for installing some Haskell packages, such as those which use
+`configure` scripts, or if your project needs some additional tools during the
+build phase.
 
 No matter which terminal software you choose (Windows Terminal, Console Windows
 Host, Command Prompt, PowerShell, Git bash or any other) you can use this
@@ -18,30 +18,30 @@ `pacman`. All tools can be found in the [index](https://packages.msys2.org) to
 MSYS2 packages. A [guide](https://www.msys2.org/docs/package-management/) to
 package management with `pacman` is also available. `pacman` &mdash; like all
-other tools in the Stack environment &mdash; should be started with
-`stack exec -- pacman`. Help about `pacman` commands (operations) can be
-obtained by `stack exec -- pacman --help`. Help about a specific `pacman`
+other tools in the [Stack environment](stack_environment.md) &mdash; should be
+started with `stack exec -- pacman`. Help about `pacman` commands (operations)
+can be obtained by `stack exec -- pacman --help`. Help about a specific `pacman`
 operation can be obtained by using `--help` (or `-h`) with an operation. For
 example, help about the operation `--sync` (or `-S`) can be obtained with
 `stack exec -- pacman --sync --help` or, equivalently,
 `stack exec -- pacman -Sh`.
 
-Command `stack path --bin-path` to see the PATH in the Stack environment. If the
-relevant MSYS2 environment is `MINGW64`, on Windows, it includes the
-`\mingw64\bin`, `\usr\bin` and `\usr\local\bin` directories of the
-Stack-supplied MSYS2. (It includes the corresponding directory if the relevant
-MSYS2 environment is other than `MINGW64`.) If your executable depends on files
-(for example, dynamic-link libraries) in those directories and you want to run
-it outside of the Stack environment, you will need to ensure copies of those
-files are on the PATH.
+Command `stack path --bin-path` to see the PATH in the
+[Stack environment](stack_environment.md). If the relevant MSYS2 environment is
+`CLANG64`, on Windows, it includes the `\clang64\bin`, `\usr\local\bin` and
+`\usr\bin` directories of the Stack-supplied MSYS2. (It includes the
+corresponding directory if the relevant MSYS2 environment is other than
+`CLANG64`.) If your executable depends on files (for example, dynamic-link
+libraries) in those directories and you want to run it outside of the Stack
+environment, you will need to ensure copies of those files are on the PATH.
 
 Command `stack path --extra-include-dirs` and `stack path --extra-library-dirs`
 to see the extra directories searched for C header files or system libraries
-files in the Stack environment. If the relevant MSYS2 environment is `MINGW64`,
-on Windows, it includes the `\mingw64\include` (include) and the `\mingw64\lib`
-and `\mingw64\bin` directories (library) of the Stack-supplied MSYS2. (It
+files in the Stack environment. If the relevant MSYS2 environment is `CLANG64`,
+on Windows, it includes the `\clang64\include` (include) and the `\clang64\lib`
+and `\clang64\bin` directories (library) of the Stack-supplied MSYS2. (It
 includes the corresponding directories if the relevant MSYS2 environment is
-other than `MINGW64`.)
+other than `CLANG64`.)
 
 For further information about configuring the relevant MSYS2 environment, see
 Stack's [`msys-environment`](../configure/yaml/non-project.md#msys-environment)
@@ -62,7 +62,7 @@ ## Setup.hs ##
 
 `Setup.hs` is automatically run inside the Stack environment. So when you need
-to launch another tool you do not need to prefix the command with 
+to launch another tool you do not need to prefix the command with
 `stack exec --` within the custom `Setup.hs` file.
 
 ## Pacman packages to install for common Haskell packages ##
@@ -72,7 +72,7 @@ pull request.
 
 *   For [text-icu](https://hackage.haskell.org/package/text-icu) install
-    `mingw64/mingw-w64-x86_64-icu`.
+    `mingw-w64-clang-x86_64-icu`.
 
 *   For [zlib >= 0.7](https://hackage.haskell.org/package/zlib) the default
     Cabal flag `pkg-config` is `true` and requires executable `pkg-config` on
@@ -83,27 +83,3 @@         stack exec -- pacman -S pkgconf
 
     Alternatively, build with `--flag zlib:-pkg-config`.
-
-## CMake ##
-
-CMake has trouble finding other tools even if they are available on the PATH.
-Likely this is not a CMake problem but one of the environment not fully
-integrating. For example GHC comes with a copy of GCC which is not installed by
-MSYS2 itself. If you want to use this GCC you can provide a full path to it, or
-find it first with `System.Directory.findExecutable` if you want to launch GCC
-from a Haskell file such as `Setup.hs`.
-
-Experience tells that the `mingw-w64` versions of Make and CMake are most
-likely to work. Though there are other versions available through `pacman`, so
-have a look to see what works for you. Both tools can be installed with the
-commands:
-
-    stack exec -- pacman -S mingw-w64-x86_64-make
-    stack exec -- pacman -S mingw-w64-x86_64-cmake
-
-Even though Make and CMake are then both installed into the same environment,
-CMake still seems to have trouble to find Make. To help CMake find GCC and Make
-supply the following flags:
-
-    -DCMAKE_C_COMPILER=path
-    -DCMAKE_MAKE_PROGRAM=path
doc/topics/haskell_and_c_code.md view
@@ -83,12 +83,13 @@ 
 The project's `stack.yaml` file only needs to identify a snapshot:
 ~~~yaml
-snapshot: lts-24.24 # GHC 9.10.3
+snapshot: lts-24.43 # GHC 9.10.3
 ~~~
 
 This example project can be built with Stack in the normal way (`stack build`),
-and the built executable can then be executed in the Stack environment in the
-normal way (`stack exec c-example-exe`).
+and the built executable can then be executed in the
+[Stack environment](stack_environment.md) in the normal way
+(`stack exec c-example-exe`).
 
 ## Haskell packages with C `main` function
 
@@ -220,10 +221,11 @@ 
 The project's `stack.yaml` file only needs to identify a snapshot:
 ~~~yaml
-snapshot: lts-24.24 # GHC 9.10.3
+snapshot: lts-24.43 # GHC 9.10.3
 ~~~
 
 This example project can be built with Stack in the normal way (`stack build`),
-and the built executables can then be executed in the Stack environment in the
-normal way (`stack exec haskell-exe` for the 'Haskell' executable and
-`stack exec c-exe` for the 'C' executable).
+and the built executables can then be executed in the
+[Stack environment](stack_environment.md) in the normal way
+(`stack exec haskell-exe` for the 'Haskell' executable and `stack exec c-exe`
+for the 'C' executable).
doc/topics/index.md view
@@ -16,6 +16,11 @@ :   Stack work directories are directories within a local project or package
     directory in which Stack stores files created during the build process.
 
+[Stack environment](stack_environment.md)
+
+:   The Stack environment is the one used by Stack when it builds or it runs an
+    executable.
+
 [Snapshot location](snapshot_location.md)
 
 :   How to specify the location of snapshots.
doc/topics/lock_files.md view
@@ -49,9 +49,7 @@ Some of this information can be incomplete. Consider this `stack.yaml` file:
 
 ~~~yaml
-snapshot: lts-19.22
-packages:
-- .
+snapshot: lts-24.43
 extra-deps:
 - acme-missiles-0.3
 ~~~
@@ -68,15 +66,15 @@     sha256: 614bc0cca76937507ea0a5ccc17a504c997ce458d7f2f9e43b15a10c8eaeb033
 ~~~
 
-The `lts-19.22` information is also incomplete. While we assume in general that
+The `lts-24.43` information is also incomplete. While we assume in general that
 Haskell LTS snapshots never change, there is nothing that prohibits that from
 happening. Instead, the complete version of that key is:
 
 ~~~yaml
-snapshot:
-- url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/22.yaml
-  size: 619399
-  sha256: 5098594e71bdefe0c13e9e6236f12e3414ef91a2b89b029fd30e8fc8087f3a07
+snapshots:
+- url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml
+  size: 729011
+  sha256: 3c412a7c13dba6d3d808455a458e0776c58b6cf99b8a7961a2f5e55589d6f1d6
 ~~~
 
 Users do not particularly feel like writing all of that. Therefore, it is common
@@ -84,9 +82,9 @@ 
 ## Recursive snapshot layers
 
-Snapshot files can be _recursive_, where `stack.yaml` refers to `foo.yaml`,
-which refers to `bar.yaml`, which refers to `baz.yaml`. A local snapshot file
-can refer to a remote snapshot file (available via an HTTP(S) URL).
+Snapshot files can be _recursive_, where `stack.yaml` refers to
+`mySnapshotA.yaml`, which refers to `mySnapshotB.yaml`, which refers to a remote
+snapshot file (available via an HTTP(S) URL).
 
 We need to encode information from _all_ of these snapshot layers and the
 `stack.yaml` file in the lock file, to ensure that we can detect if anything
@@ -116,35 +114,27 @@ It looks like the following:
 
 ~~~yaml
-# Lock file, some message about the file being auto-generated
-snapshots:
-  # Starts with the snapshot specified in stack.yaml,
-  # then continues with the snapshot specified in each
-  # subsequent snapshot file
-  - original:
-      foo.yaml # raw content specified in a snapshot file
-    completed:
-      file: foo.yaml
-      sha256: XXXX
-      size: XXXX
-  - original:
-      lts-13.9
-    completed:
-      size: 496662
-      url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/13/9.yaml
-      sha256: 83de9017d911cf7795f19353dba4d04bd24cd40622b7567ff61fc3f7223aa3ea
+# This file was autogenerated by Stack.
+# You should not edit this file by hand.
+# For more information, please see the documentation at:
+#   https://docs.haskellstack.org/en/stable/topics/lock_files
 
 packages:
-- original: https://hackage.haskell.org/package/acme-missiles-0.3.tar.gz
-  completed:
-    size: 1442
-    url: https://hackage.haskell.org/package/acme-missiles-0.3.tar.gz
-    name: acme-missiles
-    version: '0.3'
-    sha256: e563d8b524017a06b32768c4db8eff1f822f3fb22a90320b7e414402647b735b
+# Listed in the order that they are encountered in the layers of snapshots,
+# starting at the lowest layer:
+- completed:
+    hackage: acme-missiles-0.3@sha256:2ba66a092a32593880a87fb00f3213762d7bca65a687d45965778deb8694c5d1,613
     pantry-tree:
-      size: 226
       sha256: 614bc0cca76937507ea0a5ccc17a504c997ce458d7f2f9e43b15a10c8eaeb033
+      size: 226
+  original:
+    hackage: acme-missiles-0.3
+snapshots:
+- completed:
+    sha256: 3c412a7c13dba6d3d808455a458e0776c58b6cf99b8a7961a2f5e55589d6f1d6
+    size: 729011
+    url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml
+  original: lts-24.43
 ~~~
 
 ## Creation procedure
doc/topics/nix_integration.md view
@@ -35,7 +35,11 @@ `nix-shell`. There are two alternative options to create such a build
 environment:
 
-1. provide a list of [Nix packages][nix-search-packages]
+1. provide a list of [Nix packages][nix-search-packages]. To these, Stack will
+   add Nix packages for the GHC compiler, `git` (the distributed version control
+   system), `gcc` (the GNU compiler collection), `gmp` (the GNU multiple
+   precision arithmetic library) and `cacert` (a bundle of X.509 certificates of 
+   public Certificate Authorities); and
 2. provide a `shell.nix` file that gives you more control over the libraries and
    tools available inside the shell.
 
@@ -89,10 +93,16 @@ [`notify-if-nix-on-path`](../configure/yaml/non-project.md#notify-if-nix-on-path)
 to `false`.
 
-With Nix integration enabled, `stack build` and `stack exec` will automatically
-launch themselves in a local build environment (using `nix-shell` behind the
-scenes). It is not necessary to run `stack setup`, unless you want to cache a
-GHC installation before running a build.
+If Nix integration is enabled:
+
+* `stack build` and `stack exec` automatically launch themselves in a local
+  build environment (using `nix-shell`). It is not necessary to run
+  `stack setup`, unless you want to cache a GHC installation before  running a
+  build; and
+
+* [`system-ghc: true`](../configure/yaml/non-project.md#system-ghc) is implied.
+  ([`install-ghc: false`](../configure/yaml/non-project.md#install-ghc) is not
+  implied.)
 
 **Known limitation on macOS:** currently, `stack --nix ghci` fails on macOS, due
 to a bug in GHCi when working with external shared libraries.
doc/topics/scripts.md view
@@ -19,7 +19,7 @@ 
 ~~~haskell
 #!/usr/bin/env stack
--- stack script --snapshot lts-24.24 --package turtle
+-- stack script --snapshot lts-24.43 --package turtle
 {-# LANGUAGE OverloadedStrings #-}
 import Turtle (echo)
 main = echo "Hello World!"
@@ -78,11 +78,11 @@ 
 The second line of the source code is the Stack interpreter options comment. In
 this example, it specifies the [`stack script`](../commands/script_command.md)
-command with the options of a LTS Haskell 24.24 snapshot
-(`--snapshot lts-24.24`) and ensuring the
+command with the options of a LTS Haskell 24.43 snapshot
+(`--snapshot lts-24.43`) and ensuring the
 [`turtle`](https://hackage.haskell.org/package/turtle) package is available
 (`--package turtle`). The version of the package will be that in the specified
-snapshot (`lts-24.24` provides `turtle-1.6.2`).
+snapshot (`lts-24.43` provides `turtle-1.6.2`).
 
 ## Arguments and interpreter options and arguments
 
@@ -117,7 +117,7 @@ ~~~haskell
 #!/usr/bin/env stack
 {- stack script
-   --snapshot lts-24.24
+   --snapshot lts-24.43
    --
    +RTS -s -RTS
 -}
@@ -133,7 +133,7 @@ is equivalent to the following command at the command line:
 
 ~~~text
-stack script --snapshot lts-24.24 -- MyScript.hs arg1 arg2 +RTS -s -RTS
+stack script --snapshot lts-24.43 -- MyScript.hs arg1 arg2 +RTS -s -RTS
 ~~~
 
 where `+RTS -s -RTS` are some of GHC's
@@ -164,7 +164,7 @@ ~~~haskell
 #!/usr/bin/env stack
 {- stack script
-   --snapshot lts-24.24
+   --snapshot lts-24.43
    --package turtle
    --package "stm async"
    --package http-client,http-conduit
@@ -180,7 +180,7 @@ ~~~haskell
 #!/usr/bin/env stack
 {- stack script
-   --snapshot lts-24.24
+   --snapshot lts-24.43
    --extra-dep acme-missiles-0.3@rev:0
    --extra-dep "{git: git@github.com:yesodweb/wai, commit: '2f8a8e1b771829f4a8a77c0111352ce45a14c30f', subdirs: [auto-update, wai]}"
 -}
@@ -227,7 +227,7 @@ 
 ~~~haskell
 {- stack script
-   --snapshot lts-24.24
+   --snapshot lts-24.43
    --package acme-missiles
 -}
 import Acme.Missiles (launchMissiles)
@@ -238,7 +238,7 @@ 
 The command `stack --script-no-run-compile Script.hs` then behaves as if the
 command
-`stack script --snapshot lts-24.24 --package acme-missiles --no-run --compile -- Script.hs`
+`stack script --snapshot lts-24.43 --package acme-missiles --no-run --compile -- Script.hs`
 had been given. `Script.hs` is compiled (without optimisation) and the resulting
 executable is not run: no missiles are launched in the process!
 
@@ -280,7 +280,7 @@ {- stack
   runghc
   --install-ghc
-  --snapshot lts-24.24
+  --snapshot lts-24.43
   --package base
   --package turtle
   --
@@ -304,7 +304,7 @@ {- stack
    exec ghci
    --install-ghc
-   --snapshot lts-24.24
+   --snapshot lts-24.43
    --package turtle
 -}
 ~~~
doc/topics/snapshot_location.md view
@@ -32,7 +32,7 @@     *   **Stackage LTS Haskell snapshots**, for example:
 
         ~~~yaml
-        snapshot: lts-24.30
+        snapshot: lts-24.43
         ~~~
 
         ??? info "Expansion of `lts-X.Y`"
@@ -52,7 +52,7 @@     *   **Stackage Nightly snapshots**, for example:
 
         ~~~yaml
-        snapshot: nightly-2026-02-09
+        snapshot: nightly-2026-05-29
         ~~~
 
         ??? info "Expansion of `nightly-YYYY-MM-DD`"
@@ -95,7 +95,7 @@ 3.  Via a **URL** pointing to a snapshot configuration file, for example:
 
     ~~~yaml
-    snapshot: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2025/8/17.yaml`
+    snapshot: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2026/5/29.yaml`
     ~~~
 
     For safer, more reproducible builds, you can optionally specify a URL
@@ -103,9 +103,9 @@ 
     ~~~yaml
     snapshot:
-      url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/12/0.yaml
-      size: 499143
-      sha256: 781ea577595dff08b9c8794761ba1321020e3e1ec3297fb833fe951cce1bee11
+      url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml
+      size:  729011
+      sha256: 3c412a7c13dba6d3d808455a458e0776c58b6cf99b8a7961a2f5e55589d6f1d6
     ~~~
 
     `size` is the number of bytes in the file and `sha256` is the file's SHA256
+ doc/topics/stack_environment.md view
@@ -0,0 +1,99 @@+<div class="hidden-warning"><a href="https://docs.haskellstack.org/"><img src="https://rawgit.com/commercialhaskell/stack/master/doc/img/hidden-warning.svg"></a></div>
+
+# Stack environment
+
+Command
+[`stack config env`](../commands/config_command.md#the-stack-config-env-command)
+or [`stack path --bin-path`](../commands/path_command.md) to see how the PATH is
+defined in the Stack environment.
+
+In that environment, Stack adds certain directories to the start of the PATH.
+The directories added are set out below, in order of search priority.
+
+!!! note
+
+    Stack does not automatically include its
+    [local binary directory](../configure/yaml/non-project.md#local-bin-path) on
+    the PATH in the Stack environment. Command
+    [`stack path --local-bin`](../commands/path_command.md) to see that
+    directory.
+
+## The project's `bin` directory
+
+The Stack [work directory](stack_work.md#project-stack-work-directory) for a
+project contains an `install` directory with a path to a directory (the local
+install root directory) containing a `bin` directory, containing built
+executable files. Command
+[`stack path --local-install-root`](../commands/path_command.md) to see the
+local install root directory.
+
+!!! info
+
+    Stack's [`build` command](../commands/build_command.md) installs built
+    executable files of project packages in this directory. Such files can be
+    executed using Stack's [`exec` command](../commands/exec_command.md).
+
+## The snapshot's `bin` directory
+
+The `bin` directory in the root directory for snapshot installation. Command
+[`stack path --snapshot-install-root`](../commands/path_command.md) to see that
+root directory.
+
+## The compiler tools directory
+
+When the directory is required or requested, Stack creates, in the
+[Stack root](stack_root.md#compiler-tools-directory-optional), a compiler tools
+directory for the specified compiler version. Command
+[`stack path --compiler-tools-bin`](../commands/path_command.md) to see that
+directory.
+
+!!! info
+
+    Stack's
+    [`build` command](../commands/build_command.md#-no-copy-compiler-tool-flag)
+    can be configured to install built executable files of project packages into
+    the
+    [compiler tools directory](stack_root.md#compiler-tools-directory-optional)
+    for the specified compiler version.
+
+!!! info
+
+    If you wish to override a tool that is co-located with the specified
+    compiler's executable file, put a copy of the alternative tool (or a link to
+    it) in the
+    [compiler tools directory](stack_root.md#compiler-tools-directory-optional)
+    for the specified compiler version. If that directory does not exist, it can
+    be created with Stack's
+    [`config compiler-tools` command](../commands/config_command.md#the-stack-config-compiler-tools-command).
+
+## The compiler binary's directory
+
+The directory in which the GHC executable file (binary) that will be used by
+Stack is located. Command
+[`stack path --compiler-bin`](../commands/path_command.md) to see that
+directory.
+
+## GHC's MinGW `bin` directory (Windows only)
+
+The GHC-supplied MinGW `bin` directory.
+
+## Stack-supplied MSYS2 environment `bin` directory (Windows only)
+
+The `bin` directory for the specified MSYS2 environment of the
+[Stack-supplied MSYS2](developing_on_windows.md).
+
+## Stack-supplied MSYS2 `usr\local\bin` directory (Windows only)
+
+The `usr\local\bin` directory for the
+[Stack-supplied MSYS2](developing_on_windows.md).
+
+## Stack-supplied MSYS2 `usr\bin` directory (Windows only)
+
+The `usr\bin` directory for the
+[Stack-supplied MSYS2](developing_on_windows.md).
+
+## Specified extra paths
+
+Any extra paths that have been configured using Stack's
+[`extra-paths`](../configure/yaml/non-project.md#extra-path) configuration
+option.
doc/topics/stack_root.md view
@@ -191,6 +191,28 @@ If the work directory is deleted, and Stack needs that work directory, then
 Stack will recreate it.
 
+### `compiler-tools` directory (optional)
+
+When it exists, this contains a directory for the platform. That directory
+contains (if it has been created) a directory for a compiler version
+that, in turn, contains a `bin` directory (the compiler tools directory for that
+compiler version).
+
+If the compiler tools directory for a specified compiler version does not exist,
+and Stack needs that directory, then Stack will create it. The directory can
+also be created using Stack's
+[`config compiler-tools` command](../commands/config_command.md#the-stack-config-compiler-tools-command)
+
+In the [Stack environment](stack_environment.md#the-compiler-tools-directory),
+the compiler tools directory for the specified compiler version is on the PATH.
+
+For further information see:
+
+* The [Stack environment](stack_environment.md#the-compiler-tools-directory);
+* Stack's [`path --compiler-tools-bin` command](../commands/path_command.md); and
+* Stack's
+  [`build --copy-compiler-tool` command](../commands/build_command.md#-no-copy-compiler-tool-flag).
+
 ### `global-project` directory
 
 This contains:
doc/topics/stack_yaml_vs_cabal_package_file.md view
@@ -64,8 +64,8 @@ 
 The most common means by which this set of packages is defined is via a
 snapshot provided by Stackage. For example, if you go to the page
-<https://www.stackage.org/lts-24.24>, you will see a list of 3,415 packages at
-specific version numbers. When you then specify `snapshot: lts-24.24` you are
+<https://www.stackage.org/lts-24.43>, you will see a list of 3,427 packages at
+specific version numbers. When you then specify `snapshot: lts-24.43` you are
 telling Stack to use those package versions in resolving dependencies down to
 specific versions of packages.
 
doc/tutorial/building_your_project.md view
@@ -249,7 +249,7 @@ mentioned the LTS snapshots, and you can get information about it at
 [https://www.stackage.org/lts](https://www.stackage.org/lts), including:
 
-* The appropriate value (`lts-24.24`, as is currently the latest LTS)
+* The appropriate value (`lts-24.43`, as is currently the latest LTS)
 * The GHC version used
 * A full list of all packages versions available in this snapshot
 * The ability to perform a Hoogle search on the packages in this snapshot
doc/tutorial/executing_commands.md view
@@ -34,7 +34,7 @@ Writing the configuration file for the implicit global project to:
 .../global-project/stack.yaml. Note: You can change the snapshot via the
 snapshot key there.
-Using the latest snapshot lts-24.24.
+Using the latest snapshot lts-24.43.
 I installed the stm package via --package stm
 ~~~
 
doc/tutorial/hello_world_example.md view
@@ -59,7 +59,7 @@ `my-project`, with the contents:
 
 ~~~yaml
-snapshot: lts-24.24
+snapshot: lts-24.43
 ~~~
 
 By adding those two files (one to describe a package, the other to configure the
@@ -194,7 +194,8 @@ 
     No. GHC will be installed to the Stack programs directory, which is likely
     not on the PATH, so commanding `ghc` will not work. However, that version of
-    GHC can be used in the Stack environment. For more information, see the
+    GHC can be used in the [Stack environment](../topics/stack_environment.md).
+    For more information, see the
     [`stack exec`](../commands/exec_command.md) command,
     [`stack ghc`](../commands/ghc_command.md) command, and
     [`stack runghc`](../commands/ghc_command.md) command documentation.
@@ -317,15 +318,17 @@ 
 ??? question "How I can find the PATH used in the Stack environment?"
 
-    Command `stack path --bin-path` to see the PATH in the Stack environment.
+    Command `stack path --bin-path` to see the PATH in the
+    [Stack environment](../topics/stack_environment.md).
 
 !!! info
 
-    On Windows, the Stack environment includes the `\mingw64\bin`, `\usr\bin`
-    and `\usr\local\bin` directories of the Stack-supplied MSYS2. If your
-    executable depends on files (for example, dynamic-link libraries) in those
-    directories and you want ro run it outside of the Stack environment, you
-    will need to ensure copies of those files are on the PATH.
+    On Windows, the [Stack environment](../topics/stack_environment.md) includes
+    the `\clang64\bin`, `\usr\bin` and `\usr\local\bin` directories of the
+    Stack-supplied MSYS2. If your executable depends on files (for example,
+    dynamic-link libraries) in those directories and you want ro run it outside
+    of the Stack environment, you will need to ensure copies of those files are
+    on the PATH.
 
 ## The `stack test` command
 
doc/tutorial/multi-package_projects.md view
@@ -37,10 +37,10 @@ 
 Selecting the best among 14 snapshots...
 
-Note: Matches https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/25.yaml
+Note: Matches https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml
 
-Selected the snapshot https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/25.yaml.
-Initialising Stack's project-level configuration file using snapshot https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/25.yaml.
+Selected the snapshot https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml.
+Initialising Stack's project-level configuration file using snapshot https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml.
 Considered 2 user packages.
 Writing configuration to stack.yaml.
 Stack's project-level configuration file has been initialised.
@@ -51,7 +51,7 @@ 
 ~~~yaml
 snapshot:
-  url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/25.yaml
+  url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml
 
 packages:
 - packageA
doc/tutorial/project_configuration.md view
@@ -35,7 +35,7 @@ 
 ~~~yaml
 snapshot:
-  url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/9.yaml
+  url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/43.yaml
 packages:
 - .
 ~~~
@@ -44,7 +44,7 @@ project-specific configuration option. Its value tells Stack *how* to build your
 package: which version of GHC (and, implicitly, its boot packages) to use; which
 versions of other package dependencies to use, and so on. Our value here says to
-use [LTS Haskell 24.24](https://www.stackage.org/lts-24.24), which implies
+use [LTS Haskell 24.43](https://www.stackage.org/lts-24.43), which implies
 GHC 9.10.3 (which is why `stack build` installs that version of GHC if it is not
 already available to Stack). There are a number of values you can use for
 `snapshot`, which we will cover later.
src/Network/HTTP/StackClient.hs view
@@ -80,16 +80,16 @@ import           Data.Time.Clock
                    ( NominalDiffTime, diffUTCTime, getCurrentTime )
 import           Network.HTTP.Client
-                   ( HttpException (..), HttpExceptionContent (..), Request
-                   , RequestBody (..), Response (..), checkResponse, getUri
-                   , method, parseRequest, parseUrlThrow, path, requestBody
+                   ( HttpException (..), HttpExceptionContent (..), Manager
+                   , Request, RequestBody (..), Response (..), checkResponse
+                   , getUri, method, parseRequest, parseUrlThrow, path
+                   , requestBody
                    )
 import           Network.HTTP.Client.MultipartFormData
                    ( formDataBody, partBS, partFileRequestBody, partLBS )
 import           Network.HTTP.Client.TLS
-                   ( applyDigestAuth, displayDigestAuthException
-                   , getGlobalManager
-                   )
+                   ( displayDigestAuthException, getGlobalManager )
+import qualified Network.HTTP.Client.TLS ( applyDigestAuth )
 import           Network.HTTP.Conduit ( requestHeaders )
 import           Network.HTTP.Download
                    ( CheckHexDigest (..), DownloadRequest, HashCheck (..)
@@ -306,3 +306,15 @@         then put (currentTime, mempty) >> yield acc'
         else put (lastTime,    acc')
       go
+
+-- | Like 'Network.HTTP.Client.TLS.applyDigestAuth' but sets the User-Agent
+-- request header.
+applyDigestAuth ::
+     (MonadIO m, MonadThrow n)
+  => Strict.ByteString
+  -> Strict.ByteString
+  -> Request
+  -> Manager
+  -> m (n Request)
+applyDigestAuth user pass =
+  Network.HTTP.Client.TLS.applyDigestAuth user pass . setUserAgent
src/Stack/Build.hs view
@@ -41,6 +41,7 @@ import           Stack.Prelude hiding ( loadPackage )
 import           Stack.Runners ( ShouldReexec (..), withConfig, withEnvConfig )
 import           Stack.Setup ( withNewLocalBuildTargets )
+import           Stack.Types.Build.ConstructPlan ( PackageLoader )
 import           Stack.Types.Build.Exception
                    ( BuildException (..), BuildPrettyException (..) )
 import           Stack.Types.BuildConfig ( HasBuildConfig, configFileL )
@@ -408,13 +409,7 @@     }
 
 -- | Provide a function for loading package information from the package index
-loadPackage ::
-     (HasBuildConfig env, HasSourceMap env)
-  => PackageLocationImmutable
-  -> Map FlagName Bool
-  -> [Text] -- ^ GHC options
-  -> [Text] -- ^ Cabal configure options
-  -> RIO env Package
+loadPackage :: (HasBuildConfig env, HasSourceMap env) => PackageLoader (RIO env)
 loadPackage loc flags ghcOptions cabalConfigOpts = do
   compilerVersion <- view actualCompilerVersionL
   platform <- view platformL
src/Stack/Build/ConstructPlan.hs view
@@ -46,10 +46,10 @@ import           Stack.Prelude hiding ( loadPackage )
 import           Stack.SourceMap ( getPLIVersion, mkProjectPackage )
 import           Stack.Types.Build.ConstructPlan
-                   ( AddDepRes (..), CombinedMap, Ctx (..), M
-                   , MissingPresentDeps (..), PackageInfo (..), ToolWarning(..)
-                   , UnregisterState (..), W (..), adrHasLibrary, adrVersion
-                   , isAdrToInstall, toTask
+                   ( AddDepRes (..), CombinedMap, Ctx (..), LibraryMap, M
+                   , MissingPresentDeps (..), PackageInfo (..), PackageLoader
+                   , ToolWarning(..), UnregisterState (..), W (..)
+                   , adrHasLibrary, adrVersion, isAdrToInstall, toTask
                    )
 import           Stack.Types.Build.Exception
                    ( BadDependency (..), BuildException (..)
@@ -121,16 +121,11 @@ constructPlan ::
      forall env. HasEnvConfig env
   => BaseConfigOpts
-  -> [DumpPackage] -- ^ locally registered
-  -> (  PackageLocationImmutable
-     -> Map FlagName Bool
-     -> [Text]
-        -- ^ GHC options
-     -> [Text]
-        -- ^ Cabal configure options
-     -> RIO EnvConfig Package
-     )
-     -- ^ load upstream package
+  -> [DumpPackage]
+     -- ^ Locally registered.
+  -> PackageLoader (RIO EnvConfig)
+     -- ^ Function to load a 'Package' given the location of a package assumed
+     -- to be immutable.
   -> SourceMap
   -> InstalledMap
   -> Bool
@@ -195,14 +190,22 @@     let ctx = mkCtx econfig globalCabalVersion sources curator pathEnvVar
         targetPackageNames = Map.keys sourceMap.targets.targets
         -- Ignore the result of 'getCachedDepOrAddDep'.
-        onTarget = void . getCachedDepOrAddDep
+        onTarget pkgName = do
+          logDebugPlanS "constructPlan" $
+               "Constructing for target "
+            <> fromPackageName pkgName
+          void $ getCachedDepOrAddDep pkgName
+        inner :: M ()
         inner = mapM_ onTarget targetPackageNames
-    (((), W efinals installExes dirtyReason warnings parents), m) <-
-      liftIO $ runRIO ctx (runStateT (runWriterT inner) Map.empty)
+        action :: RIO Ctx (((), W), LibraryMap)
+        action = runStateT (runWriterT inner) Map.empty
+    (((), output), libraryMap) <- liftIO $ runRIO ctx action
+    let W efinals installExes dirtyReason warnings parents = output
     -- Report any warnings
     mapM_ prettyWarn (warnings [])
     -- Separate out errors
-    let (errlibs, adrs) = partitionEithers $ map toEither $ Map.toList m
+    let (errlibs, adrs) =
+          partitionEithers $ map toEither $ Map.toList libraryMap
         (errfinals, finals) =
           partitionEithers $ map toEither $ Map.toList efinals
         errs = errlibs ++ errfinals
@@ -239,18 +242,30 @@ 
   hasBaseInDeps = Map.member (mkPackageName "base") sourceDeps
 
-  mkCtx ctxEnvConfig globalCabalVersion sources curator pathEnvVar = Ctx
-    { baseConfigOpts = baseConfigOpts0
-    , loadPackage = \w x y z -> runRIO ctxEnvConfig $
-        applyForceCustomBuild globalCabalVersion <$> loadPackage0 w x y z
-    , combinedMap = combineMap sources installedMap
-    , ctxEnvConfig
-    , callStack = []
-    , wanted = Map.keysSet sourceMap.targets.targets
-    , localNames = Map.keysSet sourceProject
-    , curator
-    , pathEnvVar
-    }
+  mkCtx ::
+       EnvConfig
+    -> Version
+    -> Map PackageName PackageSource
+    -> Maybe Curator
+    -> Text
+    -> Ctx
+  mkCtx ctxEnvConfig globalCabalVersion sources curator pathEnvVar =
+    let loadPackage loc flags ghcOptions cabalConfigOpts = do
+          let action = do
+                package <- loadPackage0 loc flags ghcOptions cabalConfigOpts
+                pure $ applyForceCustomBuild globalCabalVersion package
+          runRIO ctxEnvConfig action
+    in  Ctx
+          { baseConfigOpts = baseConfigOpts0
+          , loadPackage
+          , combinedMap = combineMap sources installedMap
+          , ctxEnvConfig
+          , callStack = []
+          , wanted = Map.keysSet sourceMap.targets.targets
+          , localNames = Map.keysSet sourceProject
+          , curator
+          , pathEnvVar
+          }
 
   toEither :: (k, Either e v) -> Either e (k, v)
   toEither (_, Left e)  = Left e
@@ -467,7 +482,10 @@      -- ^ Should Haddock documentation be built?
   -> M ()
 addFinal lp package allInOne buildHaddocks = do
-  res <- addPackageDeps package >>= \case
+  let name = package.name
+  logDebugPlanS "addFinal" "Clearing the call stack."
+  res <- local (\ctx' -> ctx' { callStack = [] }) $
+           addPackageDeps package >>= \case
     Left e -> pure $ Left e
     Right (MissingPresentDeps missing present _minLoc) -> do
       let pkgConfigOpts = packageConfigureOptsFromPackage package
@@ -489,24 +507,30 @@         , cachePkgSrc = CacheSrcLocal (toFilePath (parent lp.cabalFP))
         , buildTypeConfig = packageBuildTypeConfig package
         }
-  tell mempty { wFinals = Map.singleton package.name res }
+  ctx <- ask
+  logDebugPlanS "addFinal" $
+       "Restoring the call stack: "
+    <> fromString (show $ map packageNameString ctx.callStack)
+  logDebugPlanS "addFinal" $
+       "Adding to construction output "
+    <> fromPackageName name
+    <> summariseResult res
+  tell mempty { wFinals = Map.singleton name res }
 
 -- | Given a 'PackageName', adds all of the build tasks to build the package, if
 -- needed. First checks if the package name is in the library map.
 --
--- 'constructPlan' invokes this on all the target packages, setting
--- @treatAsDep'@ to False, because those packages are direct build targets.
+-- 'constructPlan' invokes this on all the target packages.
+--
 -- 'addPackageDeps' invokes this while recursing into the dependencies of a
--- package. As such, it sets @treatAsDep'@ to True, forcing this package to be
--- marked as a dependency, even if it is directly wanted. This makes sense - if
--- we left out packages that are deps, it would break the --only-dependencies
--- build plan.
+-- package, even if it is directly wanted. This makes sense - if we left out
+-- packages that are deps, it would break the --only-dependencies build plan.
 getCachedDepOrAddDep ::
      PackageName
   -> M (Either ConstructPlanException AddDepRes)
 getCachedDepOrAddDep name = do
-  libMap <- get
-  case Map.lookup name libMap of
+  libraryMap <- get
+  case Map.lookup name libraryMap of
     Just res -> do
       logDebugPlanS "getCachedDepOrAddDep" $
            "Using cached result for "
@@ -542,10 +566,19 @@           <> fromPackageName name
           <> "."
         pure $ Left $ UnknownPackage compiler name
-      Just packageInfo ->
+      Just packageInfo -> do
+        logDebugPlanS "checkCallStackAndAddDep" $
+             "Pushing "
+          <> fromPackageName name
+          <> " on to the call stack."
         -- Add the current package name to the head of the call stack.
-        local (\ctx' -> ctx' { callStack = name : ctx'.callStack }) $
+        res <- local (\ctx' -> ctx' { callStack = name : ctx'.callStack }) $
           addDep name packageInfo
+        logDebugPlanS "checkCallStackAndAddDep" $
+             "Popped "
+          <> fromPackageName name
+          <> " from the call stack."
+        pure res
   updateLibMap name res
   pure res
 
@@ -679,15 +712,16 @@           resolveDepsAndInstall
             True lp.buildHaddocks ps lp.package minstalled
         Just tb -> do
+          -- Preserve the current library map.
+          libMap <- get
           -- Attempt to find a plan which performs an all-in-one build. Ignore
           -- the writer action + reset the state if it fails.
-          libMap <- get
           res <- pass $ do
             res <- addPackageDeps tb
-            let writerFunc w = case res of
-                  Left _ -> mempty
-                  _ -> w
-            pure (res, writerFunc)
+            let modifyOutput = case res of
+                  Left _ -> const mempty
+                  _ -> id
+            pure (res, modifyOutput)
           case res of
             Right deps -> do
               logDebugPlanS "installPackage" $
@@ -759,8 +793,14 @@   -> Maybe Installed
   -> MissingPresentDeps
   -> M AddDepRes
-installPackageGivenDeps allInOne buildHaddocks ps package minstalled
-  (MissingPresentDeps missing present minMutable) = do
+installPackageGivenDeps
+    allInOne
+    buildHaddocks
+    ps
+    package
+    minstalled
+    (MissingPresentDeps missing present minMutable)
+  = do
     let name = package.name
     mRightVersionInstalled <- case minstalled of
       Just installed -> if Set.null missing
@@ -813,10 +853,15 @@ -- Update response in the library map. If it is an error, and there's already an
 -- error about cyclic dependencies, prefer the cyclic error.
 updateLibMap :: PackageName -> Either ConstructPlanException AddDepRes -> M ()
-updateLibMap name val = modify $ \mp ->
-  case (Map.lookup name mp, val) of
-    (Just (Left DependencyCycleDetected{}), Left _) -> mp
-    _ -> Map.insert name val mp
+updateLibMap name res = do
+  logDebugPlanS "updateLibMap" $
+       "Updating for: "
+    <> fromPackageName name
+    <> summariseResult res
+  modify $ \mp ->
+    case (Map.lookup name mp, res) of
+      (Just (Left DependencyCycleDetected{}), Left _) -> mp
+      _ -> Map.insert name res mp
 
 addEllipsis :: Text -> Text
 addEllipsis t
@@ -1263,6 +1308,12 @@ logDebugPlanS s msg = do
   debugPlan <- view $ globalOptsL . to (.planInLog)
   when debugPlan $ logDebugS s msg
+
+-- | A function to summarise a result. Assumes that 'Left' is an error and
+-- 'Right' is not. Intended to be used to annotate, so includes an initial space
+-- character.
+summariseResult :: Either a b -> Utf8Builder
+summariseResult res = " (" <> either (const "error") (const "ok") res <> ")"
 
 -- | A function to yield a 'PackageInfo' value from: (1) a 'PackageSource'
 -- value; and (2) a pair of an 'InstallLocation' value and an 'Installed' value.
src/Stack/Build/ExecuteEnv.hs view
@@ -54,6 +54,7 @@ import           Distribution.System ( OS (..), Platform (..) )
 import           Distribution.Types.PackageName ( mkPackageName )
 import           Distribution.Verbosity ( showForCabal )
+import           Distribution.Version ( mkVersion )
 import           Path
                    ( PathException, (</>), parent, parseRelDir, parseRelFile )
 import           Path.Extra ( forgivingResolveFile, toFilePathNoTrailingSep )
@@ -86,7 +87,9 @@ import           Stack.Types.BuildOptsCLI ( BuildOptsCLI (..) )
 import           Stack.Types.BuildOptsMonoid ( CabalVerbosity (..) )
 import           Stack.Types.Compiler
-                   ( WhichCompiler (..), compilerVersionString, whichCompilerL )
+                   ( WhichCompiler (..), compilerVersionString
+                   , getGhcVersion, whichCompilerL
+                   )
 import           Stack.Types.CompilerPaths
                    ( CompilerPaths (..), HasCompiler (..), cabalVersionL
                    , getCompilerPath
@@ -115,6 +118,8 @@ import           System.Environment ( lookupEnv )
 import           System.FileLock
                    ( SharedExclusive (..), withFileLock, withTryFileLock )
+import           System.Semaphore
+                   ( Semaphore, destroySemaphore, freshSemaphore )
 
 -- | Type representing environments in which the @Setup.hs@ commands of Cabal
 -- (the library) can be executed.
@@ -147,6 +152,8 @@     -- ^ For nicer interleaved output: track the largest package name size
   , pathEnvVar :: !Text
     -- ^ Value of the PATH environment variable
+  , semaphore :: !(Maybe Semaphore)
+    -- ^ The semaphore that is used for job control, if --semaphore is given
   }
 
 -- | Type representing setup executable circumstances.
@@ -256,6 +263,9 @@       renameFile tmpExePath exePath
       pure $ Just exePath
 
+semaphorePrefix :: String
+semaphorePrefix = "stack"
+
 -- | Execute a function that takes an t'ExecuteEnv'.
 withExecuteEnv ::
      forall env a. HasEnvConfig env
@@ -320,6 +330,8 @@       ignoringAbsence (removeFile setupO)
       ignoringAbsence (removeFile setupShimHi)
       ignoringAbsence (removeFile setupShimO)
+      compilerVersion <- view actualCompilerVersionL
+      let ghcVersion = getGhcVersion compilerVersion
       cabalPkgVer <- view cabalVersionL
       globalDB <- view $ compilerPathsL . to (.globalDB)
       let globalDumpPkgs = toDumpPackagesByGhcPkgId globalPackages
@@ -330,6 +342,27 @@       logFiles <- liftIO $ atomically newTChan
       let totalWanted = length $ filter (.wanted) locals
       pathEnvVar <- liftIO $ maybe mempty T.pack <$> lookupEnv "PATH"
+      jobs <- view $ configL . to (.jobs)
+      let semaphoreSupported =
+               (cabalPkgVer >= mkVersion [3, 12, 0, 0])
+            && (ghcVersion >= mkVersion [9, 8, 1])
+          semaphoreUnsupportedWarning =
+            prettyWarnL
+              [ "The"
+              , style Shell "--semaphore"
+              , flow "flag was specified, which is supported by GHC 9.8.1 or \
+                     \later with Cabal 3.12.0.0 (a boot package of GHC 9.10.1) \
+                     \or later. GHC version"
+              , fromString (versionString ghcVersion)
+              , flow "and Cabal version"
+              , fromString (versionString cabalPkgVer)
+              , flow "was found. The flag will be ignored."
+              ]
+      semaphore <- if not buildOpts.semaphore
+        then pure Nothing
+        else if semaphoreSupported
+          then Just <$> liftIO (freshSemaphore semaphorePrefix jobs)
+          else semaphoreUnsupportedWarning >> pure Nothing
       inner ExecuteEnv
         { buildOpts
         , buildOptsCLI
@@ -355,7 +388,10 @@         , customBuilt
         , largestPackageName
         , pathEnvVar
-        } `finally` dumpLogs logFiles totalWanted
+        , semaphore
+        } `finally` do
+          liftIO (whenJust semaphore destroySemaphore)
+          dumpLogs logFiles totalWanted
  where
   toDumpPackagesByGhcPkgId = Map.fromList . map (\dp -> (dp.ghcPkgId, dp))
 
@@ -688,7 +724,7 @@           , keepGhcRts = False
           }
     menv <- liftIO $ config.processContextSettings envSettings
-    distRelativeDir' <- distRelativeDir
+    distDir' <- distDirFromDir pkgDir
     setupexehs <-
       -- Avoid broken Setup.hs files causing problems for simple build
       -- types, see:
@@ -837,7 +873,7 @@                   <> cabalPackageArg
 
           setupArgs =
-            ("--builddir=" ++ toFilePathNoTrailingSep distRelativeDir') : args
+            ("--builddir=" ++ toFilePathNoTrailingSep distDir') : args
 
           runExe :: Path Abs File -> [String] -> RIO env ()
           runExe exeName fullArgs = do
src/Stack/Build/ExecutePackage.hs view
@@ -68,6 +68,8 @@                    ( ExcludeTHLoading (..), ExecuteEnv (..), KeepOutputOpen (..)
                    , OutputType (..), withSingleContext
                    )
+import           Stack.Build.TestSuiteTimeout
+                   ( forceKill, prepareForEscalation, terminateGracefully )
 import           Stack.Build.Source ( addUnlistedToBuildCache )
 import           Stack.Config.ConfigureScript ( ensureConfigureScript )
 import           Stack.ConfigureOpts
@@ -151,6 +153,7 @@ import           System.PosixCompat.Files
                    ( createLink, getFileStatus, modificationTime )
 import           System.Random ( randomIO )
+import           System.Semaphore ( Semaphore (..), SemaphoreName (..) )
 
 -- | Generate the t'ConfigCache' value.
 getConfigCache ::
@@ -569,7 +572,7 @@       <> display actualCompiler
       )
     config <- view configL
-    extraOpts <- extraBuildOptions wc ee.buildOpts
+    extraOpts <- extraBuildOptions wc ee.buildOpts ee.semaphore
     let stripTHLoading
           | config.hideTHLoading = ExcludeTHLoading
           | otherwise                  = KeepTHLoading
@@ -641,9 +644,9 @@       announce "copy/register"
       try (cabal KeepTHLoading $ "copy" : copyOpts) >>= \case
         Left err@CabalExitedUnsuccessfully{} ->
-          throwM $ CabalCopyFailed
-                     (package.buildType == C.Simple)
-                     (displayException err)
+          prettyThrowM $ CabalCopyFailed
+            (package.buildType == C.Simple)
+            err
         _ -> pure ()
       when (hasLibrary || hasSubLibraries) $ cabal KeepTHLoading ["register"]
 
@@ -1155,13 +1158,47 @@                         )
                         createSource
                       OTLogFile _ h -> Nothing <$ useHandleOpen h
-                    optionalTimeout action
+                    runOutput p =
+                      case (getStdout p, getStderr p) of
+                        (Nothing, Nothing) -> pure ()
+                        (Just x, Just y) -> concurrently_ x y
+                        (x, y) -> assert False $
+                          concurrently_
+                            (fromMaybe (pure ()) x)
+                            (fromMaybe (pure ()) y)
+                    timeoutWithGrace p maxSecs graceSecs = do
+                      mExit <- timeout (maxSecs * 1000000) (waitExitCode p)
+                      case mExit of
+                        Just ec -> pure (Just ec)
+                        Nothing -> do
+                          terminateGracefully p
+                          mGraceExit <- timeout (graceSecs * 1000000)
+                            (waitExitCode p)
+                          case mGraceExit of
+                            Just _ -> pure Nothing
+                            Nothing -> do
+                              forceKill p
+                              void $ waitExitCode p
+                              pure Nothing
+                    runWithTimeout pc
+                      | Just maxSecs <- topts.maximumTimeSeconds, maxSecs > 0
+                      , Just graceSecs <- topts.timeoutGraceSeconds
+                      , graceSecs > 0 =
+                          withProcessWait (prepareForEscalation pc) $ \p -> do
+                            (_, mec') <- concurrently
+                              (runOutput p)
+                              (timeoutWithGrace p maxSecs graceSecs)
+                            pure mec'
                       | Just maxSecs <- topts.maximumTimeSeconds, maxSecs > 0 =
-                          timeout (maxSecs * 1000000) action
-                      | otherwise = Just <$> action
+                          timeout (maxSecs * 1000000) $
+                            withProcessWait pc $ \p -> do
+                              runOutput p
+                              waitExitCode p
+                      | otherwise =
+                          Just <$> withProcessWait pc (\p -> runOutput p *> waitExitCode p)
 
                 mec <- withWorkingDir (toFilePath pkgDir) $
-                  optionalTimeout $ proc (toFilePath exePath) args $ \pc0 -> do
+                  proc (toFilePath exePath) args $ \pc0 -> do
                     changeStdin <-
                       if isTestTypeLib
                         then do
@@ -1184,15 +1221,7 @@                            $ setStdout output
                            $ setStderr output
                              pc0
-                    withProcessWait pc $ \p -> do
-                      case (getStdout p, getStderr p) of
-                        (Nothing, Nothing) -> pure ()
-                        (Just x, Just y) -> concurrently_ x y
-                        (x, y) -> assert False $
-                          concurrently_
-                            (fromMaybe (pure ()) x)
-                            (fromMaybe (pure ()) y)
-                      waitExitCode p
+                    runWithTimeout pc
                 -- Add a trailing newline, incase the test
                 -- output didn't finish with a newline.
                 case outputType of
@@ -1225,12 +1254,12 @@                     else pure $ Map.singleton testName (Just ec)
               else do
                 unless expectFailure $
-                  logError $
-                    displayShow $ TestSuiteExeMissing
+                  prettyError $
+                    pretty $ TestSuiteExeMissing
                       (package.buildType == C.Simple)
                       exeName
-                      (packageNameString package.name)
-                      (unqualCompToString testName)
+                      package.name
+                      testName
                 pure emptyResult
 
         when needHpc $ do
@@ -1294,17 +1323,22 @@      (HasEnvConfig env, HasRunner env)
   => WhichCompiler
   -> BuildOpts
+  -> Maybe Semaphore
   -> RIO env [String]
-extraBuildOptions wc bopts = do
+extraBuildOptions wc bopts semaphore = do
   colorOpt <- appropriateGhcColorFlag
   let optsFlag = compilerOptionsCabalFlag wc
+      semaphoreFlag = maybe
+        []
+        (("--semaphore":) . L.singleton . getSemaphoreName . semaphoreName)
+        semaphore
       baseOpts = maybe "" (" " ++) colorOpt
   if bopts.testOpts.coverage
     then do
       hpcIndexDir <- toFilePathNoTrailingSep <$> hpcRelativeDir
-      pure [optsFlag, "-hpcdir " ++ hpcIndexDir ++ baseOpts]
+      pure $ semaphoreFlag ++ [optsFlag, "-hpcdir " ++ hpcIndexDir ++ baseOpts]
     else
-      pure [optsFlag, baseOpts]
+      pure $ semaphoreFlag ++ [optsFlag, baseOpts]
 
 -- Library, sub-library, foreign library and executable build components.
 primaryComponentOptions :: LocalPackage -> [String]
src/Stack/BuildOpts.hs view
@@ -62,6 +62,7 @@   , interleavedOutput = defaultFirstTrue buildMonoid.interleavedOutput
   , progressBar = CappedBar
   , ddumpDir = Nothing
+  , semaphore = defaultFirstFalse buildMonoid.semaphore
   }
  where
   buildMonoid = undefined :: BuildOptsMonoid
@@ -73,6 +74,7 @@   , coverage = defaultFirstFalse toMonoid.coverage
   , runTests = defaultFirstTrue toMonoid.runTests
   , maximumTimeSeconds = Nothing
+  , timeoutGraceSeconds = Nothing
   , allowStdin = defaultFirstTrue toMonoid.allowStdin
   }
  where
src/Stack/CLI.hs view
@@ -33,8 +33,9 @@ import           Stack.BuildInfo ( hpackVersion, versionString' )
 import           Stack.Clean ( CleanCommand (..), cleanCmd )
 import           Stack.ConfigCmd
-                   ( cfgCmdBuildFiles, cfgCmdBuildFilesName, cfgCmdEnv
-                   , cfgCmdEnvName, cfgCmdName, cfgCmdSet, cfgCmdSetName
+                   ( cfgCmdBuildFiles, cfgCmdBuildFilesName, cfgCmdCompilerTools
+                   , cfgCmdCompilerToolsName, cfgCmdEnv, cfgCmdEnvName
+                   , cfgCmdName, cfgCmdSet, cfgCmdSetName
                    )
 import           Stack.Constants
                    ( globalFooter, osIsWindows, relFileStack, relFileStackDotExe
@@ -256,6 +257,12 @@               -- It is withBuildConfig that yields the desired actions;
               -- cfgCmdBuildFiles itself yields nothing of interest.
               (withConfig YesReexec . withBuildConfig . cfgCmdBuildFiles)
+              (pure ())
+            addCommand'
+              cfgCmdCompilerToolsName
+              "Create (when applicable) the compiler tools directory for the \
+              \specified compiler version (implies 'config build-files')."
+              (withConfig YesReexec . withDefaultEnvConfig . cfgCmdCompilerTools)
               (pure ())
         )
 
src/Stack/Config.hs view
@@ -33,6 +33,7 @@   , defaultConfigYaml
   , getProjectConfig
   , withBuildConfig
+  , withConfigExtra
   , withNewLogFunc
   , determineStackRootAndOwnership
   ) where
@@ -55,6 +56,7 @@ import qualified Data.Set as Set
 import qualified Data.Text as T
 import qualified Data.Yaml as Yaml
+import qualified Data.Yaml.Include as YamlInclude
 import qualified Distribution.PackageDescription as PD
 import           Distribution.System
                    ( Arch (..), OS (..), Platform (..), buildPlatform )
@@ -125,6 +127,7 @@                    ( ConfigException (..), ConfigPrettyException (..)
                    , ParseAbsolutePathException (..)
                    )
+import           Stack.Types.ConfigExtra ( ConfigExtra (..) )
 import           Stack.Types.ConfigMonoid
                    ( ConfigMonoid (..), parseConfigMonoid )
 import           Stack.Types.Casa ( CasaOptsMonoid (..) )
@@ -282,6 +285,9 @@         latestSnapshot = fromFirst
           "https://stackage-haddock.haskell.org/snapshots.json"
           configMonoid.latestSnapshot
+        recentSnapshots = fromFirst
+          "https://www.stackage.org/api/v1/snapshots"
+          configMonoid.recentSnapshots
         clConnectionCount = fromFirst 8 configMonoid.connectionCount
         hideTHLoading = fromFirstTrue configMonoid.hideTHLoading
         prefixTimestamps = fromFirst False configMonoid.prefixTimestamps
@@ -300,10 +306,6 @@         installMsys = fromFirst installGHC configMonoid.installMsys
         skipGHCCheck = fromFirstFalse configMonoid.skipGHCCheck
         skipMsys = fromFirstFalse configMonoid.skipMsys
-        defMsysEnvironment = case platform of
-          Platform I386 Windows -> Just MINGW32
-          Platform X86_64 Windows -> Just MINGW64
-          _ -> Nothing
         extraIncludeDirs = configMonoid.extraIncludeDirs
         extraLibDirs = configMonoid.extraLibDirs
         customPreprocessorExts = configMonoid.customPreprocessorExts
@@ -318,15 +320,19 @@         requireStackVersion = simplifyVersionRange
           configMonoid.requireStackVersion.intersectingVersionRange
         compilerCheck = fromFirst MatchMinor configMonoid.compilerCheck
-    msysEnvironment <- case defMsysEnvironment of
-      -- Ignore the configuration setting if there is no default for the
-      -- platform.
+        mMsysEnv = case platform of
+          Platform X86_64 Windows ->
+            -- Default CLANG64 on 64-bit Windows:
+            Just $ fromFirst CLANG64 configMonoid.msysEnvironment
+          Platform _ Windows ->
+            -- No default on unsupported 32-bit Windows:
+            getFirst configMonoid.msysEnvironment
+          _ -> Nothing
+    msysEnvironment <- case mMsysEnv of
       Nothing -> pure Nothing
-      Just defMsysEnv -> do
-        let msysEnv = fromFirst defMsysEnv configMonoid.msysEnvironment
-        if msysEnvArch msysEnv == arch
-          then pure $ Just msysEnv
-          else prettyThrowM $ BadMsysEnvironment msysEnv arch
+      Just msysEnv
+        | msysEnvArch msysEnv == arch -> pure $ Just msysEnv
+        | otherwise -> prettyThrowM $ BadMsysEnvironment msysEnv arch
     platformVariant <- liftIO $
       maybe PlatformVariantNone PlatformVariant <$> lookupEnv platformVariantEnvVar
     let build = buildOptsFromMonoid configMonoid.buildOpts
@@ -596,6 +602,7 @@                 , ghcVariant
                 , ghcBuild
                 , latestSnapshot
+                , recentSnapshots
                 , systemGHC
                 , installGHC
                 , installMsys
@@ -781,32 +788,77 @@ -- by @loadConfig@. values.
 withBuildConfig :: RIO BuildConfig a -> RIO Config a
 withBuildConfig inner = do
-  config <- ask
+  withConfigExtra True $ \configExtra -> do
+    -- The mcompiler is provided on the command line.
+    mcompiler <- view $ globalOptsL . to (.compiler)
+    let config = configExtra.config
+        project' = configExtra.project
+        configFile = configExtra.configFile
+        project :: Project
+        project = project'
+          { Project.compiler = mcompiler <|> project'.compiler
+          , Project.snapshot = fromMaybe project'.snapshot configExtra.mSnapshot
+          }
+        -- We are indifferent as to whether the configuration file is a
+        -- user-specific global or a project-level one.
+        eitherConfigFile = EE.fromEither configFile
+    extraPackageDBs <- mapM resolveDir' project.extraPackageDBs
 
+    smWanted <- lockCachedWanted eitherConfigFile project.snapshot $
+      fillProjectWanted eitherConfigFile config project
+
+    -- Unfortunately redoes getWorkDir, since we don't have a BuildConfig yet
+    workDir <- view workDirL
+    let projectStorageFile =
+          parent eitherConfigFile </> workDir </> relFileStorage
+
+    initProjectStorage projectStorageFile $ \projectStorage -> do
+      let bc = BuildConfig
+            { config
+            , smWanted
+            , extraPackageDBs
+            , configFile
+            , curator = project.curator
+            , projectStorage
+            }
+      runRIO bc inner
+
+-- | Adds certain build-specific values to the configuration loaded by
+-- @loadConfig@ values.
+withConfigExtra ::
+     forall a env. (HasConfig env, HasTerm env)
+  => Bool
+     -- ^ Report user message in the project-level configuration file, if
+     -- a user message is present?
+  -> (ConfigExtra -> RIO env a)
+  -> RIO env a
+withConfigExtra reportUserMessage inner = do
+  config <- view configL
   -- If provided, turn the AbstractSnapshot from the command line into a
-  -- snapshot that can be used below.
+  -- snapshot that can be used.
 
-  -- The snapshot and mcompiler are provided on the command line. In order
-  -- to properly deal with an AbstractSnapshot, we need a base directory (to
-  -- deal with custom snapshot relative paths). We consider the current working
-  -- directory to be the correct base. Let's calculate the mSnapshot first.
+  -- The snapshot is provided on the command line. In order to properly deal
+  -- with an AbstractSnapshot, we need a base directory (to deal with custom
+  -- snapshot relative paths). We consider the current working directory to be
+  -- the correct base. We calculate the mSnapshot first.
   mSnapshot <- forM config.snapshot $ \aSnapshot -> do
     logDebug $
-          "Using snapshot: "
-       <> display aSnapshot
-       <> " specified on command line"
+         "Using snapshot: "
+      <> display aSnapshot
+      <> " specified on command line"
     makeConcreteSnapshot aSnapshot
 
-  (project', configFile) <- case config.project of
+  (project, configFile) <- case config.project of
     PCProject (project, fp) -> do
-      forM_ project.userMsg prettyUserMessage
+      when reportUserMessage $
+        forM_ project.userMsg prettyUserMessage
       pure (project, Right fp)
     PCNoProject extraDeps -> do
-      p <-
+      project <-
         case mSnapshot of
           Nothing -> throwIO NoSnapshotWhenUsingNoProject
           Just _ -> getEmptyProject mSnapshot extraDeps
-      pure (p, Left config.userGlobalConfigFile)
+      pure (project, Left config.userGlobalConfigFile)
     PCGlobalProject -> do
       logDebug "Run from outside a project, using implicit global project config"
       destDir <- getImplicitGlobalProjectDir
@@ -839,7 +891,7 @@             , style Shell "snapshot"
             , flow "key there."
             ]
-          p <- getEmptyProject mSnapshot []
+          project <- getEmptyProject mSnapshot []
           liftIO $ do
             writeBinaryFileAtomic dest $ byteString $ S.concat
               [ "# This is the implicit global project's configuration file, which is only used\n"
@@ -850,45 +902,24 @@               , "# For more information about Stack's configuration, see\n"
               , "# http://docs.haskellstack.org/en/stable/configure/yaml/\n"
               , "#\n"
-              , Yaml.encode p]
-            writeBinaryFileAtomic (parent dest </> relFileReadmeTxt) $
-              "This is the implicit global project, which is " <>
-              "used only when 'stack' is run\noutside of a " <>
-              "real project.\n"
-          pure (p, Right dest)
-  mcompiler <- view $ globalOptsL . to (.compiler)
-  let project :: Project
-      project = project'
-        { Project.compiler = mcompiler <|> project'.compiler
-        , Project.snapshot = fromMaybe project'.snapshot mSnapshot
-        }
-      -- We are indifferent as to whether the configuration file is a
-      -- user-specific global or a project-level one.
-      eitherConfigFile = EE.fromEither configFile
-  extraPackageDBs <- mapM resolveDir' project.extraPackageDBs
-
-  smWanted <- lockCachedWanted eitherConfigFile project.snapshot $
-    fillProjectWanted eitherConfigFile config project
-
-  -- Unfortunately redoes getWorkDir, since we don't have a BuildConfig yet
-  workDir <- view workDirL
-  let projectStorageFile = parent eitherConfigFile </> workDir </> relFileStorage
-
-  initProjectStorage projectStorageFile $ \projectStorage -> do
-    let bc = BuildConfig
-          { config
-          , smWanted
-          , extraPackageDBs
-          , configFile
-          , curator = project.curator
-          , projectStorage
-          }
-    runRIO bc inner
+              , Yaml.encode project
+              ]
+            writeBinaryFileAtomic (parent dest </> relFileReadmeTxt) $ mconcat
+              [ "This is the implicit global project, which is used only when 'stack' is run\n"
+              , "outside of a real project.\n"
+              ]
+          pure (project, Right dest)
+  inner $ ConfigExtra
+    { config
+    , mSnapshot
+    , project
+    , configFile
+    }
  where
   getEmptyProject ::
        Maybe RawSnapshotLocation
     -> [RawPackageLocationImmutable]
-    -> RIO Config Project
+    -> RIO env Project
   getEmptyProject mSnapshot extraDeps = do
     snapshot <- case mSnapshot of
       Just snapshot -> do
@@ -916,7 +947,7 @@       , curator = Nothing
       , dropPackages = mempty
       }
-  prettyUserMessage :: String -> RIO Config ()
+  prettyUserMessage :: String -> RIO env ()
   prettyUserMessage userMsg = do
     let userMsgs = map flow $ splitAtLineEnds userMsg
         warningDoc = mconcat $ intersperse blankLine userMsgs
@@ -1212,7 +1243,7 @@   -> Path Abs File
   -> RIO env (Either Yaml.ParseException a)
 loadYaml parser path =
-  liftIO (Yaml.decodeFileEither (toFilePath path)) >>= \case
+  liftIO (YamlInclude.decodeFileEither (toFilePath path)) >>= \case
     Left err -> pure (Left err)
     Right val ->
       case Yaml.parseEither parser val of
src/Stack/Config/Build.hs view
@@ -95,6 +95,7 @@   , interleavedOutput = fromFirstTrue buildMonoid.interleavedOutput
   , progressBar = fromFirst CappedBar buildMonoid.progressBar
   , ddumpDir = getFirst buildMonoid.ddumpDir
+  , semaphore = fromFirstFalse buildMonoid.semaphore
   }
  where
   isHaddockFromHackage = fromFirstFalse buildMonoid.haddockForHackage
@@ -134,6 +135,10 @@       fromFirst
         defaultTestOpts.maximumTimeSeconds
         toMonoid.maximumTimeSeconds
+  , TestOpts.timeoutGraceSeconds =
+      fromFirst
+        defaultTestOpts.timeoutGraceSeconds
+        toMonoid.timeoutGraceSeconds
   , TestOpts.allowStdin = fromFirstTrue toMonoid.allowStdin
   }
 
src/Stack/Config/ConfigureScript.hs view
@@ -1,5 +1,6 @@-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoImplicitPrelude   #-}
+{-# LANGUAGE OverloadedRecordDot #-}
+{-# LANGUAGE OverloadedStrings   #-}
 
 {-|
 Module      : Stack.Config.ConfigureScript
@@ -12,15 +13,17 @@ 
 import           Path ( (</>) )
 import           Path.IO ( doesFileExist )
+import           RIO.Process ( withWorkingDir )
 import           Stack.Constants ( osIsWindows, relFileConfigure )
 import           Stack.DefaultColorWhen ( defaultColorWhen )
 import           Stack.Prelude
-import           RIO.Process ( HasProcessContext, withWorkingDir )
+import           Stack.Types.Config ( Config (..), HasConfig (..) )
+import           Stack.Types.MsysEnvironment ( MsysEnvironment (..) )
 
 -- | For the given directory, yields an action that trys to generate a
 -- @configure@ script with @autoreconf@, if one does not exist in the directory.
 ensureConfigureScript ::
-     (HasProcessContext env, HasTerm env)
+     HasConfig env
   => Path b Dir
   -> RIO env ()
 ensureConfigureScript dir = do
@@ -55,6 +58,7 @@         <> blankLine
         <> string (displayException ex)
       when osIsWindows $ do
+        config <- view configL
         prettyInfo $
              fillSep
                [ flow "Check that executable"
@@ -79,22 +83,7 @@           <> line
           <> indent 4 (style Shell $ flow "stack exec where.exe -- aclocal")
           <> blankLine
-          <> fillSep
-               [ "If"
-               , style File "perl" <> ","
-               , style File "autoreconf"
-               , "or"
-               , style File "aclocal"
-               , flow "is not on the path in the required location, add them \
-                      \with command (note that the relevant package name is"
-               , style File "autotools"
-               , "not"
-               , style File "autoreconf" <> "):"
-               ]
-          <> blankLine
-          <> indent 4
-               (style Shell $ flow "stack exec pacman -- --sync --refresh mingw-w64-x86_64-autotools")
-          <> blankLine
+          <> maybe mempty advice config.msysEnvironment
           <> fillSep
                [ flow "Some versions of"
                , style File "perl"
@@ -107,6 +96,33 @@                , flow "in the required location is working, try command:"
                ]
           <> blankLine
-          <> indent 4 (style Shell $ flow "stack exec perl -- --version")
+          <> indent 4 (style Shell "stack exec perl -- --version")
           <> blankLine
     fixupOnWindows
+ where
+  advice :: MsysEnvironment -> StyleDoc
+  advice CLANG32 = mempty
+  advice MINGW32 = mempty
+  advice CLANG64 = adviceWith "mingw-w64-clang-x86_64-autotools"
+  advice CLANGARM64 = adviceWith "mingw-w64-clang-aarch64-autotools"
+  advice MINGW64 = adviceWith "mingw-w64-x86_64-autotools"
+  advice UCRT64 = adviceWith "mingw-w64-ucrt-x86_64-autotools"
+
+  adviceWith :: StyleDoc -> StyleDoc
+  adviceWith msysPackage =
+       fillSep
+         [ "If"
+         , style File "perl" <> ","
+         , style File "autoreconf"
+         , "or"
+         , style File "aclocal"
+         , flow "is not on the path in the required location, add them \
+                \with command (note that the relevant package name is"
+         , style File "autotools"
+         , "not"
+         , style File "autoreconf" <> "):"
+         ]
+    <> blankLine
+    <> indent 4
+         (style Shell $ "stack exec pacman -- --sync --refresh " <> msysPackage)
+    <> blankLine
src/Stack/Config/Nix.hs view
@@ -12,13 +12,13 @@ -}
 
 module Stack.Config.Nix
-  ( ConfigNixException
+  ( ConfigNixPrettyException
   , nixCompiler
   , nixCompilerVersion
   , nixOptsFromMonoid
   ) where
 
-import           Control.Monad.Extra ( ifM )
+import           Control.Monad.Extra ( ifM, whenJust )
 import qualified Data.Text as T
 import qualified Data.Text.IO as TIO
 import           Distribution.System ( OS (..) )
@@ -28,27 +28,48 @@ import           Stack.Types.Nix ( NixOpts (..), NixOptsMonoid (..) )
 import           System.Directory ( doesFileExist )
 
--- | Type representing exceptions thrown by functions exported by the
+-- | Type representing \'pretty\' exceptions thrown by functions exported by the
 -- "Stack.Config.Nix" module.
-data ConfigNixException
-  = NixCannotUseShellFileAndPackagesException
+data ConfigNixPrettyException
+  = NixCannotUseShellFileAndPackagesException !FilePath ![Text]
     -- ^ Nix can't be given packages and a shell file at the same time
   | GHCMajorVersionUnspecified
   | OnlyGHCSupported
   deriving Show
 
-instance Exception ConfigNixException where
-  displayException NixCannotUseShellFileAndPackagesException =
-    "Error: [S-2726]\n"
-    ++ "You cannot have packages and a shell-file filled at the same time \
-       \in your nix-shell configuration."
-  displayException GHCMajorVersionUnspecified =
-    "Error: [S-9317]\n"
-    ++ "GHC major version not specified."
-  displayException OnlyGHCSupported =
-    "Error: [S-8605]\n"
-    ++ "Only GHC is supported by 'stack --nix'."
+instance Pretty ConfigNixPrettyException where
+  pretty (NixCannotUseShellFileAndPackagesException initFile packages) =
+    "[S-2726]"
+    <> line
+    <> flow "The configuration of Stack's Nix integration cannot specify both \
+            \a Nix shell file and Nix packages. You have specified:"
+    <> blankLine
+    <> spacedBulletedList
+         [ fillSep
+             [ flow "Shell file:"
+             , style File (fromString initFile) <> ";"
+             , "and"
+             ]
+         , fillSep $
+               flow "Nix packages:"
+             : mkNarrativeList (Just Shell) False prettyPackages
+         ]
+   where
+    prettyPackages :: [StyleDoc]
+    prettyPackages = map (fromString . T.unpack) packages
+  pretty GHCMajorVersionUnspecified =
+    "[S-9317]"
+    <> line
+    <> flow "Stack's Nix integration requires at least a major version of GHC \
+            \to be specified. No major version is specified."
+  pretty OnlyGHCSupported =
+    "[S-8605]"
+    <> line
+    <> flow "Stack's Nix integration supports only GHC binary distributions as \
+            \compiler."
 
+instance Exception ConfigNixPrettyException
+
 -- | Interprets NixOptsMonoid options.
 nixOptsFromMonoid ::
      (HasRunner env, HasTerm env)
@@ -79,8 +100,9 @@         pure False
       else pure nixEnable0
 
-  when (not (null packages) && isJust initFile) $
-    throwIO NixCannotUseShellFileAndPackagesException
+  unless (null packages) $ whenJust initFile $ \fp ->
+    prettyThrowIO $ NixCannotUseShellFileAndPackagesException fp packages
+
   pure NixOpts
     { enable
     , pureShell
@@ -93,7 +115,7 @@   prefixAll p (x:xs) = p : x : prefixAll p xs
   prefixAll _ _      = []
 
-nixCompiler :: WantedCompiler -> Either ConfigNixException T.Text
+nixCompiler :: WantedCompiler -> Either ConfigNixPrettyException T.Text
 nixCompiler compilerVersion =
   case compilerVersion of
     WCGhc version ->
@@ -119,7 +141,7 @@     WCGhcjs{} -> Left OnlyGHCSupported
     WCGhcGit{} -> Left OnlyGHCSupported
 
-nixCompilerVersion :: WantedCompiler -> Either ConfigNixException T.Text
+nixCompilerVersion :: WantedCompiler -> Either ConfigNixPrettyException T.Text
 nixCompilerVersion compilerVersion =
   case compilerVersion of
     WCGhc version ->
src/Stack/ConfigCmd.hs view
@@ -18,7 +18,10 @@   , cfgCmdEnvName
   , cfgCmdBuildFiles
   , cfgCmdBuildFilesName
+  , cfgCmdCompilerTools
+  , cfgCmdCompilerToolsName
   , cfgCmdName
+  , yamlContainsInclude
   ) where
 
 import qualified Data.Aeson.Key as Key
@@ -31,63 +34,71 @@ import qualified Data.Text as T
 import qualified Data.Yaml as Yaml
 import           Pantry ( loadSnapshot )
-import           Path ( (</>), parent )
+import           Path ( parent )
+import           Path.IO ( ensureDir )
 import qualified RIO.Map as Map
 import           RIO.NonEmpty ( nonEmpty )
 import qualified RIO.NonEmpty as NE
 import           RIO.Process ( envVarsL )
-import           Stack.Config
-                   ( makeConcreteSnapshot, getProjectConfig
-                   , getImplicitGlobalProjectDir
-                   )
-import           Stack.Constants ( stackDotYaml )
+import           Stack.Config ( makeConcreteSnapshot, withConfigExtra )
 import           Stack.Prelude
 import           Stack.Types.BuildConfig ( BuildConfig )
 import           Stack.Types.Config ( Config (..), HasConfig (..) )
+import           Stack.Types.ConfigExtra ( ConfigExtra (..) )
 import           Stack.Types.ConfigMonoid
-                   ( configMonoidInstallGHCName
-                   , configMonoidInstallMsysName
+                   ( configMonoidInstallGHCName, configMonoidInstallMsysName
                    , configMonoidRecommendStackUpgradeName
                    , configMonoidSystemGHCName
                    )
 import           Stack.Types.ConfigSetOpts
                    ( CommandScope (..), ConfigCmdSet (..) ,configCmdSetScope )
-import           Stack.Types.EnvConfig ( EnvConfig )
+import           Stack.Types.EnvConfig ( EnvConfig, bindirCompilerTools )
 import           Stack.Types.EnvSettings ( EnvSettings (..) )
 import           Stack.Types.GHCVariant ( HasGHCVariant )
-import           Stack.Types.GlobalOpts ( GlobalOpts (..) )
-import           Stack.Types.ProjectConfig ( ProjectConfig (..) )
-import           Stack.Types.Runner ( globalOptsL )
 import           Stack.Types.Snapshot ( AbstractSnapshot )
 import           System.Environment ( getEnvironment )
 
--- | Type repesenting exceptions thrown by functions exported by the
+-- | Type repesenting \'pretty\' exceptions thrown by functions exported by the
 -- "Stack.ConfigCmd" module.
-data ConfigCmdException
+data ConfigCmdPrettyException
   = NoProjectConfigAvailable
+  | ConfigFileContainsIncludes !(Path Abs File)
   deriving Show
 
-instance Exception ConfigCmdException where
-  displayException NoProjectConfigAvailable =
-    "Error: [S-3136]\n"
-    ++ "'config' command used when no project configuration available."
+instance Pretty ConfigCmdPrettyException where
+  pretty NoProjectConfigAvailable =
+    "[S-3136]"
+    <> line
+    <> fillSep
+         [ style Shell "config"
+         , flow "command used when no project configuration available."
+         ]
+  pretty (ConfigFileContainsIncludes configFile) =
+    "[S-6088]"
+    <> line
+    <> fillSep
+         [ "The"
+         , style Shell "config set"
+         , flow "command cannot add a new key to a configuration file that uses"
+         , style Shell "!include"
+         , "directives:"
+         , pretty configFile
+         ]
 
+instance Exception ConfigCmdPrettyException
+
 -- | Function underlying Stack's @config set@ command.
 cfgCmdSet ::
      (HasConfig env, HasGHCVariant env)
   => ConfigCmdSet -> RIO env ()
-cfgCmdSet cmd = do
-  conf <- view configL
-  configFilePath <-
-    case configCmdSetScope cmd of
-      CommandScopeProject -> do
-        mstackYamlOption <- view $ globalOptsL . to (.stackYaml)
-        mstackYaml <- getProjectConfig mstackYamlOption
-        case mstackYaml of
-          PCProject stackYaml -> pure stackYaml
-          PCGlobalProject -> getImplicitGlobalProjectDir <&> (</> stackDotYaml)
-          PCNoProject _extraDeps -> throwIO NoProjectConfigAvailable
-          -- maybe modify the ~/.stack/config.yaml file instead?
+-- We ignore any user message in the project-level configuration file:
+cfgCmdSet cmd = withConfigExtra False $ \configExtra -> do
+  let conf = configExtra.config
+  configFilePath <- case configCmdSetScope cmd of
+      CommandScopeProject -> case configExtra.configFile of
+        Left _ -> prettyThrowIO NoProjectConfigAvailable
+        -- Maybe modify the global configuration file (config.yaml) instead?
+        Right fp -> pure fp
       CommandScopeGlobal -> pure conf.userGlobalConfigFile
   rawConfig <- liftIO (readFileUtf8 (toFilePath configFilePath))
   config <- either throwM pure (Yaml.decodeEither' $ encodeUtf8 rawConfig)
@@ -101,6 +112,8 @@       primaryCmdKey = NE.last $ NE.head cmdKeys
   newYamlLines <- case hits of
     [] -> do
+      when (yamlContainsInclude rawConfig) $
+        prettyThrowIO (ConfigFileContainsIncludes configFilePath)
       prettyInfoL
         [ pretty configFilePath
         , flow "has been extended."
@@ -267,8 +280,21 @@   concreteSnapshot <- makeConcreteSnapshot snapshot'
   -- Check that the snapshot actually exists
   void $ loadSnapshot =<< completeSnapshotLocation concreteSnapshot
-  pure (Yaml.toJSON concreteSnapshot)
+  rslValue concreteSnapshot
 
+rslValue :: HasConfig env => RawSnapshotLocation -> RIO env Yaml.Value
+rslValue (RSLCompiler compiler) = pure $ Yaml.toJSON compiler
+rslValue (RSLUrl url Nothing) = pure $ Yaml.toJSON url
+rslValue (RSLUrl url _) = do
+  -- I can't see how this would ever arise, but it is added for completeness:
+  prettyWarnL
+    [ flow "The specified snapshot value is a URL. The associated SHA256 hash \
+           \and file size will be ignored."
+    ]
+  pure $ Yaml.toJSON url
+rslValue (RSLFilePath rp) = pure $ Yaml.toJSON $ resolvedRelative rp
+rslValue rsl = pure $ Yaml.toJSON rsl
+
 cfgCmdSetKeys :: ConfigCmdSet -> NonEmpty (NonEmpty Text)
 cfgCmdSetKeys (ConfigCmdSetSnapshot _) = [["snapshot"], ["resolver"]]
 cfgCmdSetKeys (ConfigCmdSetResolver _) = [["resolver"], ["snapshot"]]
@@ -280,6 +306,24 @@ cfgCmdSetKeys (ConfigCmdSetDownloadPrefix _ _) =
   [["package-index", "download-prefix"]]
 
+-- | Check if YAML content contains a @!include@ directive in value position.
+-- This covers both inline values (e.g. @key: !include path@) and values on
+-- the next line after indentation. Stack config keys do not contain spaces or
+-- colons, so the first @:@ is always the value separator.
+yamlContainsInclude :: Text -> Bool
+yamlContainsInclude =
+ let lineContainsInclude yamlLine =
+       let stripped = T.stripStart yamlLine
+       in  includeAsValue stripped || includeOnOwnLine stripped
+
+     includeAsValue strippedLine =
+       let (_key, rest) = T.breakOn ":" strippedLine
+       in  "!include" `T.isPrefixOf` T.stripStart (T.drop 1 rest)
+
+     includeOnOwnLine strippedLine =
+       "!include" `T.isPrefixOf` strippedLine
+ in  any lineContainsInclude . T.lines
+
 -- | The name of Stack's @config@ command.
 cfgCmdName :: String
 cfgCmdName = "config"
@@ -296,6 +340,10 @@ cfgCmdBuildFilesName :: String
 cfgCmdBuildFilesName = "build-files"
 
+-- | The name of Stack's @config@ command's @compiler-tools-bin@ subcommand.
+cfgCmdCompilerToolsName :: String
+cfgCmdCompilerToolsName = "compiler-tools"
+
 data EnvVarAction = EVASet !Text | EVAUnset
   deriving Show
 
@@ -329,3 +377,7 @@ -- 'Stack.Config.withBuildConfig' that yields the desired actions.
 cfgCmdBuildFiles :: () -> RIO BuildConfig ()
 cfgCmdBuildFiles () = pure ()
+
+-- | This function takes no settings.
+cfgCmdCompilerTools :: () -> RIO EnvConfig ()
+cfgCmdCompilerTools () = bindirCompilerTools >>= ensureDir
src/Stack/DependencyGraph.hs view
@@ -117,9 +117,12 @@   localNames <- view $ buildConfigL . to (Map.keysSet . (.smWanted.project))
   logDebug "Creating dependency graph"
   (compiler, resultGraph) <- createDependencyGraph dotOpts
-  let pkgsToPrune = if dotOpts.includeBase
-                      then dotOpts.prune
-                      else Set.insert "base" dotOpts.prune
+  let pkgsToPrune = Set.union
+        ( if dotOpts.includeBase
+            then dotOpts.prune
+            else Set.insert "base" dotOpts.prune
+        )
+        (nonParentDependencies resultGraph dotOpts.reach)
       prunedGraph = pruneGraph localNames pkgsToPrune resultGraph
   logDebug "Returning pruned dependency graph"
   pure (compiler, localNames, prunedGraph)
@@ -394,9 +397,7 @@     if pkg `F.elem` names
       then Nothing
       else let filtered = Set.filter (`F.notElem` names) pkgDeps
-           in  if Set.null filtered && not (Set.null pkgDeps)
-                 then Nothing
-                 else Just (filtered, x))
+           in  Just (filtered, x))
 
 -- | Make sure that all unreachable nodes (orphans) are pruned
 pruneUnreachable ::
@@ -412,6 +413,37 @@    where
     reachable k = k `F.elem` dontPrune || k `Set.member` reachables
     reachables = F.fold (fst <$> graph')
+
+nonParentDependencies ::
+     F.Foldable f
+  => Map PackageName (Set PackageName, a)
+  -> f PackageName
+  -> Set PackageName
+nonParentDependencies graph names
+  | F.null names = Set.empty
+  | otherwise =
+      Set.difference (Map.keysSet graph) (backwardReachable names graph)
+
+backwardReachable ::
+     F.Foldable f
+  => f PackageName
+  -> Map PackageName (Set PackageName, a)
+  -> Set PackageName
+backwardReachable names graph = go Set.empty (F.toList names)
+  where
+    reverseGraph =
+      Map.fromListWith Set.union
+        [ (dep, Set.singleton name)
+        | (name, (deps, _)) <- Map.toList graph
+        , dep <- Set.toList deps
+        ]
+
+    go seen [] = seen
+    go seen (x : xs)
+      | x `Set.member` seen = go seen xs
+      | otherwise =
+          let parents = Map.findWithDefault Set.empty x reverseGraph
+          in go (Set.insert x seen) (Set.toList parents <> xs)
 
 localPackageToPackage :: LocalPackage -> Package
 localPackageToPackage lp = fromMaybe lp.package lp.testBench
src/Stack/Ghci.hs view
@@ -916,32 +916,37 @@   -> RIO env GhciPkgInfo
 makeGhciPkgInfo installMap installedMap locals addPkgs mfileTargets pkgDesc = do
   bopts <- view buildOptsL
-  let pkg = pkgDesc.package
+  let package = pkgDesc.package
       cabalFP = pkgDesc.cabalFP
       target = pkgDesc.target
-      name = pkg.name
-  (mods, files, opts) <-
-    getPackageOpts pkg installMap installedMap locals addPkgs cabalFP
-  let filteredOpts = filterWanted opts
+      name = package.name
+      dir = parent cabalFP
+      targetFiles = mfileTargets >>= M.lookup name
+  (mods, files, allOpts) <-
+    getPackageOpts package installMap installedMap locals addPkgs cabalFP
+  let opts = M.toList $ filterWanted allOpts
       filterWanted :: Map NamedComponent a -> Map NamedComponent a
       filterWanted = M.filterWithKey (\k _ -> k `S.member` allWanted)
-      allWanted = wantedPackageComponents bopts target pkg
-  pure GhciPkgInfo
-    { name
-    , opts = M.toList filteredOpts
-    , dir = parent cabalFP
-    , modules = unionModuleMaps $
+      allWanted = wantedPackageComponents bopts target package
+      modules = unionModuleMaps $
         map
           ( \(comp, mp) -> M.map
-              (\fp -> M.singleton fp (S.singleton (pkg.name, comp)))
+              (\fp -> M.singleton fp (S.singleton (name, comp)))
               mp
           )
           (M.toList (filterWanted mods))
-    , mainIs = M.map (mapMaybe dotCabalMainPath) files
-    , cFiles = mconcat
+      mainIs = M.map (mapMaybe dotCabalMainPath) files
+      cFiles = mconcat
         (M.elems (filterWanted (M.map (mapMaybe dotCabalCFilePath) files)))
-    , targetFiles = mfileTargets >>= M.lookup name
-    , package = pkg
+  pure GhciPkgInfo
+    { name
+    , opts
+    , dir
+    , modules
+    , mainIs
+    , cFiles
+    , targetFiles
+    , package
     }
 
 -- NOTE: this should make the same choices as the components code in
src/Stack/Init.hs view
@@ -437,8 +437,8 @@     , "A snapshot dictates the compiler version and the set of packages"
     , "to be used for project dependencies. For example:"
     , ""
-    , "snapshot: lts-24.24"
-    , "snapshot: nightly-2025-12-20"
+    , "snapshot: lts-24.43"
+    , "snapshot: nightly-2026-05-29"
     , "snapshot: ghc-9.10.3"
     , ""
     , "The location of a snapshot can be provided as a file or url. Stack assumes"
src/Stack/Ls.hs view
@@ -31,8 +31,8 @@ import qualified Data.Text.IO as T
 import qualified Data.Vector as V
 import           Network.HTTP.StackClient
-                   ( addRequestHeader, hAccept, httpJSON, getResponseBody
-                   , parseRequest
+                   ( HttpException (..), addRequestHeader, getResponseBody
+                   , hAccept, httpJSON, parseUrlThrow
                    )
 import           Path ( parent )
 import           RIO.List ( sort )
@@ -48,7 +48,8 @@ import           Stack.SourceMap ( globalsFromHints )
 import           Stack.Types.BuildConfig
                    ( BuildConfig (..), HasBuildConfig (..) )
-import           Stack.Types.Config ( Config (..), HasConfig (..) )
+import           Stack.Types.Config
+                   ( Config (..), HasConfig (..), askRecentSnapshotsUrl )
 import           Stack.Types.DependencyTree
                    ( DependencyGraph, DependencyTree (..), DotPayload (..)
                    , licenseText, versionText
@@ -63,7 +64,7 @@                    , ListStylesOpts (..), ListToolsOpts (..), LsView (..)
                    , SnapshotOpts (..)
                    )
-import           Stack.Types.Runner ( HasRunner, Runner, terminalL )
+import           Stack.Types.Runner ( Runner, terminalL )
 import           Stack.Types.SourceMap ( SMWanted (..) )
 import           System.Console.ANSI.Codes
                    ( SGR (Reset), setSGRCode, sgrToCode )
@@ -71,18 +72,35 @@ import           System.Directory ( listDirectory )
 import           System.IO ( putStrLn )
 
--- | Type representing exceptions thrown by functions exported by the "Stack.Ls"
--- module.
-newtype LsException
-  = ParseFailure [Value]
-  deriving Show
+-- | Type representing \'pretty\' exceptions thrown by functions exported by the
+-- "Stack.Ls" module.
+data LsPrettyException
+  = ParseFailure ![Value]
+  | ParseRecentSnapshotsUrlFailed !HttpException
 
-instance Exception LsException where
-  displayException (ParseFailure val) =
-    "Error: [S-3421]\n"
-    ++ "Failure to parse values as a snapshot: "
-    ++ show val
+deriving instance Show LsPrettyException
 
+instance Pretty LsPrettyException where
+  pretty (ParseFailure val) =
+    "[S-3421]"
+    <> line
+    <> fillSep
+         [ flow "Failure to parse values as a snapshot:"
+         , string (show val)
+         ]
+  pretty (ParseRecentSnapshotsUrlFailed err) =
+    "[S-9131]"
+    <> line
+    <> fillSep
+         [ flow "While trying to parse the"
+         , style Shell "recent-snapshots"
+         , flow "URL, Stack encountered the following error:"
+         ]
+    <> blankLine
+    <> fromString (displayException err)
+
+instance Exception LsPrettyException
+
 -- | Type representing Stackage snapshot types.
 data SnapshotType
   = Lts
@@ -120,7 +138,7 @@     , title
     , time
     }
-toSnapshot val = impureThrow $ ParseFailure val
+toSnapshot val = prettyImpureThrow $ ParseFailure val
 
 parseSnapshot :: Value -> A.Parser Snapshot
 parseSnapshot = A.withArray "array of snapshot" (pure . toSnapshot . V.toList)
@@ -199,9 +217,12 @@     LsStyles _ -> pure ()
     LsTools _ -> pure ()
 
-handleRemote :: HasRunner env => LsCmdOpts -> RIO env ()
+handleRemote :: HasConfig env => LsCmdOpts -> RIO env ()
 handleRemote lsOpts = do
-  req <- liftIO $ parseRequest urlInfo
+  urlInfoText <- askRecentSnapshotsUrl
+  req <- catch
+    (parseUrlThrow $ T.unpack urlInfoText)
+    (prettyThrowM . ParseRecentSnapshotsUrlFailed)
   isStdoutTerminal <- view terminalL
   let req' = addRequestHeader hAccept "application/json" req
   result <- httpJSON req'
@@ -222,8 +243,6 @@     LsDependencies _ -> pure ()
     LsStyles _ -> pure ()
     LsTools _ -> pure ()
- where
-  urlInfo = "https://www.stackage.org/snapshots"
 
 -- | Function underlying the @stack ls@ command.
 lsCmd :: LsCmdOpts -> RIO Runner ()
@@ -232,7 +251,7 @@     LsSnapshot sopt ->
       case sopt.viewType of
         Local -> handleLocal lsOpts
-        Remote -> handleRemote lsOpts
+        Remote -> withConfig NoReexec $ handleRemote lsOpts
     LsGlobals globalsOpts -> withConfig NoReexec $ listGlobalsCmd globalsOpts
     LsDependencies depOpts -> listDependencies depOpts
     LsStyles stylesOpts -> withConfig NoReexec $ listStylesCmd stylesOpts
src/Stack/Nix.hs view
@@ -36,18 +36,21 @@ import           System.Environment ( getArgs, lookupEnv )
 import qualified System.FilePath as F
 
--- | Type representing exceptions thrown by functions exported by the
--- "Stack.Nix" module.
-data NixException
+-- | Type representing  \'pretty\' exceptions thrown by functions exported by
+-- the "Stack.Nix" module.
+data NixPrettyException
   = CannotDetermineProjectRoot
     -- ^ Can't determine the project root (location of the shell file if any).
   deriving Show
 
-instance Exception NixException where
-  displayException CannotDetermineProjectRoot =
-    "Error: [S-7384]\n"
-    ++ "Cannot determine project root directory."
+instance Pretty NixPrettyException where
+  pretty CannotDetermineProjectRoot =
+    "[S-7384]"
+    <> line
+    <> flow "Cannot determine project root directory."
 
+instance Exception NixPrettyException
+
 -- | Execute @nix-shell@, replacing the current process.
 runShellAndExit :: RIO Config void
 runShellAndExit = do
@@ -77,10 +80,12 @@     -- (thus the void return type)
     compilerVersion <- withBuildConfig $ view wantedCompilerVersionL
 
-    ghc <- either throwIO pure $ nixCompiler compilerVersion
-    ghcVersion <- either throwIO pure $ nixCompilerVersion compilerVersion
+    ghc <- either prettyThrowIO pure $ nixCompiler compilerVersion
+    ghcVersion <- either prettyThrowIO pure $ nixCompilerVersion compilerVersion
     let pkgsInConfig = config.nix.packages
-        pkgs = pkgsInConfig ++ [ghc, "git", "gcc", "gmp"]
+        -- It appears that cacert needs to be specified in order for
+        -- crypton-x509-system >= 1.6.8 to work with Stack's Nix integration:
+        pkgs = pkgsInConfig ++ [ghc, "git", "gcc", "gmp", "cacert"]
         pkgsStr = "[" <> T.intercalate " " pkgs <> "]"
         pureShell = config.nix.pureShell
         addGCRoots = config.nix.addGCRoots
src/Stack/Options/BuildMonoidParser.hs view
@@ -36,7 +36,8 @@ -- | Parse command line arguments for build configuration.
 buildOptsMonoidParser :: GlobalOptsContext -> Parser BuildOptsMonoid
 buildOptsMonoidParser hide0 = BuildOptsMonoid
-  <$> trace'
+  <$> semaphore
+  <*> trace'
   <*> profile
   <*> noStrip
   <*> libProfiling
@@ -244,6 +245,11 @@     <> help "Specify output directory for ddump-files."
     <> hide
     ))
+  semaphore = firstBoolFlagsFalse
+    "semaphore"
+    "the use of a system semaphore to perform compilation in parallel when \
+    \possible. Supported, by default, by GHC 9.10.1 or later."
+    hide
 
 -- | Parser for Cabal verbosity options
 cabalVerbosityOptsParser :: Bool -> Parser (First CabalVerbosity)
src/Stack/Options/ConfigEnvParser.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude   #-}
+{-# LANGUAGE OverloadedRecordDot #-}
 
 {-|
 Module      : Stack.Options.ConfigEnvParser
@@ -14,16 +15,34 @@ import qualified Options.Applicative as OA
 import           Options.Applicative.Builder.Extra ( boolFlags )
 import           Stack.Prelude
-import           Stack.Types.EnvSettings ( EnvSettings (..) )
+import           Stack.Types.EnvSettings
+                   ( EnvSettings (..), defaultEnvSettings )
 
 -- | Parse command line arguments for Stack's @config env@ command.
 configCmdEnvParser :: OA.Parser EnvSettings
 configCmdEnvParser = EnvSettings
-  <$> boolFlags True "locals" "include information about local packages" mempty
-  <*> boolFlags True
-        "ghc-package-path" "set GHC_PACKAGE_PATH environment variable" mempty
-  <*> boolFlags True "stack-exe" "set STACK_EXE environment variable" mempty
-  <*> boolFlags False
-        "locale-utf8" "set the GHC_CHARENC environment variable to UTF-8" mempty
-  <*> boolFlags False
-        "keep-ghc-rts" "keep any GHCRTS environment variable" mempty
+  <$> boolFlags
+        defaultEnvSettings.includeLocals
+        "locals"
+        "include information about local packages"
+        mempty
+  <*> boolFlags
+        defaultEnvSettings.includeGhcPackagePath
+        "ghc-package-path"
+        "set GHC_PACKAGE_PATH environment variable"
+        mempty
+  <*> boolFlags
+        defaultEnvSettings.stackExe
+        "stack-exe"
+        "set STACK_EXE environment variable"
+        mempty
+  <*> boolFlags
+        defaultEnvSettings.localeUtf8
+        "locale-utf8"
+        "set the GHC_CHARENC environment variable to UTF-8"
+        mempty
+  <*> boolFlags
+        defaultEnvSettings.keepGhcRts
+        "keep-ghc-rts"
+        "keep any GHCRTS environment variable"
+        mempty
src/Stack/Options/ConfigSetParser.hs view
@@ -36,7 +36,7 @@               <$> OA.argument
                     readAbstractSnapshot
                     (  OA.metavar "SNAPSHOT"
-                    <> OA.help "E.g. \"nightly\" or \"lts-24.24\"" ))
+                    <> OA.help "E.g. \"nightly\" or \"lts-24.43\"" ))
               ( OA.progDesc
                   "Change the snapshot of the current project." ))
       , OA.command "resolver"
@@ -45,7 +45,7 @@               <$> OA.argument
                     readAbstractSnapshot
                     (  OA.metavar "SNAPSHOT"
-                    <> OA.help "E.g. \"nightly\" or \"lts-24.24\"" ))
+                    <> OA.help "E.g. \"nightly\" or \"lts-24.43\"" ))
               ( OA.progDesc
                   "Change the snapshot of the current project, using the \
                   \(deprecated) resolver key." ))
src/Stack/Options/DotParser.hs view
@@ -34,6 +34,7 @@   <*> includeBase
   <*> depthLimit
   <*> fmap (maybe Set.empty $ Set.fromList . splitNames) prunedPkgs
+  <*> fmap (maybe Set.empty $ Set.fromList . splitNames) reachPkgs
   <*> targetsParser
   <*> flagsParser
   <*> testTargets
@@ -57,6 +58,13 @@     (  long "prune"
     <> metavar "PACKAGES"
     <> help "Prune specified package(s). PACKAGES is a comma-separated list of \
+            \package names."
+    ))
+  reachPkgs = optional (strOption
+    (  long "reach"
+    <> metavar "PACKAGES"
+    <> help "Prune packages that cannot reach any of the specified package(s) \
+            \in the dependency graph. PACKAGES is a comma-separated list of \
             \package names."
     ))
 
src/Stack/Options/ExecParser.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude   #-}
+{-# LANGUAGE OverloadedRecordDot #-}
 
 {-|
 Module      : Stack.Options.ExecParser
@@ -23,7 +24,8 @@                    ( ExecOpts (..), ExecOptsExtra (..), SpecialExecCmd (..) )
 import           Stack.Options.Completion ( projectExeCompleter )
 import           Stack.Prelude
-import           Stack.Types.EnvSettings ( EnvSettings (..) )
+import           Stack.Types.EnvSettings
+                   ( EnvSettings (..), defaultEnvSettings )
 
 -- | Parse command line arguments for Stack's @exec@, @ghc@, @run@,
 -- @runghc@ and @runhaskell@ commands.
@@ -57,18 +59,18 @@   <*> eoCwdParser
  where
   eoEnvSettingsParser :: Parser EnvSettings
-  eoEnvSettingsParser = EnvSettings True
-    <$> boolFlags True
+  eoEnvSettingsParser = EnvSettings defaultEnvSettings.includeLocals
+    <$> boolFlags defaultEnvSettings.includeGhcPackagePath
           "ghc-package-path"
           "setting the GHC_PACKAGE_PATH variable for the subprocess."
           idm
-    <*> boolFlags True
+    <*> boolFlags defaultEnvSettings.stackExe
           "stack-exe"
           "setting the STACK_EXE environment variable to the path for the \
           \stack executable."
           idm
-    <*> pure False
-    <*> pure True
+    <*> pure defaultEnvSettings.localeUtf8
+    <*> pure defaultEnvSettings.keepGhcRts
 
   eoPackagesParser :: Parser [String]
   eoPackagesParser = many (strOption
src/Stack/Options/TestParser.hs view
@@ -44,7 +44,15 @@         hide
   <*> optionalFirst (option (fmap Just auto)
         (  long "test-suite-timeout"
-        <> help "Maximum test suite run time in seconds."
+        <> metavar "SECONDS"
+        <> help "For each test suite, maximum run time before it fails."
+        <> hide
+        ))
+  <*> optionalFirst (option (fmap Just auto)
+        (  long "test-suite-timeout-grace"
+        <> metavar "SECONDS"
+        <> help "Request termination of timed-out test suite process. Grace \
+                \period after timeout before termination is forced."
         <> hide
         ))
   <*> firstBoolFlagsTrue
src/Stack/Package.hs view
@@ -38,12 +38,10 @@ 
 import qualified Data.Map.Strict as M
 import qualified Data.Set as S
-import qualified Data.Text as T
 import           Distribution.CabalSpecVersion ( cabalSpecToVersionDigits )
 import           Distribution.Compiler
                    ( CompilerFlavor (..), PerCompilerFlavor (..) )
 import           Distribution.ModuleName ( ModuleName )
-import           Distribution.Package ( mkPackageName )
 import           Distribution.PackageDescription
                    ( Benchmark (..), BuildInfo (..), BuildType (..)
                    , CondTree (..), Condition (..), ConfVar (..)
@@ -87,7 +85,6 @@ import           Stack.Types.CompCollection
                    ( CompCollection, collectionLookup, foldAndMakeCollection
                    , foldComponentToAnotherCollection, getBuildableSet
-                   , getBuildableSetText
                    )
 import           Stack.Types.Compiler ( ActualCompiler (..) )
 import           Stack.Types.CompilerPaths ( cabalVersionL )
@@ -625,7 +622,8 @@ -- | Force a package to be treated as a custom build type, see
 -- <https://github.com/commercialhaskell/stack/issues/4488>
 applyForceCustomBuild ::
-     Version -- ^ global Cabal version
+     Version
+     -- ^ Global Cabal version.
   -> Package
   -> Package
 applyForceCustomBuild cabalVersion package
@@ -695,115 +693,118 @@   -> m a
      -- ^ Initial value.
   -> m a
-processPackageComponent pkg componentFn = do
-  let componentKindProcessor ::
-           forall component. HasComponentInfo component
-        => (Package -> CompCollection component)
-        -> m a
-        -> m a
-      componentKindProcessor target =
-        foldComponentToAnotherCollection
-          (target pkg)
-          componentFn
-      processMainLib = maybe id componentFn pkg.library
-      processAllComp =
-        ( if pkg.benchmarkEnabled
-            then componentKindProcessor (.benchmarks)
-            else id
-        )
-        . ( if pkg.testEnabled
-              then componentKindProcessor (.testSuites)
-              else id
-          )
-        . componentKindProcessor (.foreignLibraries)
-        . componentKindProcessor (.executables)
-        . componentKindProcessor (.subLibraries)
-        . processMainLib
-  processAllComp
+processPackageComponent pkg componentFn =
+    processBenchmarks
+  . processTestSuites
+  . componentKindProcessor (.foreignLibraries)
+  . componentKindProcessor (.executables)
+  . componentKindProcessor (.subLibraries)
+  . processMainLib
+ where
+  processMainLib = maybe id componentFn pkg.library
 
+  componentKindProcessor ::
+       forall component. HasComponentInfo component
+    => (Package -> CompCollection component)
+       -- ^ Accessor.
+    -> m a
+     -- ^ Initial value.
+    -> m a
+  componentKindProcessor target =
+    foldComponentToAnotherCollection (target pkg) componentFn
+
+  processTestSuites = if pkg.testEnabled
+    then componentKindProcessor (.testSuites)
+    else id
+
+  processBenchmarks = if pkg.benchmarkEnabled
+    then componentKindProcessor (.benchmarks)
+    else id
+
 -- | This is a function to iterate in a monad over all of a package's
--- dependencies, and yield a collection of results (used with list and set).
+-- dependencies (including any custom-setup ones), and yield a collection of
+-- results (used with list and set).
 processPackageMapDeps ::
      (Monad m)
   => Package
   -> (Map PackageName DepValue -> m a -> m a)
+     -- ^ Processing function.
   -> m a
+     -- ^ Initial value.
   -> m a
-processPackageMapDeps pkg fn = do
-  let packageSetupDepsProcessor resAction = case pkg.setupDeps of
-        Nothing -> resAction
-        Just v -> fn v resAction
-      processAllComp = processPackageComponent pkg (fn . componentDependencyMap)
-        . packageSetupDepsProcessor
-  processAllComp
+processPackageMapDeps pkg fn =
+  packageDepsProcessor . packageSetupDepsProcessor
+ where
+  packageSetupDepsProcessor action =
+    maybe action (`fn` action) pkg.setupDeps
 
--- | This is a function to iterate in a monad over all of a package component's
--- dependencies, and yield a collection of results.
+  packageDepsProcessor =
+    processPackageComponent pkg (fn . componentDependencyMap)
+
+-- | This is a function to iterate in a monad over all of a package's
+-- dependencies (including any custom-setup ones), and yield a collection of
+-- results.
 processPackageDeps ::
-     (Monad m)
+     forall a b m. Monad m
   => Package
-  -> (smallResT -> resT -> resT)
-  -> (PackageName -> DepValue -> m smallResT)
-  -> m resT
-  -> m resT
-processPackageDeps pkg combineResults fn = do
-  let
-      asPackageNameSet ::
-           (Package -> CompCollection component)
-        -> Set PackageName
-      asPackageNameSet accessor =
-        S.map (mkPackageName . T.unpack) $ getBuildableSetText $ accessor pkg
-      (!subLibNames, !foreignLibNames) =
-        ( asPackageNameSet (.subLibraries)
-        , asPackageNameSet (.foreignLibraries)
-        )
-      shouldIgnoreDep (packageNameV :: PackageName)
-        | packageNameV == pkg.name = True
-        | packageNameV `S.member` subLibNames = True
-        | packageNameV `S.member` foreignLibNames = True
-        | otherwise = False
-      innerIterator packageName depValue resListInMonad
-        | shouldIgnoreDep packageName = resListInMonad
-        | otherwise = do
-            resList <- resListInMonad
-            newResElement <- fn packageName depValue
-            pure $ combineResults newResElement resList
-  processPackageMapDeps pkg (flip (M.foldrWithKey' innerIterator))
+  -> (b -> a -> a)
+     -- ^ Combining function.
+  -> (PackageName -> DepValue -> m b)
+     -- ^ Processing function for a dependency.
+  -> m a
+     -- ^ Intial value.
+  -> m a
+processPackageDeps pkg combineResults fn =
+  processPackageMapDeps pkg (flip (M.foldrWithKey' iterator))
+ where
+  iterator :: PackageName -> DepValue -> m a -> m a
+  iterator depPackageName depValue acc
+    -- If the name of the dependency package is the same as the package, we
+    -- ignore the former. It is possible for a dependency package to have the
+    -- same name as a named sublibrary or a named foreign library.
+    | depPackageName == pkg.name = acc
+    | otherwise = combineResults <$> fn depPackageName depValue <*> acc
 
--- | Iterate/fold on all the package dependencies, components, setup deps and
--- all.
+-- | This is a function to iterate in a monad over all of a package's
+-- dependencies (including any custom-setup ones), and yield a list of
+-- results.
 processPackageDepsToList ::
      Monad m
   => Package
-  -> (PackageName -> DepValue -> m resT)
-  -> m [resT]
+  -> (PackageName -> DepValue -> m b)
+     -- ^ Processing function for a dependency.
+  -> m [b]
 processPackageDepsToList pkg fn = processPackageDeps pkg (:) fn (pure [])
 
--- | Iterate/fold on all the package dependencies, components, setup deps and
--- all.
+-- | This is a function to iterate in a monad over all of a package's
+-- dependencies (including any custom-setup ones), and yield a collection of
+-- the results.
 processPackageDepsEither ::
      (Monad m, Monoid a, Monoid b)
   => Package
   -> (PackageName -> DepValue -> m (Either a b))
+     -- ^ Processing function for dependency.
   -> m (Either a b)
 processPackageDepsEither pkg fn =
-  processPackageDeps pkg combineRes fn (pure (Right mempty))
+  processPackageDeps pkg combineResults fn (pure (Right mempty))
  where
-  combineRes (Left err) (Left errs) = Left (errs <> err)
-  combineRes _ (Left b) = Left b
-  combineRes (Left err) _ = Left err
-  combineRes (Right a) (Right b) = Right $ a <> b
+  combineResults (Left a) (Left b) = Left (a <> b)
+  combineResults _ (Left b) = Left b
+  combineResults (Left a) _ = Left a
+  combineResults (Right a) (Right b) = Right (a <> b)
 
--- | List all package's dependencies in a "free" context through the identity
+-- | List the names of all of a package's dependencies (including any
+-- custom-setup ones) in a "free" context through the 'Data.Functor.Identity'
 -- monad.
 listOfPackageDeps :: Package -> [PackageName]
-listOfPackageDeps pkg =
-  runIdentity $ processPackageDepsToList pkg (\pn _ -> pure pn)
+listOfPackageDeps pkg = runIdentity $
+  processPackageDepsToList pkg (\pn _ -> pure pn)
 
--- | The set of package's dependencies.
+-- | Yield a set of the names of all a package's dependencies (including any
+-- custom-setup ones) through the 'Data.Functor.Identity' monad.
 setOfPackageDeps :: Package -> Set PackageName
-setOfPackageDeps pkg =
-  runIdentity $ processPackageDeps pkg S.insert (\pn _ -> pure pn) (pure mempty)
+setOfPackageDeps pkg = runIdentity $
+  processPackageDeps pkg S.insert (\pn _ -> pure pn) (pure mempty)
 
 -- | This implements a topological sort on all targeted components for the build
 -- and their dependencies. It's only targeting internal dependencies, so it's
src/Stack/Path.hs view
@@ -53,6 +53,7 @@                    , packageDatabaseLocal
                    )
 import qualified Stack.Types.EnvConfig as EnvConfig
+import           Stack.Types.EnvSettings ( defaultEnvSettings )
 import           Stack.Types.GHCVariant ( HasGHCVariant (..) )
 import           Stack.Types.GlobalOpts
                    ( GlobalOpts (..), globalOptsBuildOptsMonoidL )
@@ -123,7 +124,13 @@     T.putStrLn $ prefix <> extractPath info
 
 runHaddockWithEnvConfig :: Bool -> RIO EnvConfig () -> RIO Runner ()
-runHaddockWithEnvConfig x action = runHaddock x (withDefaultEnvConfig action)
+runHaddockWithEnvConfig x action = runHaddock x $
+  withDefaultEnvConfig $ do
+    config <- view configL
+    menv <- liftIO $ config.processContextSettings defaultEnvSettings
+    -- Required, as otherwise (due to withDefaultEnvConfig) the environment is
+    -- based on Stack.Type.EnvSettings.minimalEnvSettings.
+    withProcessContext menv action
 
 runHaddockWithConfig :: RIO Config () -> RIO Runner ()
 runHaddockWithConfig = runHaddock False
@@ -140,11 +147,6 @@   -- We must use a BuildConfig from an EnvConfig to ensure that it contains the
   -- full environment info including GHC paths etc.
   buildConfig <- view $ envConfigL . buildConfigL
-  -- This is the modified 'bin-path',
-  -- including the local GHC or MSYS if not configured to operate on
-  -- global GHC.
-  -- It was set up in 'withBuildConfigAndLock -> withBuildConfigExt -> setupEnv'.
-  -- So it's not the *minimal* override path.
   snapDb <- packageDatabaseDeps
   localDb <- packageDatabaseLocal
   extraDbs <- packageDatabaseExtra
@@ -297,7 +299,7 @@     , "compiler-bin"
     , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . parent . (.compiler)
     )
-  , ( "Directory containing binaries specific to a particular compiler"
+  , ( "The compiler tools directory for the specified compiler version."
     , "compiler-tools-bin"
     , WithoutHaddocks $ T.pack . toFilePathNoTrailingSep . (.toolsDir)
     )
src/Stack/Prelude.hs view
@@ -38,6 +38,7 @@   , ppException
   , prettyThrowIO
   , prettyThrowM
+  , prettyImpureThrow
   , mcons
   , MungedPackageId (..)
   , MungedPackageName (..)
@@ -133,8 +134,8 @@                    )
 import           RIO.PrettyPrint.DefaultStyles (defaultStyles)
 import           RIO.PrettyPrint.PrettyException
-                   ( PrettyException (..), ppException, prettyThrowIO
-                   , prettyThrowM
+                   ( PrettyException (..), ppException, prettyImpureThrow
+                   , prettyThrowIO, prettyThrowM
                    )
 import           RIO.PrettyPrint.StylesUpdate
                    ( StylesUpdate (..), parseStylesUpdateFromString )
src/Stack/Setup/Installed.hs view
@@ -160,8 +160,10 @@       pure mempty
         { bins =
             [ dir </> relDirMsysEnvPrefix </> relDirBin
-            , dir </> relDirUsr </> relDirBin
+              -- Stack follows the Unix-like convention that usr/local/bin
+              -- should have search priority over usr/bin.
             , dir </> relDirUsr </> relDirLocal </> relDirBin
+            , dir </> relDirUsr </> relDirBin
             ]
         , includes =
             [ dir </> relDirMsysEnvPrefix </> relDirInclude
src/Stack/Types/Build/ConstructPlan.hs view
@@ -15,12 +15,14 @@   , CombinedMap
   , M
   , W (..)
+  , LibraryMap
   , AddDepRes (..)
   , toTask
   , adrVersion
   , adrHasLibrary
   , isAdrToInstall
   , Ctx (..)
+  , PackageLoader
   , UnregisterState (..)
   , ToolWarning (..)
   , MissingPresentDeps (..)
@@ -82,15 +84,7 @@ 
 -- | Type synonym representing values used during the construction of a build
 -- plan. The type is an instance of 'Monad', hence its name.
-type M =
-  WriterT
-    W
-    -- ^ The output to be collected
-    ( StateT
-        (Map PackageName (Either ConstructPlanException AddDepRes))
-        -- ^ Library map
-        (RIO Ctx)
-    )
+type M = WriterT W (StateT LibraryMap (RIO Ctx))
 
 -- | Type representing values used as the output to be collected during the
 -- construction of a build plan.
@@ -121,6 +115,11 @@   mempty = memptydefault
   mappend = (<>)
 
+-- | A type synonym representing dictionaries of package names, and either an
+-- exception encountered during the construction of the build plan or the
+-- 'Stack.Build.ConstructPlan.addDep' result.
+type LibraryMap = Map PackageName (Either ConstructPlanException AddDepRes)
+
 -- | Type representing results of 'Stack.Build.ConstructPlan.addDep'.
 data AddDepRes
   = ADRToInstall Task
@@ -175,14 +174,9 @@ data Ctx = Ctx
   { baseConfigOpts :: !BaseConfigOpts
     -- ^ Basic information used to determine configure options
-  , loadPackage    :: !(  PackageLocationImmutable
-                       -> Map FlagName Bool
-                       -> [Text]
-                          -- ^ GHC options.
-                       -> [Text]
-                          -- ^ Cabal configure options.
-                       -> M Package
-                       )
+  , loadPackage    :: !(PackageLoader M)
+    -- ^ A function to load a `Package` given the location of a package assumed
+    -- to be immutable.
   , combinedMap    :: !CombinedMap
     -- ^ A dictionary of package names, and combined information about the
     -- package in respect of whether or not it is already installed and, unless
@@ -196,6 +190,20 @@   , curator       :: !(Maybe Curator)
   , pathEnvVar     :: !Text
   }
+
+-- | A type synonym representing functions that yield a 'Package' given the
+-- location of a package assumed to be immutable, parameterised by the relevant
+-- monad.
+type PackageLoader m =
+     PackageLocationImmutable
+     -- ^ Location of a package that is assumed to be immutable.
+  -> Map FlagName Bool
+     -- ^ Cabal flags.
+  -> [Text]
+     -- ^ GHC options.
+  -> [Text]
+     -- ^ Cabal configure options.
+  -> m Package
 
 instance HasPlatform Ctx where
   platformL = configL . platformL
src/Stack/Types/Build/Exception.hs view
@@ -70,8 +70,6 @@       Version -- version specified on command line
   | NoSetupHsFound (Path Abs Dir)
   | InvalidGhcOptionsSpecification [PackageName]
-  | TestSuiteExeMissing Bool String String String
-  | CabalCopyFailed Bool String
   | LocalPackagesPresent [PackageIdentifier]
   | CouldNotLockDistDir !(Path Abs File)
   | TaskCycleBug PackageIdentifier
@@ -178,23 +176,6 @@       , packageNameString name
       , "' not found"
       ]
-  displayException (TestSuiteExeMissing isSimpleBuildType exeName pkgName' testName) =
-    missingExeError "[S-7987]"
-      isSimpleBuildType $ concat
-        [ "Test suite executable \""
-        , exeName
-        , " not found for "
-        , pkgName'
-        , ":test:"
-        , testName
-        ]
-  displayException (CabalCopyFailed isSimpleBuildType innerMsg) =
-    missingExeError "[S-8027]"
-      isSimpleBuildType $ concat
-        [ "'cabal copy' failed.  Error message:\n"
-        , innerMsg
-        , "\n"
-        ]
   displayException (LocalPackagesPresent locals) = unlines
     $ "Error: [S-5510]"
     : "Local packages are not allowed when using the 'script' command. \
@@ -266,6 +247,8 @@       WantedCompilerSetter -- Way that the wanted compiler is set
       StyleDoc -- recommended resolution
   | ActionNotFilteredBug StyleDoc
+  | TestSuiteExeMissing !Bool !String !PackageName !StackUnqualCompName
+  | CabalCopyFailed !Bool !BuildPrettyException
   deriving Show
 
 instance Pretty BuildPrettyException where
@@ -461,6 +444,29 @@       , flow "is seeking to run an action that should have been filtered from \
              \the list of actions."
       ]
+  pretty (TestSuiteExeMissing isSimpleBuildType exeName pkgName testName) =
+    missingExeError "[S-7987]" isSimpleBuildType $
+         fillSep
+           [ flow "Test suite executable"
+           , style Shell (fromString exeName)
+           , flow "not found for"
+           , style PkgComponent pkgComponent <> "."
+           ]
+      <> line
+   where
+    pkgComponent =
+         fromString (packageNameString pkgName)
+      <> ":test:"
+      <> fromString (unqualCompToString testName)
+  pretty (CabalCopyFailed isSimpleBuildType err) =
+    missingExeError "[S-8027]" isSimpleBuildType $
+         fillSep
+           [ style Shell "cabal copy"
+           , flow "failed. Error message:"
+           ]
+      <> line
+      <> pretty err
+      <> line
 
 instance Exception BuildPrettyException
 
@@ -834,22 +840,42 @@   | BDDependencyCycleDetected ![PackageName]
   deriving (Eq, Ord, Show)
 
-missingExeError :: String -> Bool -> String -> String
-missingExeError errorCode isSimpleBuildType msg = unlines
-  $ "Error: " <> errorCode
-  : msg
-  : "Possible causes of this issue:"
-  : map ("* " <>) possibleCauses
+missingExeError :: StyleDoc -> Bool -> StyleDoc -> StyleDoc
+missingExeError errorCode isSimpleBuildType msg =
+     errorCode
+  <> line
+  <> msg
+  <> line
+  <> flow "Possible causes of this issue:"
+  <> line
+  <> bulletedList possibleCauses
  where
-  possibleCauses
-    = "No module named \"Main\". The 'main-is' source file should usually \
-      \have a header indicating that it's a 'Main' module."
-    : "A Cabal file that refers to nonexistent other files (e.g. a \
-      \license-file that doesn't exist). Running 'cabal check' may point \
-      \out these issues."
-    : [ "The Setup.hs file is changing the installation target dir."
-      | not isSimpleBuildType
-      ]
+  possibleCauses =
+       [ fillSep
+           [ flow "No module named"
+           , style Shell "Main" <> "."
+           , "The"
+           , style Shell "main-is"
+           , flow "source file should usually have a header indicating that \
+                  \it's a"
+           , style Shell "Main"
+           , "module."
+           ]
+       , fillSep
+           [ flow "A Cabal file that refers to nonexistent other files (e.g. a"
+           , style Shell "license-file"
+           , flow "that doesn't exist). Running"
+           , style Shell "cabal check"
+           , flow "may point out these issues."
+           ]
+       ]
+    <> [ fillSep
+           [ "The"
+           , style File "Setup.hs"
+           , flow "file is changing the installation target directory."
+           ]
+       | not isSimpleBuildType
+       ]
 
 showBuildError ::
      String
src/Stack/Types/BuildOpts.hs view
@@ -18,6 +18,7 @@   , BenchmarkOpts (..)
   , buildOptsHaddockL
   , buildOptsInstallExesL
+  , buildOptsSemaphoreL
   ) where
 
 import           Stack.Prelude
@@ -95,6 +96,9 @@   , progressBar :: !ProgressBarFormat
     -- ^ Format of the progress bar
   , ddumpDir :: !(Maybe Text)
+  , semaphore :: !Bool
+    -- ^ Use Cabal's --semaphore=SEMAPHORE option to build modules of the same
+    -- package in parallel.
   }
   deriving Show
 
@@ -111,6 +115,8 @@   , coverage :: !Bool -- ^ Generate a code coverage report
   , runTests :: !Bool -- ^ Enable running of tests
   , maximumTimeSeconds :: !(Maybe Int) -- ^ test suite timeout in seconds
+  , timeoutGraceSeconds :: !(Maybe Int)
+    -- ^ additional grace period after timeout before force-killing
   , allowStdin :: !Bool -- ^ Whether to allow standard input
   }
   deriving (Eq, Show)
@@ -131,3 +137,7 @@ buildOptsHaddockL :: Lens' BuildOpts Bool
 buildOptsHaddockL =
   lens (.buildHaddocks) (\bopts t -> bopts {buildHaddocks = t})
+
+buildOptsSemaphoreL :: Lens' BuildOpts Bool
+buildOptsSemaphoreL =
+  lens (.semaphore) (\bopts t -> bopts {semaphore = t})
src/Stack/Types/BuildOptsMonoid.hs view
@@ -24,6 +24,7 @@   , buildOptsMonoidTestsL
   , buildOptsMonoidBenchmarksL
   , buildOptsMonoidInstallExesL
+  , buildOptsMonoidSemaphoreL
   , toFirstCabalVerbosity
   , readProgressBarFormat
   ) where
@@ -43,7 +44,8 @@ -- | Build options that may be specified as non-project specific configuration
 -- options under the build key (with certain exceptions) or from the CLI.
 data BuildOptsMonoid = BuildOptsMonoid
-  { trace :: !Any
+  { semaphore :: !FirstFalse
+  , trace :: !Any
     -- ^ Cannot be specified under the build key
   , profile :: !Any
     -- ^ Cannot be specified under the build key
@@ -121,8 +123,10 @@     interleavedOutput <- FirstTrue <$> o ..:? interleavedOutputName
     progressBar <- First <$> o ..:? progressBarName
     ddumpDir <- o ..:? ddumpDirName ..!= mempty
+    semaphore <- FirstFalse <$> o ..:? semaphoreArgName
     pure BuildOptsMonoid
-      { trace
+      { semaphore
+      , trace
       , profile
       , noStrip
       , libProfile
@@ -254,6 +258,9 @@ ddumpDirName :: Text
 ddumpDirName = "ddump-dir"
 
+semaphoreArgName :: Text
+semaphoreArgName = "semaphore"
+
 instance Semigroup BuildOptsMonoid where
   (<>) = mappenddefault
 
@@ -267,6 +274,7 @@   , coverage :: !FirstFalse
   , runTests :: !FirstTrue
   , maximumTimeSeconds :: !(First (Maybe Int))
+  , timeoutGraceSeconds :: !(First (Maybe Int))
   , allowStdin :: !FirstTrue
   }
   deriving (Show, Generic)
@@ -278,6 +286,7 @@     coverage <- FirstFalse <$> o ..:? coverageArgName
     runTests <- FirstTrue . (not <$>) <$> o ..:? noRunTestsArgName
     maximumTimeSeconds <- First <$> o ..:? maximumTimeSecondsArgName
+    timeoutGraceSeconds <- First <$> o ..:? timeoutGraceSecondsArgName
     allowStdin <- FirstTrue <$> o ..:? testsAllowStdinName
     pure TestOptsMonoid
       { rerunTests
@@ -285,6 +294,7 @@       , coverage
       , runTests
       , maximumTimeSeconds
+      , timeoutGraceSeconds
       , allowStdin
       }
 
@@ -303,6 +313,9 @@ maximumTimeSecondsArgName :: Text
 maximumTimeSecondsArgName = "test-suite-timeout"
 
+timeoutGraceSecondsArgName :: Text
+timeoutGraceSecondsArgName = "test-suite-timeout-grace"
+
 testsAllowStdinName :: Text
 testsAllowStdinName = "tests-allow-stdin"
 
@@ -402,6 +415,11 @@ buildOptsMonoidInstallExesL =
   lens (.installExes.firstFalse)
     (\buildMonoid t -> buildMonoid {installExes = FirstFalse t})
+
+buildOptsMonoidSemaphoreL :: Lens' BuildOptsMonoid (Maybe Bool)
+buildOptsMonoidSemaphoreL =
+  lens (.semaphore.firstFalse)
+    (\buildMonoid t -> buildMonoid {semaphore = FirstFalse t})
 
 -- Type representing formats of Stack's progress bar when building.
 data ProgressBarFormat
src/Stack/Types/Config.hs view
@@ -18,6 +18,7 @@     Config (..)
   , HasConfig (..)
   , askLatestSnapshotUrl
+  , askRecentSnapshotsUrl
   , configProjectRoot
   , ghcInstallHook
   -- * Lens helpers
@@ -95,6 +96,8 @@     -- tinfo6)
   , latestSnapshot          :: !Text
     -- ^ URL of a JSON file providing the latest LTS and Nightly snapshots.
+  , recentSnapshots         :: !Text
+    -- ^ URL of a JSON file providing recently-published snapshots.
   , systemGHC               :: !Bool
     -- ^ Should we use the system-installed GHC (on the PATH) if
     -- available? Can be overridden by command line options.
@@ -239,6 +242,10 @@ -- | Get the URL to request the information on the latest snapshots
 askLatestSnapshotUrl :: (MonadReader env m, HasConfig env) => m Text
 askLatestSnapshotUrl = view $ configL . to (.latestSnapshot)
+
+-- | Get the URL to request the information on the recently-published snapshots
+askRecentSnapshotsUrl :: (MonadReader env m, HasConfig env) => m Text
+askRecentSnapshotsUrl = view $ configL . to (.recentSnapshots)
 
 -- | @STACK_ROOT\/hooks\/@
 hooksDir :: HasConfig env => RIO env (Path Abs Dir)
+ src/Stack/Types/ConfigExtra.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE NoImplicitPrelude #-}
+
+{-|
+Module      : Stack.Types.ConfigExtra
+License     : BSD-3-Clause
+-}
+
+module Stack.Types.ConfigExtra
+  ( ConfigExtra (..)
+  ) where
+
+import           Stack.Prelude
+import           Stack.Types.Config ( Config )
+import           Stack.Types.Project ( Project (..) )
+
+-- | A type that represents 'Config' values together with some extra information
+--
+data ConfigExtra = ConfigExtra
+  { config :: !Config
+  , mSnapshot :: !(Maybe RawSnapshotLocation)
+  , project :: !Project
+  , configFile :: !(Either (Path Abs File) (Path Abs File))
+    -- ^ Either (Left) the location of the user-specific global configuration
+    -- file or, in most cases, (Right) the location of the project-level
+    -- coniguration file (stack.yaml, by default).
+    --
+    -- Note: if the STACK_YAML environment variable is used, the location of the
+    -- project-level configuration file may be different from
+    -- projectRootL </> "stack.yaml" if a different file name is used.
+  }
src/Stack/Types/ConfigMonoid.hs view
@@ -21,7 +21,7 @@   , configMonoidSystemGHCName
   ) where
 
-import           Data.Aeson.Types ( Object, Value )
+import           Data.Aeson.Types ( FromJSON (..), Object, Value )
 import           Data.Aeson.WarningParser
                    ( WarningParser, WithJSONWarnings, (..:?), (..!=)
                    , jsonSubWarnings, jsonSubWarningsT, withObjectWarnings
@@ -84,6 +84,8 @@     -- ^ See: 'Stack.Types.Config.prefixTimestamps'
   , latestSnapshot          :: !(First Text)
     -- ^ See: 'Stack.Types.Config.latestSnapshot'
+  , recentSnapshots         :: !(First Text)
+    -- ^ See: 'Stack.Types.Config.recentSnapshots'
   , packageIndex            :: !(First PackageIndexConfig)
     -- ^ See: 'withPantryConfig'
   , systemGHC               :: !(First Bool)
@@ -228,6 +230,43 @@   mempty = memptydefault
   mappend = (<>)
 
+-- | An uninterpreted representation of URLs options. Configurations may be
+-- "cascaded" using mappend (left-biased).
+data UrlsOptsMonoid = UrlsOptsMonoid
+  { latestSnapshot          :: !(First Text)
+    -- ^ See: 'Stack.Types.Config.latestSnapshot'
+  , recentSnapshots         :: !(First Text)
+    -- ^ See: 'Stack.Types.Config.recentSnapshots'
+  }
+  deriving Generic
+
+-- | Decode uninterpreted URLs options from JSON/YAML.
+instance FromJSON (WithJSONWarnings UrlsOptsMonoid) where
+  parseJSON = withObjectWarnings "UrlsOptsMonoid" $ \o -> do
+    latestSnapshot  <- First <$> o ..:? latestSnapshotArgName
+    recentSnapshots <- First <$> o ..:? recentSnapshotsArgName
+    pure UrlsOptsMonoid
+      { latestSnapshot
+      , recentSnapshots
+      }
+
+-- | Left-biased combine URLs options
+instance Semigroup UrlsOptsMonoid where
+  (<>) = mappenddefault
+
+-- | Left-biased combine URLs options
+instance Monoid UrlsOptsMonoid where
+  mempty = memptydefault
+  mappend = (<>)
+
+-- | URLs latest snapshots argument name.
+latestSnapshotArgName :: Text
+latestSnapshotArgName = "latest-snapshot"
+
+-- | URLs recent snapshots argument name.
+recentSnapshotsArgName :: Text
+recentSnapshotsArgName = "recent-snapshots"
+
 parseConfigMonoid ::
      Path Abs Dir
   -> Value
@@ -249,14 +288,10 @@   connectionCount <- First <$> obj ..:? configMonoidConnectionCountName
   hideTHLoading <- FirstTrue <$> obj ..:? configMonoidHideTHLoadingName
   prefixTimestamps <- First <$> obj ..:? configMonoidPrefixTimestampsName
-
-  latestSnapshot <- obj ..:? configMonoidUrlsName >>= \case
-    Nothing -> pure $ First Nothing
-    Just urls -> jsonSubWarnings $ lift $ withObjectWarnings
-      "urls"
-      (\o -> First <$> o ..:? "latest-snapshot" :: WarningParser (First Text))
-      (urls :: Value)
-
+  urlsOpts :: UrlsOptsMonoid <-
+    jsonSubWarnings (obj ..:? configMonoidUrlsName ..!= mempty)
+  let latestSnapshot = urlsOpts.latestSnapshot
+      recentSnapshots = urlsOpts.recentSnapshots
   packageIndex <-
     First <$> jsonSubWarningsT (obj ..:?  configMonoidPackageIndexName)
   systemGHC <- First <$> obj ..:? configMonoidSystemGHCName
@@ -380,6 +415,7 @@     , hideTHLoading
     , prefixTimestamps
     , latestSnapshot
+    , recentSnapshots
     , packageIndex
     , systemGHC
     , installGHC
src/Stack/Types/Dependency.hs view
@@ -43,37 +43,51 @@ -- <https://github.com/commercialhaskell/stack/issues/2195>
 data DepType
   = AsLibrary !DepLibrary
+    -- ^ Dependency is used as a library.
   | AsBuildTool
+    -- ^ Dependency is used only to provide a build tool.
   deriving (Eq, Show)
 
+-- | Type repesenting dependency packages used as a library.
 data DepLibrary = DepLibrary
   { main :: !Bool
+    -- ^ Is the dependency on a main (unnamed) library component?
   , subLib :: Set StackUnqualCompName
+    -- ^ A set (which may be empty) of dependencies on sub-library components.
   }
   deriving (Eq, Show)
 
+-- | A function to yield the set (which may be empty) of dependencies on
+-- sub-library components. Yields 'Nothing' if the dependency is used only to
+-- provide a build tool.
 getDepSublib :: DepValue -> Maybe (Set StackUnqualCompName)
 getDepSublib val = case val.depType of
   AsLibrary libVal -> Just libVal.subLib
   _ -> Nothing
 
+-- | Represents a dependency only on a main (unnamed) library component.
 defaultDepLibrary :: DepLibrary
 defaultDepLibrary = DepLibrary True mempty
 
+-- | Test whether the dependency is being used as a library.
 isDepTypeLibrary :: DepType -> Bool
 isDepTypeLibrary AsLibrary{} = True
 isDepTypeLibrary AsBuildTool = False
 
+-- | Given a 'Cabal.Dependency', yield the Stack equivalent.
 cabalToStackDep :: Cabal.Dependency -> DepValue
 cabalToStackDep (Cabal.Dependency _ verRange libNameSet) =
   DepValue { versionRange = verRange, depType = AsLibrary depLibrary }
  where
   depLibrary = DepLibrary finalHasMain filteredItems
+
   (finalHasMain, filteredItems) = foldr' iterator (False, mempty) libNameSet
-  iterator LMainLibName (_, newLibNameSet) = (True, newLibNameSet)
-  iterator (LSubLibName libName) (hasMain, newLibNameSet) =
-    (hasMain, Set.insert (fromCabalName libName) newLibNameSet)
+   where
+    iterator LMainLibName (_, newLibNameSet) = (True, newLibNameSet)
+    iterator (LSubLibName libName) (hasMain, newLibNameSet) =
+      (hasMain, Set.insert (fromCabalName libName) newLibNameSet)
 
+-- | Given an 'Cabal.ExeDependency', yield the Stack equivalent.
 cabalExeToStackDep :: Cabal.ExeDependency -> DepValue
 cabalExeToStackDep (Cabal.ExeDependency _ _name verRange) =
   DepValue { versionRange = verRange, depType = AsBuildTool }
src/Stack/Types/DotOpts.hs view
@@ -27,6 +27,9 @@     -- fixpoint
   , prune :: !(Set PackageName)
     -- ^ Package names to prune from the graph
+  , reach :: !(Set PackageName)
+    -- ^ If not empty, packages in the pruned graph must be able to reach one or
+    -- more of these packages
   , dotTargets :: [Text]
     -- ^ Stack TARGETs to trace dependencies for
   , flags :: !(Map ApplyCLIFlag (Map FlagName Bool))
src/Stack/Types/MsysEnvironment.hs view
@@ -26,13 +26,10 @@ data MsysEnvironment
   = CLANG32
   | CLANG64
+    -- ^ Stack's default on architecture x86_64.
   | CLANGARM64
   | MINGW32
-    -- ^ Stack's default on architecture i386, and applied if GHC version is
-    -- earlier than GHC 9.6.
   | MINGW64
-    -- ^ Stack's default on architecture x86_64, and applied if GHC version is
-    -- earlier than GHC 9.6.
   | UCRT64
   deriving (Eq, Ord, Show)
 
src/Stack/Types/ProjectConfig.hs view
@@ -24,7 +24,7 @@     -- Instead, use the implicit global.
   | PCNoProject ![RawPackageLocationImmutable]
     -- ^ Use a no project run. This comes from
-    -- 'Stack.Types.StackYamlLocSYLNoProject'.
+    -- 'Stack.Types.StackYamlLoc.SYLNoProject'.
 
 -- | Yields 'True' only if the project configuration information is for the
 -- implicit global project.
+ src/unix/Stack/Build/TestSuiteTimeout.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE NoImplicitPrelude #-}
+
+{-|
+Module      : Stack.Build.TestSuiteTimeout
+Description : OS-specific test suite timeout termination helpers.
+License     : BSD-3-Clause
+-}
+
+module Stack.Build.TestSuiteTimeout
+  ( prepareForEscalation
+  , terminateGracefully
+  , forceKill
+  ) where
+
+import           RIO.Process ( ProcessConfig, setNewSession )
+import qualified RIO.Process as RP ( Process, unsafeProcessHandle )
+import           Stack.Prelude
+import           System.Posix.Signals
+                   ( sigKILL, sigTERM, signalProcess, signalProcessGroup )
+import qualified System.Process as Process
+
+prepareForEscalation :: ProcessConfig stdin stdout stderr -> ProcessConfig stdin stdout stderr
+prepareForEscalation = setNewSession True
+
+terminateGracefully :: RP.Process stdin stdout stderr -> RIO env ()
+terminateGracefully p = do
+  let processHandle = RP.unsafeProcessHandle p
+  mpid <- liftIO $ Process.getPid processHandle
+  forM_ mpid $ \pid -> do
+    -- In a new session, the initial pid is also the process group id.
+    void $ tryAny $ liftIO $ signalProcessGroup sigTERM pid
+    void $ tryAny $ liftIO $ signalProcess sigTERM pid
+
+forceKill :: RP.Process stdin stdout stderr -> RIO env ()
+forceKill p = do
+  let processHandle = RP.unsafeProcessHandle p
+  mpid <- liftIO $ Process.getPid processHandle
+  forM_ mpid $ \pid -> do
+    void $ tryAny $ liftIO $ signalProcessGroup sigKILL pid
+    void $ tryAny $ liftIO $ signalProcess sigKILL pid
+ src/windows/Stack/Build/TestSuiteTimeout.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE NoImplicitPrelude #-}
+
+{-|
+Module      : Stack.Build.TestSuiteTimeout
+Description : OS-specific test suite timeout termination helpers.
+License     : BSD-3-Clause
+-}
+
+module Stack.Build.TestSuiteTimeout
+  ( prepareForEscalation
+  , terminateGracefully
+  , forceKill
+  ) where
+
+import           RIO.Process ( ProcessConfig )
+import qualified RIO.Process as RP ( Process, unsafeProcessHandle )
+import           Stack.Prelude
+import qualified System.Process as Process
+
+prepareForEscalation :: ProcessConfig stdin stdout stderr -> ProcessConfig stdin stdout stderr
+prepareForEscalation = id
+
+terminateGracefully :: RP.Process stdin stdout stderr -> RIO env ()
+terminateGracefully p =
+  void $ tryAny $ liftIO $ Process.terminateProcess $ RP.unsafeProcessHandle p
+
+forceKill :: RP.Process stdin stdout stderr -> RIO env ()
+forceKill p =
+  void $ tryAny $ liftIO $ Process.terminateProcess $ RP.unsafeProcessHandle p
stack.cabal view
@@ -1,6 +1,6 @@ cabal-version:      2.2 name:               stack-version:            3.9.3+version:            3.11.1 license:            BSD-3-Clause license-file:       LICENSE maintainer:@@ -81,6 +81,7 @@     doc/configure/environment_variables.md     doc/configure/global_flags.md     doc/configure/index.md+    doc/configure/yaml/include.md     doc/configure/yaml/index.md     doc/configure/yaml/non-project.md     doc/configure/yaml/project.md@@ -123,6 +124,7 @@     doc/topics/shell_autocompletion.md     doc/topics/snapshot_location.md     doc/topics/Stack_and_VS_Code.md+    doc/topics/stack_environment.md     doc/topics/stack_root.md     doc/topics/stack_work.md     doc/topics/stack_yaml_vs_cabal_package_file.md@@ -348,6 +350,7 @@         Stack.Types.Component         Stack.Types.ComponentUtils         Stack.Types.Config+        Stack.Types.ConfigExtra         Stack.Types.Config.Exception         Stack.Types.ConfigMonoid         Stack.Types.ConfigSetOpts@@ -439,7 +442,7 @@         aeson-warning-parser >=0.1.1,         ansi-terminal >=1.0.2,         array >=0.5.8.0,-        async >=2.2.5,+        async >=2.2.6,         attoparsec >=0.14.4,         base >=4.16.0.0 && <5,         base64-bytestring >=1.2.1.0,@@ -449,18 +452,18 @@         conduit >=1.3.6.1,         conduit-extra >=1.3.8,         containers >=0.7,-        crypton >=1.0.4,+        crypton >=1.0.6,         directory >=1.3.8.5,         echo >=0.1.4,         exceptions >=0.10.9,         extra >=1.8.1,         file-embed >=0.0.16.0,-        filelock >=0.1.1.8,+        filelock >=0.1.1.9,         filepath >=1.5.4.0,         fsnotify >=0.4.1,-        generic-deriving >=1.14.6,+        generic-deriving >=1.14.7,         ghc-boot >=9.10.3,-        hashable >=1.5.0.0,+        hashable >=1.5.1.0,         hi-file-parser >=0.1.8.0,         hpack >=0.36.0,         hpc >=0.7.0.2,@@ -487,6 +490,7 @@         random >=1.2.1.3,         rio >=0.1.22.0 && <0.1.23.0 || >0.1.23.0,         rio-prettyprint >=0.1.8.0,+        semaphore-compat >=1.0.0,         split >=0.2.5,         stm >=2.5.3.1,         tar >=0.6.2.0,@@ -526,6 +530,7 @@     if os(windows)         hs-source-dirs: src/windows/         other-modules:+            Stack.Build.TestSuiteTimeout             Stack.Constants.UsrLibDirs             Stack.Docker.Handlers             System.Posix.User@@ -535,6 +540,7 @@         c-sources:      src/unix/cbits/uname.c         hs-source-dirs: src/unix/         other-modules:+            Stack.Build.TestSuiteTimeout             Stack.Constants.UsrLibDirs             Stack.Docker.Handlers             System.Uname@@ -567,7 +573,7 @@         aeson-warning-parser >=0.1.1,         ansi-terminal >=1.0.2,         array >=0.5.8.0,-        async >=2.2.5,+        async >=2.2.6,         attoparsec >=0.14.4,         base >=4.16.0.0 && <5,         base64-bytestring >=1.2.1.0,@@ -577,18 +583,18 @@         conduit >=1.3.6.1,         conduit-extra >=1.3.8,         containers >=0.7,-        crypton >=1.0.4,+        crypton >=1.0.6,         directory >=1.3.8.5,         echo >=0.1.4,         exceptions >=0.10.9,         extra >=1.8.1,         file-embed >=0.0.16.0,-        filelock >=0.1.1.8,+        filelock >=0.1.1.9,         filepath >=1.5.4.0,         fsnotify >=0.4.1,-        generic-deriving >=1.14.6,+        generic-deriving >=1.14.7,         ghc-boot >=9.10.3,-        hashable >=1.5.0.0,+        hashable >=1.5.1.0,         hi-file-parser >=0.1.8.0,         hpack >=0.36.0,         hpc >=0.7.0.2,@@ -615,6 +621,7 @@         random >=1.2.1.3,         rio >=0.1.22.0 && <0.1.23.0 || >0.1.23.0,         rio-prettyprint >=0.1.8.0,+        semaphore-compat >=1.0.0,         split >=0.2.5,         stack,         stm >=2.5.3.1,@@ -676,7 +683,7 @@         aeson-warning-parser >=0.1.1,         ansi-terminal >=1.0.2,         array >=0.5.8.0,-        async >=2.2.5,+        async >=2.2.6,         attoparsec >=0.14.4,         base >=4.16.0.0 && <5,         base64-bytestring >=1.2.1.0,@@ -686,22 +693,22 @@         conduit >=1.3.6.1,         conduit-extra >=1.3.8,         containers >=0.7,-        crypton >=1.0.4,+        crypton >=1.0.6,         directory >=1.3.8.5,         echo >=0.1.4,         exceptions >=0.10.9,         extra >=1.8.1,         file-embed >=0.0.16.0,-        filelock >=0.1.1.8,+        filelock >=0.1.1.9,         filepath >=1.5.4.0,         fsnotify >=0.4.1,-        generic-deriving >=1.14.6,+        generic-deriving >=1.14.7,         ghc-boot >=9.10.3,-        hashable >=1.5.0.0,+        hashable >=1.5.1.0,         hi-file-parser >=0.1.8.0,         hpack >=0.36.0,         hpc >=0.7.0.2,-        hspec >=2.11.16,+        hspec >=2.11.17,         http-client >=0.7.19,         http-client-tls >=0.3.6.2,         http-conduit >=2.3.9.1,@@ -714,7 +721,7 @@         neat-interpolation >=0.5.1.4,         open-browser >=0.4.0.0,         optparse-applicative >=0.18.1.0,-        optparse-generic >=1.5.2,+        optparse-generic >=1.5.3,         pantry >=0.11.0,         path >=0.9.5,         path-io >=1.8.2,@@ -726,6 +733,7 @@         random >=1.2.1.3,         rio >=0.1.22.0 && <0.1.23.0 || >0.1.23.0,         rio-prettyprint >=0.1.8.0,+        semaphore-compat >=1.0.0,         split >=0.2.5,         stm >=2.5.3.1,         tar >=0.6.2.0,@@ -802,7 +810,7 @@         aeson-warning-parser >=0.1.1,         ansi-terminal >=1.0.2,         array >=0.5.8.0,-        async >=2.2.5,+        async >=2.2.6,         attoparsec >=0.14.4,         base >=4.16.0.0 && <5,         base64-bytestring >=1.2.1.0,@@ -812,22 +820,22 @@         conduit >=1.3.6.1,         conduit-extra >=1.3.8,         containers >=0.7,-        crypton >=1.0.4,+        crypton >=1.0.6,         directory >=1.3.8.5,         echo >=0.1.4,         exceptions >=0.10.9,         extra >=1.8.1,         file-embed >=0.0.16.0,-        filelock >=0.1.1.8,+        filelock >=0.1.1.9,         filepath >=1.5.4.0,         fsnotify >=0.4.1,-        generic-deriving >=1.14.6,+        generic-deriving >=1.14.7,         ghc-boot >=9.10.3,-        hashable >=1.5.0.0,+        hashable >=1.5.1.0,         hi-file-parser >=0.1.8.0,         hpack >=0.36.0,         hpc >=0.7.0.2,-        hspec >=2.11.16,+        hspec >=2.11.17,         http-client >=0.7.19,         http-client-tls >=0.3.6.2,         http-conduit >=2.3.9.1,@@ -852,6 +860,7 @@         raw-strings-qq >=1.1,         rio >=0.1.22.0 && <0.1.23.0 || >0.1.23.0,         rio-prettyprint >=0.1.8.0,+        semaphore-compat >=1.0.0,         split >=0.2.5,         stack,         stm >=2.5.3.1,
stack.yaml view
@@ -1,15 +1,31 @@-snapshot: lts-24.24 # GHC 9.10.3
+snapshot: lts-24.43 # GHC 9.10.3
 
 extra-deps:
-# lts-24.24 specifies Cabal-3.12.1.0
-- Cabal-3.16.0.0@sha256:9972c2bd263168a20bd990962a68d4fd024f50c30a00519a6b942e8871d1bd67,14455
-- Cabal-syntax-3.16.0.0@sha256:6a35036763557301876c5b7a448de4f1cb54fe1e223ff6c4c0c1fdd6df635a65,7509
-# lts-24.24 specifies hpack-0.38.3
-- hpack-0.39.1@sha256:d7378debd96e805760540e3640aeda3a1ebee1d000dac99726ed55c827c81a94,5229
-# lts-24.24 specifies pantry-0.10.1
+# lts-24.43 specifies Cabal-3.12.1.0
+- Cabal-3.16.1.0@sha256:39873317ab895194547c3fd72c91cdb97c800a49b2656920854747ee466627ca,14459
+- Cabal-syntax-3.16.1.0@sha256:17cf54d07d7aa65ea24ba4045912b8a8af065f10e429fd1811d43810b313c504,7778
+# lts-24.43 does not include crypton-asn1-*
+- crypton-asn1-encoding-0.10.0@sha256:45494a1723a047a815d0d620481c1028dca28a4ea5cf2554868687da90753961,2497
+- crypton-asn1-parse-0.10.0@sha256:4a2cfc4980957d1a279ef69137ee5f665c247ccd8bb962812d5b071d543893fb,1359
+- crypton-asn1-types-0.4.1@sha256:02f3ec473011b3da92f7bf738bea19cadf88a6470b25a6cb5042216c7549c912,1326
+# lts-24.43 specifies crypton-x509-1.7.7
+- crypton-x509-1.8.0@sha256:d4822ba8dcb19ee3233fc98152f5afda383ac952770a1d07f1d01168e9fcdbc2,2006
+# lts-24.43 specifies crypton-x509-store-1.6.14
+- crypton-x509-store-1.8.0@sha256:075ba50a3daa0fdbb493481a665926e1ced2135c6b4ed56f97398aa855f0aecb,1674
+# lts-24.43 specifies crypton-x509-system-1.6.8
+- crypton-x509-system-1.8.0@sha256:76bab32c7d9cb3ea356a905f85829c70967fb6f9b4b890f00d67dc54130d45ca,1521
+# lts-24.43 specifies crypton-x509-validation-1.6.14
+- crypton-x509-validation-1.8.0@sha256:63acb2df06f28c3ffdddaf6d9402105b9026796036aa10d7347ae4f7db51c36b,2018
+# lts-24.43 specifies hpack-0.38.3
+- hpack-0.39.6@sha256:3dcd46245401aec2239ff63680880f04817635c7df00ee8ebe2bea9b57393891,5263
+# lts-24.43 specifies pantry-0.10.1
 - pantry-0.11.2@sha256:bc14e75f512deb22e0d9d645e62eb63b319d1732bfed6509491601215ecbd307,7896
-# lts-24.24 specifies persistent-2.17.1.0
-- persistent-2.18.0.0@sha256:baa3e0959cf10bbd1da462efeb61d4f073d0cc924a149325494ba5ce29bc17a4,7096
+# lts-24.43 specifies persistent-2.17.1.0
+- persistent-2.18.1.0@sha256:6a111b26c3e710f1e080a7543cf93766c4cc53ac560dbaa0d4b7ddc98a2f7b1d,7096
+# lts-24.43 does not include time-hourglass
+- time-hourglass-0.3.0@sha256:ee02356fe24919ec43ae17fc0007398c2fd0bbe822833b2d7a9c849537b90580,3114
+# lts-24.43 specifies tls-2.1.8
+- tls-2.2.2@sha256:95f5acd4ce76cbd6bdc46b737370dcbd93c59cf1cd1934a30e55c61c1dc140e9,7283
 
 docker:
   enable: false
tests/integration/lib/StackTest.hs view
@@ -278,7 +278,7 @@ -- the main @stack.yaml@.
 --
 defaultSnapshotArg :: String
-defaultSnapshotArg = "--snapshot=lts-24.24"
+defaultSnapshotArg = "--snapshot=lts-24.43"
 
 -- | Remove a file and ignore any warnings about missing files.
 removeFileIgnore :: HasCallStack => FilePath -> IO ()
tests/unit/Stack/ConfigSpec.hs view
@@ -53,14 +53,15 @@ 
 sampleConfig :: String
 sampleConfig =
-  "snapshot: lts-24.24\n" ++
+  "snapshot: lts-24.43\n" ++
   "packages: ['.']\n"
 
 buildOptsConfig :: String
 buildOptsConfig =
-  "snapshot: lts-24.24\n" ++
+  "snapshot: lts-24.43\n" ++
   "packages: ['.']\n" ++
   "build:\n" ++
+  "  semaphore: true\n" ++
   "  library-profiling: true\n" ++
   "  executable-profiling: true\n" ++
   "  library-stripping: false\n" ++
@@ -89,6 +90,7 @@   "    additional-args: ['-fprof']\n" ++
   "    coverage: true\n" ++
   "    no-run-tests: true\n" ++
+  "    test-suite-timeout-grace: 30\n" ++
   "  bench: true\n" ++
   "  benchmark-opts:\n" ++
   "    benchmark-arguments: -O2\n" ++
@@ -104,7 +106,7 @@ 
 buildOptsHaddockForHackageConfig :: String
 buildOptsHaddockForHackageConfig =
-  "snapshot: lts-24.24\n" ++
+  "snapshot: lts-24.43\n" ++
   "packages: ['.']\n" ++
   "build:\n" ++
   "  haddock: true\n" ++
@@ -120,24 +122,24 @@ 
 hpackConfig :: String
 hpackConfig =
-  "snapshot: lts-24.24\n" ++
+  "snapshot: lts-24.43\n" ++
   "with-hpack: /usr/local/bin/hpack\n" ++
   "packages: ['.']\n"
 
 resolverConfig :: String
 resolverConfig =
-  "resolver: lts-24.24\n" ++
+  "resolver: lts-24.43\n" ++
   "packages: ['.']\n"
 
 snapshotConfig :: String
 snapshotConfig =
-  "snapshot: lts-24.24\n" ++
+  "snapshot: lts-24.43\n" ++
   "packages: ['.']\n"
 
 resolverSnapshotConfig :: String
 resolverSnapshotConfig =
-  "resolver: lts-24.24\n" ++
-  "snapshot: lts-24.24\n" ++
+  "resolver: lts-24.43\n" ++
+  "snapshot: lts-24.43\n" ++
   "packages: ['.']\n"
 
 stackDotYaml :: Path Rel File
@@ -187,11 +189,11 @@ 
     it "parses snapshot using 'resolver'" $ inTempDir $ do
       loadProject resolverConfig $ \project ->
-        project.snapshot `shouldBe` RSLSynonym (LTS 24 24)
+        project.snapshot `shouldBe` RSLSynonym (LTS 24 43)
 
     it "parses snapshot using 'snapshot'" $ inTempDir $ do
       loadProject snapshotConfig $ \project ->
-        project.snapshot `shouldBe` RSLSynonym (LTS 24 24)
+        project.snapshot `shouldBe` RSLSynonym (LTS 24 43)
 
     it "throws if both 'resolver' and 'snapshot' are present" $ inTempDir $ do
       loadProject resolverSnapshotConfig (const (pure ()))
@@ -228,6 +230,7 @@       writeFile (toFilePath stackDotYaml) buildOptsConfig
       loadConfig' $ \config -> liftIO $ do
         let bopts = config.build
+        bopts.semaphore `shouldBe` True
         bopts.libProfile `shouldBe` True
         bopts.exeProfile `shouldBe` True
         bopts.libStrip `shouldBe` False
@@ -257,6 +260,7 @@           , coverage = True
           , runTests = False
           , maximumTimeSeconds = Nothing
+          , timeoutGraceSeconds = Just 30
           , allowStdin = True
           }
         bopts.benchmarks `shouldBe` True