Skip to content

Commit

Permalink
Track build artifacts in installed packages.
Browse files Browse the repository at this point in the history
1) Extend the InstalledPackageInfo record with 5 records involving
configuration flags that affect which build artifacts (dynamic and static
files) are provided.  (This record corresponds to the ‘.conf’ files in
package-db directories, and Cabal-syntax provides an interface to this record.
Cabal-syntax is used as a dependency by ‘ghc-pkg’ and ‘cabal-install’, and old
Cabal-syntax implementations may produce an ‘Unknown field’ warning when used
with new ‘.conf’ files.)
2) Add a step to the validation phase of the modular resolver that also rules
out pre-installed package options that would introduce a missing artifact
condition, so that alternatives if available can be chosen instead, rather than
producing assignments for a build plan that would fail with ‘files missing’
(e.g. ‘….hi’ or ‘….dyn_hi’).
  • Loading branch information
bairyn committed Dec 2, 2022
1 parent 44cc455 commit c6d6397
Show file tree
Hide file tree
Showing 29 changed files with 503 additions and 39 deletions.
15 changes: 13 additions & 2 deletions Cabal-syntax/src/Distribution/Types/InstalledPackageInfo.hs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,13 @@ data InstalledPackageInfo
frameworks :: [String],
haddockInterfaces :: [FilePath],
haddockHTMLs :: [FilePath],
pkgRoot :: Maybe FilePath
pkgRoot :: Maybe FilePath,
-- Artifacts included in this package:
pkgVanillaLib :: Bool,
pkgSharedLib :: Bool,
pkgDynExe :: Bool,
pkgProfLib :: Bool,
pkgProfExe :: Bool
}
deriving (Eq, Generic, Typeable, Read, Show)

