Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions Cabal/src/Distribution/Simple/Program/Db.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module Distribution.Simple.Program.Db
-- ** Query and manipulate the program db
, addKnownProgram
, addKnownPrograms
, clearUnconfiguredPrograms
, prependProgramSearchPath
, prependProgramSearchPathNoLogging
, lookupKnownProgram
Expand Down Expand Up @@ -201,6 +202,14 @@ addKnownProgram prog =
addKnownPrograms :: [Program] -> ProgramDb -> ProgramDb
addKnownPrograms progs progdb = foldl' (flip addKnownProgram) progdb progs

-- | Drop all unconfigured programs from a 'ProgramDb', retaining only
-- configured programs, the search path, and environment overrides.
--
-- This mirrors round-tripping via the @'Binary' 'ProgramDb'@ instance, which
-- drops unconfigured programs.
clearUnconfiguredPrograms :: ProgramDb -> ProgramDb
clearUnconfiguredPrograms progdb = progdb{unconfiguredProgs = Map.empty}

lookupKnownProgram :: String -> ProgramDb -> Maybe Program
lookupKnownProgram name =
fmap (\(p, _, _) -> p) . Map.lookup name . unconfiguredProgs
Expand Down Expand Up @@ -258,8 +267,14 @@ prependProgramSearchPathNoLogging
-> ProgramDb
-> ProgramDb
prependProgramSearchPathNoLogging extraPaths extraEnv db =
let db' = modifyProgramSearchPath (nub . (map ProgramSearchPathDir extraPaths ++)) db
db'' = db'{progOverrideEnv = extraEnv ++ progOverrideEnv db'}
let db' =
if null extraPaths
then db -- skip work if nothing to do
else modifyProgramSearchPath (nub . (map ProgramSearchPathDir extraPaths ++)) db
db'' =
if null extraEnv
then db' -- skip work if nothing to do
else db'{progOverrideEnv = extraEnv ++ progOverrideEnv db'}
in db''

-- | User-specify this path. Basically override any path information
Expand Down
47 changes: 34 additions & 13 deletions cabal-install/src/Distribution/Client/ProjectPlanning.hs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,16 @@ rebuildProjectConfig
$ projectConfigProvenance projectConfig
]

