diff --git a/cabal-install-solver/src/Distribution/Solver/Modular.hs b/cabal-install-solver/src/Distribution/Solver/Modular.hs index 2aac240318f..9111b2d78d0 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular.hs @@ -116,7 +116,7 @@ modularResolver sc (Platform arch os) cinfo iidx sidx pkgConfigDB pprefs pcs pns solve' :: SolverConfig -> CompilerInfo -> Index - -> PkgConfigDb + -> Maybe PkgConfigDb -> (PN -> PackagePreferences) -> Map PN [LabeledPackageConstraint] -> Set PN diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs index e097d3e081c..70b13cbec5c 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Message.hs @@ -279,6 +279,7 @@ showFR :: ConflictSet -> FailReason -> String showFR _ (UnsupportedExtension ext) = " (conflict: requires " ++ showUnsupportedExtension ext ++ ")" showFR _ (UnsupportedLanguage lang) = " (conflict: requires " ++ showUnsupportedLanguage lang ++ ")" showFR _ (MissingPkgconfigPackage pn vr) = " (conflict: pkg-config package " ++ prettyShow pn ++ prettyShow vr ++ ", not found in the pkg-config database)" +showFR _ (MissingPkgconfigProgram pn vr) = " (pkg-config package " ++ prettyShow pn ++ prettyShow vr ++ " is needed but no pkg-config executable was found or querying it failed)" showFR _ (NewPackageDoesNotMatchExistingConstraint d) = " (conflict: " ++ showConflictingDep d ++ ")" showFR _ (ConflictingConstraints d1 d2) = " (conflict: " ++ L.intercalate ", " (L.map showConflictingDep [d1, d2]) ++ ")" showFR _ (NewPackageIsMissingRequiredComponent comp dr) = " (does not contain " ++ showExposedComponent comp ++ ", which is required by " ++ showDependencyReason dr ++ ")" diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Solver.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Solver.hs index 39bd7bf4690..b57f55af1fc 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Solver.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Solver.hs @@ -91,7 +91,7 @@ newtype PruneAfterFirstSuccess = PruneAfterFirstSuccess Bool solve :: SolverConfig -- ^ solver parameters -> CompilerInfo -> Index -- ^ all available packages as an index - -> PkgConfigDb -- ^ available pkg-config pkgs + -> Maybe PkgConfigDb -- ^ available pkg-config pkgs -> (PN -> PackagePreferences) -- ^ preferences -> M.Map PN [LabeledPackageConstraint] -- ^ global constraints -> S.Set PN -- ^ global goals diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Tree.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Tree.hs index 10d372525b1..62eb964dc01 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Tree.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Tree.hs @@ -102,6 +102,7 @@ data POption = POption I (Maybe PackagePath) data FailReason = UnsupportedExtension Extension | UnsupportedLanguage Language | MissingPkgconfigPackage PkgconfigName PkgconfigVersionRange + | MissingPkgconfigProgram PkgconfigName PkgconfigVersionRange | NewPackageDoesNotMatchExistingConstraint ConflictingDep | ConflictingConstraints ConflictingDep ConflictingDep | NewPackageIsMissingRequiredComponent ExposedComponent (DependencyReason QPN) diff --git a/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs b/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs index cbe6282b6d0..4af149b31cf 100644 --- a/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs +++ b/cabal-install-solver/src/Distribution/Solver/Modular/Validate.hs @@ -90,7 +90,7 @@ import Distribution.Types.PkgconfigVersionRange data ValidateState = VS { supportedExt :: Extension -> Bool, supportedLang :: Language -> Bool, - presentPkgs :: PkgconfigName -> PkgconfigVersionRange -> Bool, + presentPkgs :: Maybe (PkgconfigName -> PkgconfigVersionRange -> Bool), index :: Index, -- Saved, scoped, dependencies. Every time 'validate' makes a package choice, @@ -383,7 +383,7 @@ extractNewDeps v b fa sa = go -- or the successfully extended assignment. extend :: (Extension -> Bool) -- ^ is a given extension supported -> (Language -> Bool) -- ^ is a given language supported - -> (PkgconfigName -> PkgconfigVersionRange -> Bool) -- ^ is a given pkg-config requirement satisfiable + -> Maybe (PkgconfigName -> PkgconfigVersionRange -> Bool) -- ^ is a given pkg-config requirement satisfiable -> [LDep QPN] -> PPreAssignment -> Either Conflict PPreAssignment @@ -398,8 +398,10 @@ extend extSupported langSupported pkgPresent newactives ppa = foldM extendSingle if langSupported lang then Right a else Left (dependencyReasonToConflictSet dr, UnsupportedLanguage lang) extendSingle a (LDep dr (Pkg pn vr)) = - if pkgPresent pn vr then Right a - else Left (dependencyReasonToConflictSet dr, MissingPkgconfigPackage pn vr) + case (\f -> f pn vr) <$> pkgPresent of + Just True -> Right a + Just False -> Left (dependencyReasonToConflictSet dr, MissingPkgconfigPackage pn vr) + Nothing -> Left (dependencyReasonToConflictSet dr, MissingPkgconfigProgram pn vr) extendSingle a (LDep dr (Dep dep@(PkgComponent qpn _) ci)) = let mergedDep = M.findWithDefault (MergedDepConstrained []) qpn a in case (\ x -> M.insert qpn x a) <$> merge mergedDep (PkgDep dr dep ci) of @@ -561,7 +563,7 @@ extendRequiredComponents eqpn available = foldM extendSingle -- | Interface. -validateTree :: CompilerInfo -> Index -> PkgConfigDb -> Tree d c -> Tree d c +validateTree :: CompilerInfo -> Index -> Maybe PkgConfigDb -> Tree d c -> Tree d c validateTree cinfo idx pkgConfigDb t = runValidate (validate t) VS { supportedExt = maybe (const True) -- if compiler has no list of extensions, we assume everything is supported (\ es -> let s = S.fromList es in \ x -> S.member x s) @@ -569,7 +571,7 @@ validateTree cinfo idx pkgConfigDb t = runValidate (validate t) VS { , supportedLang = maybe (const True) (flip L.elem) -- use list lookup because language list is small and no Ord instance (compilerInfoLanguages cinfo) - , presentPkgs = pkgConfigPkgIsPresent pkgConfigDb + , presentPkgs = pkgConfigPkgIsPresent <$> pkgConfigDb , index = idx , saved = M.empty , pa = PA M.empty M.empty M.empty diff --git a/cabal-install-solver/src/Distribution/Solver/Types/DependencyResolver.hs b/cabal-install-solver/src/Distribution/Solver/Types/DependencyResolver.hs index e773492ae74..139a6d2b33d 100644 --- a/cabal-install-solver/src/Distribution/Solver/Types/DependencyResolver.hs +++ b/cabal-install-solver/src/Distribution/Solver/Types/DependencyResolver.hs @@ -30,7 +30,7 @@ type DependencyResolver loc = Platform -> CompilerInfo -> InstalledPackageIndex -> PackageIndex (SourcePackage loc) - -> PkgConfigDb + -> Maybe PkgConfigDb -> (PackageName -> PackagePreferences) -> [LabeledPackageConstraint] -> Set PackageName diff --git a/cabal-install-solver/src/Distribution/Solver/Types/PkgConfigDb.hs b/cabal-install-solver/src/Distribution/Solver/Types/PkgConfigDb.hs index 21845eafdec..ccf52ea2c8c 100644 --- a/cabal-install-solver/src/Distribution/Solver/Types/PkgConfigDb.hs +++ b/cabal-install-solver/src/Distribution/Solver/Types/PkgConfigDb.hs @@ -47,15 +47,12 @@ import Distribution.Types.PkgconfigVersionRange import Distribution.Verbosity (Verbosity) -- | The list of packages installed in the system visible to --- @pkg-config@. This is an opaque datatype, to be constructed with --- `readPkgConfigDb` and queried with `pkgConfigPkgPresent`. -data PkgConfigDb = PkgConfigDb (M.Map PkgconfigName (Maybe PkgconfigVersion)) - -- ^ If an entry is `Nothing`, this means that the - -- package seems to be present, but we don't know the - -- exact version (because parsing of the version - -- number failed). - | NoPkgConfigDb - -- ^ For when we could not run pkg-config successfully. +-- @pkg-config@. +-- +-- If an entry is `Nothing`, this means that the package seems to be present, +-- but we don't know the exact version (because parsing of the version number +-- failed). +newtype PkgConfigDb = PkgConfigDb (M.Map PkgconfigName (Maybe PkgconfigVersion)) deriving (Show, Generic, Typeable) instance Binary PkgConfigDb @@ -64,11 +61,11 @@ instance Structured PkgConfigDb -- | Query pkg-config for the list of installed packages, together -- with their versions. Return a `PkgConfigDb` encapsulating this -- information. -readPkgConfigDb :: Verbosity -> ProgramDb -> IO PkgConfigDb +readPkgConfigDb :: Verbosity -> ProgramDb -> IO (Maybe PkgConfigDb) readPkgConfigDb verbosity progdb = handle ioErrorHandler $ do mpkgConfig <- needProgram verbosity pkgConfigProgram progdb case mpkgConfig of - Nothing -> noPkgConfig "Cannot find pkg-config program" + Nothing -> noPkgConfig "cannot find pkg-config program" Just (pkgConfig, _) -> do -- To prevent malformed Unicode in the descriptions from crashing cabal, -- read without interpreting any encoding first. (#9608) @@ -106,7 +103,7 @@ readPkgConfigDb verbosity progdb = handle ioErrorHandler $ do (programInvocation pkgConfig ("--modversion" : pkgNames)) let pkgVersions = lines outs if exitCode == ExitSuccess && length pkgVersions == length pkgNames - then (return . pkgConfigDbFromList . zip pkgNames) pkgVersions + then (return . Just . pkgConfigDbFromList . zip pkgNames) pkgVersions else -- if there's a single broken pc file the above fails, so we fall back -- into calling it individually @@ -116,17 +113,17 @@ readPkgConfigDb verbosity progdb = handle ioErrorHandler $ do -- requested one, we fall back to querying one by one. do info verbosity ("call to pkg-config --modversion on all packages failed. Falling back to querying pkg-config individually on each package") - pkgConfigDbFromList . catMaybes <$> mapM (getIndividualVersion pkgConfig) pkgNames + Just . pkgConfigDbFromList . catMaybes <$> mapM (getIndividualVersion pkgConfig) pkgNames where -- For when pkg-config invocation fails (possibly because of a -- too long command line). noPkgConfig extra = do - info verbosity ("Failed to query pkg-config, Cabal will continue" - ++ " without solving for pkg-config constraints: " + info verbosity ("Warning: Failed to query pkg-config, Cabal will backtrack " + ++ "if a package from pkg-config is requested. Error message: " ++ extra) - return NoPkgConfigDb + return Nothing - ioErrorHandler :: IOException -> IO PkgConfigDb + ioErrorHandler :: IOException -> IO (Maybe PkgConfigDb) ioErrorHandler e = noPkgConfig (show e) getIndividualVersion :: ConfiguredProgram -> String -> IO (Maybe (String, String)) @@ -162,13 +159,6 @@ pkgConfigPkgIsPresent (PkgConfigDb db) pn vr = Nothing -> False -- Package not present in the DB. Just Nothing -> True -- Package present, but version unknown. Just (Just v) -> withinPkgconfigVersionRange v vr --- If we could not read the pkg-config database successfully we fail. --- The plan found by the solver can't be executed later, because pkg-config itself --- is going to be called in the build phase to get the library location for linking --- so even if there is a library, it would need to be passed manual flags anyway. -pkgConfigPkgIsPresent NoPkgConfigDb _ _ = False - - -- | Query the version of a package in the @pkg-config@ database. -- @Nothing@ indicates the package is not in the database, while @@ -176,12 +166,6 @@ pkgConfigPkgIsPresent NoPkgConfigDb _ _ = False -- but its version is not known. pkgConfigDbPkgVersion :: PkgConfigDb -> PkgconfigName -> Maybe (Maybe PkgconfigVersion) pkgConfigDbPkgVersion (PkgConfigDb db) pn = M.lookup pn db --- NB: Since the solver allows solving to succeed if there is --- NoPkgConfigDb, we should report that we *guess* that there --- is a matching pkg-config configuration, but that we just --- don't know about it. -pkgConfigDbPkgVersion NoPkgConfigDb _ = Just Nothing - -- | Query pkg-config for the locations of pkg-config's package files. Use this -- to monitor for changes in the pkg-config DB. diff --git a/cabal-install/src/Distribution/Client/Configure.hs b/cabal-install/src/Distribution/Client/Configure.hs index fc7ea49fe31..0586a362dd2 100644 --- a/cabal-install/src/Distribution/Client/Configure.hs +++ b/cabal-install/src/Distribution/Client/Configure.hs @@ -390,7 +390,7 @@ planLocalPackage -> ConfigExFlags -> InstalledPackageIndex -> SourcePackageDb - -> PkgConfigDb + -> Maybe PkgConfigDb -> IO (Progress String String SolverInstallPlan) planLocalPackage verbosity diff --git a/cabal-install/src/Distribution/Client/Dependency.hs b/cabal-install/src/Distribution/Client/Dependency.hs index 2949b4d21d1..ae731cdc64b 100644 --- a/cabal-install/src/Distribution/Client/Dependency.hs +++ b/cabal-install/src/Distribution/Client/Dependency.hs @@ -781,7 +781,7 @@ runSolver = modularResolver resolveDependencies :: Platform -> CompilerInfo - -> PkgConfigDb + -> Maybe PkgConfigDb -> DepResolverParams -> Progress String String SolverInstallPlan resolveDependencies platform comp pkgConfigDB params = diff --git a/cabal-install/src/Distribution/Client/Fetch.hs b/cabal-install/src/Distribution/Client/Fetch.hs index 54db5ae607b..f09ae4d772e 100644 --- a/cabal-install/src/Distribution/Client/Fetch.hs +++ b/cabal-install/src/Distribution/Client/Fetch.hs @@ -161,7 +161,7 @@ planPackages -> FetchFlags -> InstalledPackageIndex -> SourcePackageDb - -> PkgConfigDb + -> Maybe PkgConfigDb -> [PackageSpecifier UnresolvedSourcePackage] -> IO [UnresolvedSourcePackage] planPackages diff --git a/cabal-install/src/Distribution/Client/Freeze.hs b/cabal-install/src/Distribution/Client/Freeze.hs index 9bc4e3234b5..92f590bb772 100644 --- a/cabal-install/src/Distribution/Client/Freeze.hs +++ b/cabal-install/src/Distribution/Client/Freeze.hs @@ -199,7 +199,7 @@ planPackages -> FreezeFlags -> InstalledPackageIndex -> SourcePackageDb - -> PkgConfigDb + -> Maybe PkgConfigDb -> [PackageSpecifier UnresolvedSourcePackage] -> IO [SolverPlanPackage] planPackages diff --git a/cabal-install/src/Distribution/Client/Install.hs b/cabal-install/src/Distribution/Client/Install.hs index a31e4d2ce62..9cf80d3858c 100644 --- a/cabal-install/src/Distribution/Client/Install.hs +++ b/cabal-install/src/Distribution/Client/Install.hs @@ -381,7 +381,7 @@ install type InstallContext = ( InstalledPackageIndex , SourcePackageDb - , PkgConfigDb + , Maybe PkgConfigDb , [UserTarget] , [PackageSpecifier UnresolvedSourcePackage] , HttpTransport @@ -567,7 +567,7 @@ planPackages -> InstallFlags -> InstalledPackageIndex -> SourcePackageDb - -> PkgConfigDb + -> Maybe PkgConfigDb -> [PackageSpecifier UnresolvedSourcePackage] -> Progress String String SolverInstallPlan planPackages diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs index d0f696be957..0b099dac37c 100644 --- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs +++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs @@ -664,7 +664,7 @@ rebuildInstallPlan -> (Compiler, Platform, ProgramDb) -> [PackageSpecifier UnresolvedSourcePackage] -> InstalledPackageIndex - -> Rebuild (SolverInstallPlan, PkgConfigDb, IndexUtils.TotalIndexState, IndexUtils.ActiveRepos) + -> Rebuild (SolverInstallPlan, Maybe PkgConfigDb, IndexUtils.TotalIndexState, IndexUtils.ActiveRepos) phaseRunSolver projectConfig@ProjectConfig { projectConfigShared @@ -776,7 +776,7 @@ rebuildInstallPlan phaseElaboratePlan :: ProjectConfig -> (Compiler, Platform, ProgramDb) - -> PkgConfigDb + -> Maybe PkgConfigDb -> SolverInstallPlan -> [PackageSpecifier (SourcePackage (PackageLocation loc))] -> Rebuild @@ -1010,7 +1010,7 @@ getSourcePackages verbosity withRepoCtx idxState activeRepos = do $ repos return sourcePkgDbWithTIS -getPkgConfigDb :: Verbosity -> ProgramDb -> Rebuild PkgConfigDb +getPkgConfigDb :: Verbosity -> ProgramDb -> Rebuild (Maybe PkgConfigDb) getPkgConfigDb verbosity progdb = do dirs <- liftIO $ getPkgConfigDbDirs verbosity progdb -- Just monitor the dirs so we'll notice new .pc files. @@ -1210,7 +1210,7 @@ planPackages -> SolverSettings -> InstalledPackageIndex -> SourcePackageDb - -> PkgConfigDb + -> Maybe PkgConfigDb -> [PackageSpecifier UnresolvedSourcePackage] -> Map PackageName (Map OptionalStanza Bool) -> Progress String String SolverInstallPlan @@ -1533,7 +1533,7 @@ elaborateInstallPlan -> Platform -> Compiler -> ProgramDb - -> PkgConfigDb + -> Maybe PkgConfigDb -> DistDirLayout -> StoreDirLayout -> SolverInstallPlan @@ -1937,7 +1937,7 @@ elaborateInstallPlan ++ " from " ++ prettyShow (elabPkgSourceId elab0) ) - (pkgConfigDbPkgVersion pkgConfigDB pn) + (pkgConfigDB >>= \db -> pkgConfigDbPkgVersion db pn) ) | PkgconfigDependency pn _ <- PD.pkgconfigDepends diff --git a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL.hs b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL.hs index 991c5cafa0e..08e1d7fb141 100644 --- a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL.hs +++ b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL.hs @@ -783,7 +783,7 @@ exResolve -> Maybe [Extension] -- List of languages supported by the compiler, or Nothing if unknown. -> Maybe [Language] - -> PC.PkgConfigDb + -> Maybe PC.PkgConfigDb -> [ExamplePkgName] -> Maybe Int -> CountConflicts diff --git a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL/TestCaseUtils.hs b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL/TestCaseUtils.hs index 91ec541f976..afd1419d30c 100644 --- a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL/TestCaseUtils.hs +++ b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/DSL/TestCaseUtils.hs @@ -130,7 +130,7 @@ data SolverTest = SolverTest , testDb :: ExampleDb , testSupportedExts :: Maybe [Extension] , testSupportedLangs :: Maybe [Language] - , testPkgConfigDb :: PkgConfigDb + , testPkgConfigDb :: Maybe PkgConfigDb , testEnableAllTests :: EnableAllTests } @@ -233,7 +233,7 @@ mkTestExtLangPC exts langs mPkgConfigDb db label targets result = , testDb = db , testSupportedExts = exts , testSupportedLangs = langs - , testPkgConfigDb = maybe NoPkgConfigDb pkgConfigDbFromList mPkgConfigDb + , testPkgConfigDb = pkgConfigDbFromList <$> mPkgConfigDb , testEnableAllTests = EnableAllTests False } diff --git a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/QuickCheck.hs b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/QuickCheck.hs index 114db775f21..1a2bc97224f 100644 --- a/cabal-install/tests/UnitTests/Distribution/Solver/Modular/QuickCheck.hs +++ b/cabal-install/tests/UnitTests/Distribution/Solver/Modular/QuickCheck.hs @@ -227,7 +227,7 @@ solve enableBj fineGrainedConflicts reorder countConflicts indep prefOldest goal (unTestDb (testDb test)) Nothing Nothing - (pkgConfigDbFromList []) + (Just $ pkgConfigDbFromList []) (map unPN (testTargets test)) -- The backjump limit prevents individual tests from using -- too much time and memory. diff --git a/cabal-testsuite/PackageTests/ExtraProgPath/setup.out b/cabal-testsuite/PackageTests/ExtraProgPath/setup.out index c3755d7e8c7..01fc2e5cfc0 100644 --- a/cabal-testsuite/PackageTests/ExtraProgPath/setup.out +++ b/cabal-testsuite/PackageTests/ExtraProgPath/setup.out @@ -5,6 +5,6 @@ Resolving dependencies... Error: [Cabal-7107] Could not resolve dependencies: [__0] next goal: CheckExtraProgPath (user goal) -[__0] rejecting: CheckExtraProgPath-0.1 (conflict: pkg-config package zlib-any, not found in the pkg-config database) +[__0] rejecting: CheckExtraProgPath-0.1 (pkg-config package zlib-any is needed but no pkg-config executable was found or querying it failed) [__0] fail (backjumping, conflict set: CheckExtraProgPath) After searching the rest of the dependency tree exhaustively, these were the goals I've had most trouble fulfilling: CheckExtraProgPath (2) diff --git a/changelog.d/pr-10122 b/changelog.d/pr-10122 new file mode 100644 index 00000000000..7e9fbe10d47 --- /dev/null +++ b/changelog.d/pr-10122 @@ -0,0 +1,10 @@ +synopsis: Clarify error message when pkg-config is not found +packages: cabal-install-solver +prs: #10122 + +description: { + +- The error message when pkg-config is not found or querying it fails will no +longer incorrectly claim that the package is missing in the database. + +}