Expand Down Expand Up @@ -173,5 +179,10 @@ emptyInstalledPackageInfo
haddockInterfaces = [],
haddockHTMLs = [],
pkgRoot = Nothing,
libVisibility = LibraryVisibilityPrivate
libVisibility = LibraryVisibilityPrivate,
pkgVanillaLib = True,
pkgSharedLib = True,
pkgDynExe = True,
pkgProfLib = True,
pkgProfExe = True
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ ipiFieldGrammar = mkInstalledPackageInfo
<@> monoidalFieldAla "haddock-interfaces" (alaList' FSep FilePathNT) L.haddockInterfaces
<@> monoidalFieldAla "haddock-html" (alaList' FSep FilePathNT) L.haddockHTMLs
<@> optionalFieldAla "pkgroot" FilePathNT L.pkgRoot
<@> booleanFieldDef "pkg-vanilla-lib" L.pkgVanillaLib True
<@> booleanFieldDef "pkg-shared-lib" L.pkgSharedLib True
<@> booleanFieldDef "pkg-dyn-exe" L.pkgDynExe True
<@> booleanFieldDef "pkg-prof-lib" L.pkgProfLib True
<@> booleanFieldDef "pkg-prof-exe" L.pkgProfExe True
where
mkInstalledPackageInfo _ Basic {..} = InstalledPackageInfo
-- _basicPkgName is not used
Expand Down
20 changes: 20 additions & 0 deletions Cabal-syntax/src/Distribution/Types/InstalledPackageInfo/Lens.hs
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,23 @@ libVisibility :: Lens' InstalledPackageInfo LibraryVisibility
libVisibility f s = fmap (\x -> s { T.libVisibility = x }) (f (T.libVisibility s))
{-# INLINE libVisibility #-}

pkgVanillaLib :: Lens' InstalledPackageInfo Bool
pkgVanillaLib f s = fmap (\x -> s { T.pkgVanillaLib = x }) (f (T.pkgVanillaLib s))
{-# INLINE pkgVanillaLib #-}

pkgSharedLib :: Lens' InstalledPackageInfo Bool
pkgSharedLib f s = fmap (\x -> s { T.pkgSharedLib = x }) (f (T.pkgSharedLib s))
{-# INLINE pkgSharedLib #-}

pkgDynExe :: Lens' InstalledPackageInfo Bool
pkgDynExe f s = fmap (\x -> s { T.pkgDynExe = x }) (f (T.pkgDynExe s))
{-# INLINE pkgDynExe #-}

pkgProfLib :: Lens' InstalledPackageInfo Bool
pkgProfLib f s = fmap (\x -> s { T.pkgProfLib = x }) (f (T.pkgProfLib s))
{-# INLINE pkgProfLib #-}

pkgProfExe :: Lens' InstalledPackageInfo Bool
pkgProfExe f s = fmap (\x -> s { T.pkgProfExe = x }) (f (T.pkgProfExe s))
{-# INLINE pkgProfExe #-}

7 changes: 6 additions & 1 deletion Cabal/src/Distribution/Simple/Register.hs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,12 @@ generalInstalledPackageInfo adjustRelIncDirs pkg abi_hash lib lbi clbi installDi
IPI.haddockInterfaces = [haddockdir installDirs </> haddockName pkg],
IPI.haddockHTMLs = [htmldir installDirs],
IPI.pkgRoot = Nothing,
IPI.libVisibility = libVisibility lib
IPI.libVisibility = libVisibility lib,
IPI.pkgVanillaLib = withVanillaLib lbi,
IPI.pkgSharedLib = withProfLib lbi,
IPI.pkgDynExe = withSharedLib lbi,
IPI.pkgProfLib = withStaticLib lbi,
IPI.pkgProfExe = withDynExe lbi
}
where
ghc84 = case compilerId $ compiler lbi of
Expand Down
1 change: 1 addition & 0 deletions cabal-install-solver/cabal-install-solver.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ library
Distribution.Solver.Modular.Var
Distribution.Solver.Modular.Version
Distribution.Solver.Modular.WeightedPSQ
Distribution.Solver.Types.ArtifactSelection
Distribution.Solver.Types.ComponentDeps
Distribution.Solver.Types.ConstraintSource
Distribution.Solver.Types.DependencyResolver
Expand Down
2 changes: 1 addition & 1 deletion cabal-install-solver/src/Distribution/Solver/Modular.hs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ modularResolver sc (Platform arch os) cinfo iidx sidx pkgConfigDB pprefs pcs pns
solve' sc cinfo idx pkgConfigDB pprefs gcs pns
where
-- Indices have to be converted into solver-specific uniform index.
idx = convPIs os arch cinfo gcs (shadowPkgs sc) (strongFlags sc) (solveExecutables sc) iidx sidx
idx = convPIs os arch cinfo gcs (shadowPkgs sc) (strongFlags sc) (solveExecutables sc) (sourceArtifacts sc) iidx sidx
-- Constraints have to be converted into a finite map indexed by PN.
gcs = M.fromListWith (++) (map pair pcs)
where
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ addChildren bs@(BS { rdeps = rdm, next = OneGoal (StanzaGoal qsn@(SN qpn _) t gr
-- and furthermore we update the set of goals.
--
-- TODO: We could inline this above.
addChildren bs@(BS { next = Instance qpn (PInfo fdeps _ fdefs _) }) =
addChildren bs@(BS { next = Instance qpn (PInfo fdeps _ fdefs _ _) }) =
addChildren ((scopedExtendOpen qpn fdeps fdefs bs)
{ next = Goals })

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ exploreLog mbj enableBj fineGrainedConflicts (CountConflicts countConflicts) idx
-- to be merged with the previous one.
couldResolveConflicts :: QPN -> POption -> S.Set CS.Conflict -> Maybe ConflictSet
couldResolveConflicts currentQPN@(Q _ pn) (POption i@(I v _) _) conflicts =
let (PInfo deps _ _ _) = idx M.! pn M.! i
let (PInfo deps _ _ _ _) = idx M.! pn M.! i
qdeps = qualifyDeps (defaultQualifyOptions idx) currentQPN deps

couldBeResolved :: CS.Conflict -> Maybe ConflictSet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Distribution.Solver.Modular.Dependency
import Distribution.Solver.Modular.Flag
import Distribution.Solver.Modular.Package
import Distribution.Solver.Modular.Tree
import Distribution.Solver.Types.ArtifactSelection

-- | An index contains information about package instances. This is a nested
-- dictionary. Package names are mapped to instances, which in turn is mapped
Expand All @@ -32,10 +33,13 @@ type Index = Map PN (Map I PInfo)
-- globally, for reasons external to the solver. We currently use this
-- for shadowing which essentially is a GHC limitation, and for
-- installed packages that are broken.
--
-- Additionally, track build artifacts provided and build artifacts required.
data PInfo = PInfo (FlaggedDeps PN)
(Map ExposedComponent ComponentInfo)
FlagInfo
(Maybe FailReason)
(ArtifactSelection, ArtifactSelection)

-- | Info associated with each library and executable in a package instance.
data ComponentInfo = ComponentInfo {
Expand Down Expand Up @@ -64,7 +68,7 @@ defaultQualifyOptions idx = QO {
| -- Find all versions of base ..
Just is <- [M.lookup base idx]
-- .. which are installed ..
, (I _ver (Inst _), PInfo deps _comps _flagNfo _fr) <- M.toList is
, (I _ver (Inst _), PInfo deps _comps _flagNfo _fr _arts) <- M.toList is
-- .. and flatten all their dependencies ..
, (LDep _ (Dep (PkgComponent dep _) _ci), _comp) <- flattenFlaggedDeps deps
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import Distribution.PackageDescription.Configuration
import qualified Distribution.Simple.PackageIndex as SI
import Distribution.System

import Distribution.Solver.Types.ArtifactSelection
( ArtifactSelection(..), allArtifacts, staticOutsOnly, dynOutsOnly, noOuts )
import Distribution.Solver.Types.ComponentDeps
( Component(..), componentNameToComponent )
import Distribution.Solver.Types.Flag
Expand Down Expand Up @@ -55,11 +57,12 @@ import Distribution.Solver.Modular.Version
-- explicitly requested.
convPIs :: OS -> Arch -> CompilerInfo -> Map PN [LabeledPackageConstraint]
-> ShadowPkgs -> StrongFlags -> SolveExecutables
-> Maybe (ArtifactSelection, ArtifactSelection)
-> SI.InstalledPackageIndex -> CI.PackageIndex (SourcePackage loc)
-> Index
convPIs os arch comp constraints sip strfl solveExes iidx sidx =
convPIs os arch comp constraints sip strfl solveExes srcArts iidx sidx =
mkIndex $
convIPI' sip iidx ++ convSPI' os arch comp constraints strfl solveExes sidx
convIPI' sip iidx ++ convSPI' os arch comp constraints strfl solveExes srcArts sidx

-- | Convert a Cabal installed package index to the simpler,
-- more uniform index format of the solver.
Expand All @@ -75,8 +78,8 @@ convIPI' (ShadowPkgs sip) idx =
where

-- shadowing is recorded in the package info
shadow (pn, i, PInfo fdeps comps fds _)
| sip = (pn, i, PInfo fdeps comps fds (Just Shadowed))
shadow (pn, i, PInfo fdeps comps fds _ arts)
| sip = (pn, i, PInfo fdeps comps fds (Just Shadowed) arts)
shadow x = x

-- | Extract/recover the package ID from an installed package info, and convert it to a solver's I.
Expand All @@ -90,8 +93,8 @@ convId ipi = (pn, I ver $ Inst $ IPI.installedUnitId ipi)
convIP :: SI.InstalledPackageIndex -> IPI.InstalledPackageInfo -> (PN, I, PInfo)
convIP idx ipi =
case traverse (convIPId (DependencyReason pn M.empty S.empty) comp idx) (IPI.depends ipi) of
Left u -> (pn, i, PInfo [] M.empty M.empty (Just (Broken u)))
Right fds -> (pn, i, PInfo fds components M.empty Nothing)
Left u -> (pn, i, PInfo [] M.empty M.empty (Just (Broken u)) mempty)
Right fds -> (pn, i, PInfo fds components M.empty Nothing (ipiToAS ipi))
where
-- TODO: Handle sub-libraries and visibility.
components =
Expand Down Expand Up @@ -151,31 +154,46 @@ convIPId dr comp idx ipid =
-- NB: something we pick up from the
-- InstalledPackageIndex is NEVER an executable

-- | Extract the 'ArtifactSelection's representing which artifacts are
-- available in this installed package and which artifacts this installed
-- package requires. Assume both are the same.
ipiToAS :: IPI.InstalledPackageInfo -> (ArtifactSelection, ArtifactSelection)
ipiToAS ipi = (\x -> (x, x)) $ mconcat [statics, dynamics]
where
statics :: ArtifactSelection
statics = if any ($ ipi) [IPI.pkgVanillaLib] then staticOutsOnly else mempty
dynamics :: ArtifactSelection
dynamics = if any ($ ipi) [IPI.pkgSharedLib, IPI.pkgDynExe] then dynOutsOnly else mempty

-- | Convert a cabal-install source package index to the simpler,
-- more uniform index format of the solver.
convSPI' :: OS -> Arch -> CompilerInfo -> Map PN [LabeledPackageConstraint]
-> StrongFlags -> SolveExecutables
-> StrongFlags -> SolveExecutables -> Maybe (ArtifactSelection, ArtifactSelection)
-> CI.PackageIndex (SourcePackage loc) -> [(PN, I, PInfo)]
convSPI' os arch cinfo constraints strfl solveExes =
L.map (convSP os arch cinfo constraints strfl solveExes) . CI.allPackages
convSPI' os arch cinfo constraints strfl solveExes srcArts =
L.map (convSP os arch cinfo constraints strfl solveExes srcArts) . CI.allPackages

-- | Convert a single source package into the solver-specific format.
convSP :: OS -> Arch -> CompilerInfo -> Map PN [LabeledPackageConstraint]
-> StrongFlags -> SolveExecutables -> SourcePackage loc -> (PN, I, PInfo)
convSP os arch cinfo constraints strfl solveExes (SourcePackage (PackageIdentifier pn pv) gpd _ _pl) =
-> StrongFlags -> SolveExecutables -> Maybe (ArtifactSelection, ArtifactSelection)
-> SourcePackage loc
-> (PN, I, PInfo)
convSP os arch cinfo constraints strfl solveExes srcArts (SourcePackage (PackageIdentifier pn pv) gpd _ _pl) =
let i = I pv InRepo
pkgConstraints = fromMaybe [] $ M.lookup pn constraints
in (pn, i, convGPD os arch cinfo pkgConstraints strfl solveExes pn gpd)
in (pn, i, convGPD os arch cinfo pkgConstraints strfl solveExes srcArts pn gpd)

-- We do not use 'flattenPackageDescription' or 'finalizePD'
-- from 'Distribution.PackageDescription.Configuration' here, because we
-- want to keep the condition tree, but simplify much of the test.

-- | Convert a generic package description to a solver-specific 'PInfo'.
convGPD :: OS -> Arch -> CompilerInfo -> [LabeledPackageConstraint]
-> StrongFlags -> SolveExecutables -> PN -> GenericPackageDescription
-> StrongFlags -> SolveExecutables
-> Maybe (ArtifactSelection, ArtifactSelection)
-> PN -> GenericPackageDescription
-> PInfo
convGPD os arch cinfo constraints strfl solveExes pn
convGPD os arch cinfo constraints strfl solveExes srcArts pn
(GenericPackageDescription pkg scannedVersion flags mlib sub_libs flibs exes tests benchs) =
let
fds = flagInfo strfl flags
Expand Down Expand Up @@ -238,7 +256,7 @@ convGPD os arch cinfo constraints strfl solveExes pn
isPrivate LibraryVisibilityPrivate = True
isPrivate LibraryVisibilityPublic = False

in PInfo flagged_deps components fds fr
in PInfo flagged_deps components fds fr (fromMaybe (allArtifacts, noOuts) srcArts)

-- | Applies the given predicate (for example, testing buildability or
-- visibility) to the given component and environment. Values are combined with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ validateLinking index = (`runReader` initVS) . go
goP :: QPN -> POption -> Validate (Tree d c) -> Validate (Tree d c)
goP qpn@(Q _pp pn) opt@(POption i _) r = do
vs <- ask
let PInfo deps _ _ _ = vsIndex vs ! pn ! i
qdeps = qualifyDeps (vsQualifyOptions vs) qpn deps
newSaved = M.insert qpn qdeps (vsSaved vs)
let PInfo deps _ _ _ _ = vsIndex vs ! pn ! i
qdeps = qualifyDeps (vsQualifyOptions vs) qpn deps
newSaved = M.insert qpn qdeps (vsSaved vs)
case execUpdateState (pickPOption qpn opt qdeps) vs of
Left (cs, err) -> return $ Fail cs (DependenciesNotLinked err)
Right vs' -> local (const vs' { vsSaved = newSaved }) r
Expand Down Expand Up @@ -349,7 +349,7 @@ verifyLinkGroup lg =
-- if a constructor is added to the datatype we won't notice it here
Just i -> do
vs <- get
let PInfo _deps _exes finfo _ = vsIndex vs ! lgPackage lg ! i
let PInfo _deps _exes finfo _ _ = vsIndex vs ! lgPackage lg ! i
flags = M.keys finfo
stanzas = [TestStanzas, BenchStanzas]
forM_ flags $ \fn -> do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ showFR _ MultipleInstances = " (multiple instances)"
showFR c (DependenciesNotLinked msg) = " (dependencies not linked: " ++ msg ++ "; conflict set: " ++ showConflictSet c ++ ")"
showFR c CyclicDependencies = " (cyclic dependencies; conflict set: " ++ showConflictSet c ++ ")"
showFR _ (UnsupportedSpecVer ver) = " (unsupported spec-version " ++ prettyShow ver ++ ")"
showFR _ (MissingArtifacts arts) = " (missing build artifacts: " ++ prettyShow arts ++ ")"
-- The following are internal failures. They should not occur. In the
-- interest of not crashing unnecessarily, we still just print an error
-- message though.
Expand Down
Loading

0 comments on commit c6d6397

Please sign in to comment.