-- | Configure the compiler. This results in a program database that contains
-- the **configured** compiler (which is stored in a cache)
-- and **unconfigured** related programs (cannot be cached, as unconfigured).
--
-- This will be re-run when the compiler or @hc-pkg@ change, and when the
-- program search path or @extra-prog-path@ or @program-locations@ change.
--
-- In the case of @GHC@, we configure @ghc@ and @ghc-pkg@, and provide
-- unconfigured attendant programs such as @hsc2hs@, @haddock@ and toolchain
-- programs such as @ar@, @ld@. See 'Distribution.Simple.GHC.configure'.
configureCompiler
:: Verbosity
-> DistDirLayout
Expand Down Expand Up @@ -564,11 +574,15 @@ configureCompiler
monitorFiles (programsMonitorFiles progdb')
return result

-- Now, **outside** of the caching logic of 'rerunIfChanged', add on
-- auxiliary unconfigured programs to the ProgramDb (e.g. hc-pkg, haddock, ar, ld...).
-- Now, **outside** of the caching logic of 'rerunIfChanged':
--
-- 1. Call 'clearUnconfiguredPrograms' to ensure the consistency between
-- the first run (in-memory) and when deserialising from cache.
-- 2. Add on auxiliary unconfigured programs to the ProgramDb
-- (e.g. hsc2hs, haddock, ar, ld...).
--
-- See Note [Caching the result of configuring the compiler]
finalProgDb <- liftIO $ Cabal.configCompilerProgDb verbosity hc hcProgDb hcPkg
finalProgDb <- liftIO $ Cabal.configCompilerProgDb verbosity hc (clearUnconfiguredPrograms hcProgDb) hcPkg
return (hc, plat, finalProgDb)
where
hcFlavor = flagToMaybe projectConfigHcFlavor
Expand Down Expand Up @@ -597,6 +611,9 @@ To solve this, we cache the ProgramDb containing the compiler (which will be
a configured program, hence properly serialised/deserialised), and then
re-compute any attendant unconfigured programs (such as hc-pkg, haddock or build
tools such as ar, ld) using 'configCompilerProgDb'.
We also call 'clearUnconfiguredPrograms' on the ProgramDb returned by
'rerunIfChanged', so that the first-run (in-memory) result behaves the same as
the cache hit result: always drop unconfigured programs.

Another idea would be to simply eagerly configure all unconfigured programs,
as was originally attempted. But this doesn't work, for a couple of reasons:
Expand Down Expand Up @@ -740,14 +757,14 @@ rebuildInstallPlan
:: ProjectConfig
-> (Compiler, Platform, ProgramDb)
-> Rebuild ()
phaseConfigurePrograms projectConfig (_, _, compilerprogdb) = do
phaseConfigurePrograms projectConfig (_, _, compilerProgDb) = do
-- Users are allowed to specify program locations independently for
-- each package (e.g. to use a particular version of a pre-processor
-- for some packages). However they cannot do this for the compiler
-- itself as that's just not going to work. So we check for this.
liftIO $
checkBadPerPackageCompilerPaths
(configuredPrograms compilerprogdb)
(configuredPrograms compilerProgDb)
(getMapMappend (projectConfigSpecificPackage projectConfig))

-- TODO: [required eventually] find/configure other programs that the
Expand Down Expand Up @@ -891,7 +908,7 @@ rebuildInstallPlan
, projectConfigSpecificPackage
, projectConfigBuildOnly
}
(compiler, platform, progdb)
(compiler, platform, compilerProgDb)
pkgConfigDB
solverPlan
localPackages = do
Expand All @@ -906,13 +923,16 @@ rebuildInstallPlan

defaultInstallDirs <- liftIO $ userInstallDirTemplates compiler
let installDirs = fmap Cabal.fromFlag $ (fmap Flag defaultInstallDirs) <> (projectConfigInstallDirs projectConfigShared)
-- Configure the compiler ProgramDb now (once for the entire project),
-- to avoid repeatedly doing this once per package.
configuredCompilerProgDb <- liftIO $ configureAllKnownPrograms verbosity compilerProgDb
(elaboratedPlan, elaboratedShared) <-
liftIO . runLogProgress verbosity $
elaborateInstallPlan
verbosity
platform
compiler
progdb
configuredCompilerProgDb
pkgConfigDB
distDirLayout
cabalStoreDirLayout
Expand Down Expand Up @@ -1631,6 +1651,7 @@ elaborateInstallPlan
-> Platform
-> Compiler
-> ProgramDb
-- ^ __Configured__ compiler program database (ghc, ghc-pkg, haddock, ld, etc)
-> Maybe PkgConfigDb
-> DistDirLayout
-> StoreDirLayout
Expand All @@ -1647,7 +1668,7 @@ elaborateInstallPlan
verbosity
platform
compiler
compilerprogdb
compilerProgDb
pkgConfigDB
distDirLayout@DistDirLayout{..}
storeDirLayout@StoreDirLayout{storePackageDBStack}
Expand All @@ -1666,7 +1687,7 @@ elaborateInstallPlan
ElaboratedSharedConfig
{ pkgConfigPlatform = platform
, pkgConfigCompiler = compiler
, pkgConfigCompilerProgs = compilerprogdb
, pkgConfigCompilerProgs = compilerProgDb
, pkgConfigReplOptions = mempty
}

Expand Down Expand Up @@ -2365,7 +2386,7 @@ elaborateInstallPlan
okProfDyn = profilingDynamicSupportedOrUnknown compiler
profExe = perPkgOptionFlag pkgid False packageConfigProf

elabBuildOptions = Cabal.adjustBuildOptions compiler compilerprogdb elabBuildOptionsRaw
elabBuildOptions = Cabal.adjustBuildOptions compiler compilerProgDb elabBuildOptionsRaw

