Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add separate cache for getPkgConfigDb #9422

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
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
15 changes: 15 additions & 0 deletions cabal-install/src/Distribution/Client/ProjectConfig.hs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ module Distribution.Client.ProjectConfig
, resolveSolverSettings
, BuildTimeSettings (..)
, resolveBuildTimeSettings
, resolveProgramDb

-- * Checking configuration
, checkBadPerPackageCompilerPaths
Expand Down Expand Up @@ -153,6 +154,12 @@ import Distribution.Simple.InstallDirs
import Distribution.Simple.Program
( ConfiguredProgram (..)
)
import Distribution.Simple.Program.Db
( ProgramDb
, defaultProgramDb
, prependProgramSearchPath
, userSpecifyPaths
)
import Distribution.Simple.Setup
( Flag (Flag)
, flagToList
Expand Down Expand Up @@ -525,6 +532,14 @@ resolveBuildTimeSettings
| isParallelBuild buildSettingNumJobs = False
| otherwise = False

-- | ProgramDb with user specified paths
resolveProgramDb :: Verbosity -> PackageConfig -> IO ProgramDb
resolveProgramDb verbosity packageConfig = do
let extraPath = fromNubList (packageConfigProgramPathExtra packageConfig)
programDb <- prependProgramSearchPath verbosity extraPath [] defaultProgramDb
let paths = Map.toList $ getMapLast (packageConfigProgramPaths packageConfig)
return $ userSpecifyPaths paths programDb

---------------------------------------------
-- Reading and writing project config files
--
Expand Down
76 changes: 40 additions & 36 deletions cabal-install/src/Distribution/Client/ProjectPlanning.hs
Original file line number Diff line number Diff line change
Expand Up @@ -461,11 +461,7 @@ configureCompiler
, projectConfigHcPath
, projectConfigHcPkg
}
, projectConfigLocalPackages =
PackageConfig
{ packageConfigProgramPaths
, packageConfigProgramPathExtra
}
, projectConfigLocalPackages
} = do
let fileMonitorCompiler = newFileMonitor $ distProjectCacheFile "compiler"