( elabProfExeDetail
, elabProfLibDetail
Expand All @@ -2386,7 +2407,7 @@ elaborateInstallPlan
elabProgramPaths =
Map.fromList
[ (programId prog, programPath prog)
| prog <- configuredPrograms compilerprogdb
| prog <- configuredPrograms compilerProgDb
]
<> perPkgOptionMapLast pkgid packageConfigProgramPaths
elabProgramArgs =
Expand All @@ -2408,14 +2429,14 @@ elaborateInstallPlan
(++)
( Map.fromList
[ (programId prog, args)
| prog <- configuredPrograms compilerprogdb
| prog <- configuredPrograms compilerProgDb
, let args = programOverrideArgs $ addHaddockIfDocumentationEnabled prog
, not (null args)
]
)
(perPkgOptionMapMappend pkgid packageConfigProgramArgs)
elabProgramPathExtra = perPkgOptionNubList pkgid packageConfigProgramPathExtra
elabConfiguredPrograms = configuredPrograms compilerprogdb
elabConfiguredPrograms = configuredPrograms compilerProgDb
elabConfigureScriptArgs = perPkgOptionList pkgid packageConfigConfigureArgs
elabExtraLibDirs = perPkgOptionList pkgid packageConfigExtraLibDirs
elabExtraLibDirsStatic = perPkgOptionList pkgid packageConfigExtraLibDirsStatic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,9 +188,10 @@ data ElaboratedSharedConfig = ElaboratedSharedConfig
{ pkgConfigPlatform :: Platform
, pkgConfigCompiler :: Compiler -- TODO: [code cleanup] replace with CompilerInfo
, pkgConfigCompilerProgs :: ProgramDb
-- ^ The programs that the compiler configured (e.g. for GHC, the progs
-- ghc & ghc-pkg). Once constructed, only the 'configuredPrograms' are
-- used.
-- ^ All known programs configured once for the project: the compiler
-- (e.g. ghc & ghc-pkg) plus associated tools (hsc2hs, haddock, hpc,
-- runghc) and toolchain programs (ar, ld, strip). Once constructed,
-- only the 'configuredPrograms' are used.
, pkgConfigReplOptions :: ReplOptions
}
deriving (Show, Generic)
Expand Down
60 changes: 40 additions & 20 deletions cabal-install/src/Distribution/Client/SetupWrapper.hs
Original file line number Diff line number Diff line change
Expand Up @@ -612,8 +612,8 @@ setupWrapper
-> IO (SetupRunnerRes setupSpec)
setupWrapper verbosity options mpkg cmd getCommonFlags getFlags getExtraArgs wrapperArgs = do
let allowInLibrary = case wrapperArgs of
NotInLibrary -> Don'tAllowInLibrary
InLibraryArgs {} -> AllowInLibrary
NotInLibrary -> Don'tAllowInLibrary
ASetup (setup :: Setup kind) <- getSetup verbosity options mpkg allowInLibrary
let version = setupVersion setup
flags <- getFlags version
Expand Down Expand Up @@ -643,21 +643,30 @@ setupWrapper verbosity options mpkg cmd getCommonFlags getFlags getExtraArgs wra
InLibraryArgs libArgs ->
case libArgs of
InLibraryConfigureArgs elabSharedConfig elabReadyPkg -> do
-- See (1)(a) in Note [Constructing the ProgramDb]
-- Start from the pre-configured compiler ProgramDb, augmented
-- with all builtin programs (restored as unconfigured).
-- This ensures:
-- (a) configureAllKnownPrograms inside configureFinal skips
-- compiler programs (already configured at project level),
-- (b) builtin preprocessors like alex and happy are present as
-- unconfigured programs, so configureFinal's
-- configureAllKnownPrograms can find them using the
-- per-package search path (respecting extra-prog-path).
-- See (1) in Note [Constructing the ProgramDb].

-- Apply per-package user-supplied program args/paths.
-- See (2)(a) in Note [Constructing the ProgramDb]
baseProgDb <-
-- Use 'mkProgramDb' to pass user-supplied per-package
-- program options (--PROG-options=...).
mkProgramDb verbHandles flags
(restoreProgramDb builtinPrograms $
pkgConfigCompilerProgs elabSharedConfig)
setupProgDb <-
prependProgramSearchPath verbosity
(useExtraPathEnv options)
(useExtraEnvOverrides options) =<<
mkProgramDb verbHandles flags -- Passes user-supplied arguments to e.g. GHC
Comment thread
sheaf marked this conversation as resolved.
(restoreProgramDb builtinPrograms $
useProgramDb options) -- Recall that 'useProgramDb' is set to 'pkgConfigCompilerProgs'
-- See (2) in Note [Constructing the ProgramDb]
setupProgDb <-
configCompilerProgDb
verbosity
(pkgConfigCompiler elabSharedConfig)
(useExtraEnvOverrides options)
baseProgDb
Nothing -- we use configProgramPaths instead
lbi0 <-
InLibrary.configure
(InLibrary.libraryConfigureInputsFromElabPackage
Expand All @@ -670,7 +679,7 @@ setupWrapper verbosity options mpkg cmd getCommonFlags getFlags getExtraArgs wra
)
flags
let progs0 = LBI.withPrograms lbi0
-- See (1)(b) in Note [Constructing the ProgramDb]
-- See (2)(b) in Note [Constructing the ProgramDb]
progs1 <- updatePathProgDb verbosity progs0
let
lbi =
Expand Down Expand Up @@ -715,7 +724,24 @@ includes the call to 'configCompilerEx'.
To obtain a program database with all the required information, we do a few
things:

(1)
(1) We retrieve the pre-configured compiler program database (typically
containing ghc, ghc-pkg, haddock, and toolchain programs such as ar, ld),
and restore all builtin programs (alex, happy, hsc2hs, ...) as unconfigured
entries on top of it.

This serves two purposes:

(a) The compiler programs (ghc, ghc-pkg, haddock, hsc2hs, ...) that were
already configured at the project level appear in 'configuredProgs'.
The 'configureAllKnownPrograms' call inside the Cabal per-package
'configureFinal' skips them, saving redundant work.

(b) Builtin preprocessors (e.g. alex, happy) are NOT configured at the
project level; restoring them here means the call to
'configureAllKnownPrograms' in 'configureFinal' can find them using
the per-package search path (including 'extra-prog-path').

(2)
(a) When building a package with internal build tools, we must ensure that
these build tools are available in PATH, with appropriate environment
variable overrides for their data directory. To do this, we call
Expand All @@ -724,12 +750,6 @@ things:
(b) Moreover, these programs must be available in the search paths for the
compiler itself, in case they are run at compile-time (e.g. with a Template
Haskell splice). We achieve this using 'updatePathProgDb'.

(2) Given the compiler, we must compute the ProgramDb of programs that are
specified alongside the compiler, such as ghc-pkg, haddock, and toolchain
programs such as ar, ld.

We do this using the function 'configCompilerProgDb'.
-}

-- ------------------------------------------------------------
Expand Down
17 changes: 17 additions & 0 deletions changelog.d/conf-compiler-progs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
synopsis: Pre-configure compiler program database
packages: [Cabal, cabal-install]
prs: 11768
---

The compiler program database, containing `ghc`, `ghc-pkg`, `haddock` and various
toolchain programs (such as `ar`, `ld`) is now configured ahead of time within
`cabal-install`, so that we don't have to re-configure all of those programs
once for every package.

See the pre-existing Note [Caching the result of configuring the compiler] in
Distribution.Client.ProjectPlanning and Note [Constructing the ProgramDb]
in Distribution.Client.SetupWrapper for additional details.

This required a tiny change to `Cabal` to define and expose
`clearUnconfiguredPrograms :: ProgramDb -> ProgramDb` for use in `cabal-install`.
Loading