Expand All @@ -477,35 +473,26 @@ configureCompiler
, hcPath
, hcPkg
, progsearchpath
, packageConfigProgramPaths
, packageConfigProgramPathExtra
, projectConfigLocalPackages
)
$ do
liftIO $ info verbosity "Compiler settings changed, reconfiguring..."
let extraPath = fromNubList packageConfigProgramPathExtra
progdb <- liftIO $ prependProgramSearchPath verbosity extraPath [] defaultProgramDb
let progdb' = userSpecifyPaths (Map.toList (getMapLast packageConfigProgramPaths)) progdb
(comp, plat, progdb'') <-
liftIO $
Cabal.configCompilerEx
hcFlavor
hcPath
hcPkg
progdb'
verbosity
progdb <- liftIO $ resolveProgramDb verbosity projectConfigLocalPackages
(comp, plat, progdb') <-
liftIO $ Cabal.configCompilerEx hcFlavor hcPath hcPkg progdb verbosity

-- Note that we added the user-supplied program locations and args
-- for /all/ programs, not just those for the compiler prog and
-- compiler-related utils. In principle we don't know which programs
-- the compiler will configure (and it does vary between compilers).
-- We do know however that the compiler will only configure the
-- programs it cares about, and those are the ones we monitor here.
monitorFiles (programsMonitorFiles progdb'')
monitorFiles (programsMonitorFiles progdb')

-- Configure the unconfigured programs in the program database,
-- as we can't serialise unconfigured programs.
-- See also #2241 and #9840.
finalProgDb <- liftIO $ configureAllKnownPrograms verbosity progdb''
finalProgDb <- liftIO $ configureAllKnownPrograms verbosity progdb'

return (comp, plat, finalProgDb)
where
Expand Down Expand Up @@ -557,9 +544,14 @@ rebuildInstallPlan
{ cabalStoreDirLayout
} = \projectConfig localPackages mbInstalledPackages ->
runRebuild distProjectRootDirectory $ do
progsearchpath <- liftIO $ getSystemSearchPath
progsearchpath <- liftIO getSystemSearchPath
let projectConfigMonitored = projectConfig{projectConfigBuildOnly = mempty}

progdb <- liftIO $ resolveProgramDb verbosity (projectConfigLocalPackages projectConfig)
monitorFiles (programsMonitorFiles progdb)

pkgConfigDB <- getPkgConfigDb verbosity distDirLayout progdb

-- The overall improved plan is cached
rerunIfChanged
verbosity
Expand All @@ -580,15 +572,15 @@ rebuildInstallPlan
$ do
compilerEtc <- phaseConfigureCompiler projectConfig
_ <- phaseConfigurePrograms projectConfig compilerEtc
(solverPlan, pkgConfigDB, totalIndexState, activeRepos) <-
(solverPlan, totalIndexState, activeRepos) <-
phaseRunSolver
projectConfig
compilerEtc
pkgConfigDB
localPackages
(fromMaybe mempty mbInstalledPackages)
( elaboratedPlan
, elaboratedShared
) <-

(elaboratedPlan, elaboratedShared) <-
phaseElaboratePlan
projectConfig
compilerEtc
Expand Down Expand Up @@ -622,7 +614,8 @@ rebuildInstallPlan
phaseConfigureCompiler
:: ProjectConfig
-> Rebuild (Compiler, Platform, ProgramDb)
phaseConfigureCompiler = configureCompiler verbosity distDirLayout
phaseConfigureCompiler projectConfig =
configureCompiler verbosity distDirLayout projectConfig

-- Configuring other programs.
--
Expand Down Expand Up @@ -662,15 +655,17 @@ rebuildInstallPlan
phaseRunSolver
:: ProjectConfig
-> (Compiler, Platform, ProgramDb)
-> PkgConfigDb
-> [PackageSpecifier UnresolvedSourcePackage]
-> InstalledPackageIndex
-> Rebuild (SolverInstallPlan, PkgConfigDb, IndexUtils.TotalIndexState, IndexUtils.ActiveRepos)
-> Rebuild (SolverInstallPlan, IndexUtils.TotalIndexState, IndexUtils.ActiveRepos)
phaseRunSolver
projectConfig@ProjectConfig
{ projectConfigShared
, projectConfigBuildOnly
}
(compiler, platform, progdb)
pkgConfigDB
localPackages
installedPackages =
rerunIfChanged
Expand All @@ -697,7 +692,6 @@ rebuildInstallPlan
withRepoCtx
(solverSettingIndexState solverSettings)
(solverSettingActiveRepos solverSettings)
pkgConfigDB <- getPkgConfigDb verbosity progdb

-- TODO: [code cleanup] it'd be better if the Compiler contained the
-- ConfiguredPrograms that it needs, rather than relying on the progdb
Expand All @@ -722,7 +716,7 @@ rebuildInstallPlan
Left msg -> do
reportPlanningFailure projectConfig compiler platform localPackages
dieWithException verbosity $ PhaseRunSolverErr msg
Right plan -> return (plan, pkgConfigDB, tis, ar)
Right plan -> return (plan, tis, ar)
where
corePackageDbs :: [PackageDB]
corePackageDbs =
Expand Down Expand Up @@ -1010,13 +1004,23 @@ getSourcePackages verbosity withRepoCtx idxState activeRepos = do
$ repos
return sourcePkgDbWithTIS

getPkgConfigDb :: Verbosity -> ProgramDb -> Rebuild PkgConfigDb
getPkgConfigDb verbosity progdb = do
dirs <- liftIO $ getPkgConfigDbDirs verbosity progdb
-- Just monitor the dirs so we'll notice new .pc files.
-- Alternatively we could monitor all the .pc files too.
traverse_ monitorDirectoryStatus dirs
liftIO $ readPkgConfigDb verbosity progdb
getPkgConfigDb :: Verbosity -> DistDirLayout -> ProgramDb -> Rebuild PkgConfigDb
getPkgConfigDb verbosity distDirLayout progdb = do
mpkgConfig <- liftIO $ needProgram verbosity pkgConfigProgram progdb
case mpkgConfig of
Nothing -> do
liftIO $ info verbosity "Cannot find pkg-config program. Cabal will continue without solving for pkg-config constraints."
return NoPkgConfigDb
Just (pkgConfig, progdb') -> do
dirs <- liftIO $ getPkgConfigDbDirs verbosity progdb'
rerunIfChanged verbosity fileMonitorPkgConfigDb (pkgConfig, dirs) $ do
-- By monitoring the dirs, we'll notice new .pc files. We do not monitor changes in the .pc files themselves.
traverse_ monitorDirectoryStatus dirs
liftIO $ do
info verbosity "Querying pkg-config database..."
readPkgConfigDb verbosity progdb'
where
fileMonitorPkgConfigDb = newFileMonitor $ distProjectCacheFile distDirLayout "pkg-config-db"

-- | Select the config values to monitor for changes package source hashes.
packageLocationsSignature
Expand Down
2 changes: 2 additions & 0 deletions cabal-testsuite/PackageTests/ExtraProgPath/setup.out
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# cabal v2-build
Warning: cannot determine version of <ROOT>/pkg-config :
""
Warning: cannot determine version of <ROOT>/pkg-config :
""
Resolving dependencies...
Error: [Cabal-7107]
Could not resolve dependencies:
Expand Down
1 change: 1 addition & 0 deletions cabal-testsuite/PackageTests/MonitorPkgConfig/P.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module P where
6 changes: 6 additions & 0 deletions cabal-testsuite/PackageTests/MonitorPkgConfig/cabal.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# cabal v2-build
# cabal v2-build
# cabal v2-build
# cabal v2-build
# cabal v2-build
# cabal v2-build
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
35 changes: 35 additions & 0 deletions cabal-testsuite/PackageTests/MonitorPkgConfig/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Distribution.Compat.Environment (setEnv)
import System.Directory (copyFile, createDirectoryIfMissing, removeDirectoryRecursive)
import Test.Cabal.Prelude

main = cabalTest $ do
env <- getTestEnv

cabal' "v2-build" ["--dry-run", "p", "-v2"]
>>= assertOutputContains "Querying pkg-config database..."

cabal' "v2-build" ["--dry-run", "p", "-v2"]
>>= assertOutputDoesNotContain "Querying pkg-config database..."

-- Check that changing PKG_CONFIG_PATH invalidates the cache

let pkgConfigPath = testWorkDir env </> "pkgconfig"
liftIO $ do
createDirectoryIfMissing True pkgConfigPath
setEnv "PKG_CONFIG_PATH" pkgConfigPath

cabal' "v2-build" ["--dry-run", "p", "-v2"]
>>= assertOutputContains "Querying pkg-config database..."

cabal' "v2-build" ["--dry-run", "p", "-v2"]
>>= assertOutputDoesNotContain "Querying pkg-config database..."

-- Check that changing a file in PKG_CONFIG_PATH invalidates the cache

liftIO $ copyFile (testCurrentDir env </> "test.pc") (pkgConfigPath </> "test.pc")

cabal' "v2-build" ["--dry-run", "p", "-v2"]
>>= assertOutputContains "Querying pkg-config database..."

cabal' "v2-build" ["--dry-run", "p", "-v2"]
>>= assertOutputDoesNotContain "Querying pkg-config database..."
12 changes: 12 additions & 0 deletions cabal-testsuite/PackageTests/MonitorPkgConfig/p.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: p
version: 1.0
license: BSD3
author: Somebody
maintainer: some@email.address
build-type: Simple
cabal-version: >=1.10

library
exposed-modules: P
build-depends: base
default-language: Haskell2010
3 changes: 3 additions & 0 deletions cabal-testsuite/PackageTests/MonitorPkgConfig/test.pc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Name: test
Version: 0
Description: a test .pc file
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ testBody = withProjectFile "cabal.project" $ withRemoteRepo "repo" $ do
. resultOutput
<$> recordMode DoNotRecord (cabal' "update" [])
-- update golden output with actual timestamp
shell "cp" ["cabal.out.in", "cabal.out"]
shell "sed" ["-i''", "-e", "s/REPLACEME/" <> output <> "/g", "cabal.out"]
shell "sed" ["-e", "s/REPLACEME/" <> output <> "/g; w cabal.out", "cabal.out.in"]
-- This shall fail with an error message as specified in `cabal.out`
fails $ cabal "build" ["--index-state=4000-01-01T00:00:00Z", "fake-pkg"]
-- This shall fail by not finding the package, what indicates that it
Expand Down
12 changes: 12 additions & 0 deletions changelog.d/pr-9422
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
synopsis: Add separate cache for getPkgConfigDb
packages: cabal-install
prs: #9422
issues: #8930

description: {
Querying pkg-config for the version of every module can be a very expensive
operation on some systems. This change adds a separate, per-project, cache for
pkgConfigDB; reducing the cost from "every plan change" to "every pkg-config-db
change per project". A notice is also presented to the user when refreshing the
packagedb.
}
Loading