Commit d94ddc0e authored by Edward Z. Yang's avatar Edward Z. Yang
Browse files

Refactor LocalBuildInfo interface.



This is an omnibus patch, with the overall goal of making
LocalBuildInfo Great Again.  The essential ideas:

* New type 'TargetInfo' which bundles together 'ComponentLocalBuildInfo'
  and 'Component'.  Eventually, it will also record file paths / module
  targets.  This data structure is basically what you want; a lot of
  old Cabal code did lots of gyrations converting from
  'ComponentLocalBuildInfo' to 'Component' and vice versa, now
  it's all centralized.

* The "new" API for 'LocalBuildInfo' is in
  "Distribution.Types.LocalBuildInfo".  The general principle
  is, where we previous dealt in 'ComponentLocalBuildInfo',
  we now deal in 'TargetInfo'.  There are shockingly few
  functions we need!

* I've restored 'componentsConfigs' to its Cabal 1.24 signature
  for BC.

* I killed a number of unused functions from "Distribution.Simple.LocalBuildInfo":
  'getLocalComponent', 'maybeGetDefaultLibraryLocalBuildInfo',
  'maybeGetComponentLocalBuildInfo', 'checkComponentsCyclic' and
  'enabledComponents'.  For each I checked on Hackage that they were
  not used.

* 'getComponentLocalBuildInfo', 'withComponentsInBuildOrder' and
  'componentsInBuildOrder' are deprecated to encourage people
  to instead use the 'TargetInfo's to finger which components
  they want built.

* 'ComponentLocalBuildInfo' now stores internally the computed
  'componentInternalDeps', so that 'LocalBuildInfo' can simply store
  a graph of 'ComponentLocalBuildInfo'.

* The code in Configure has been streamlined to use our new Graph
  data type to great success.

* The type of 'runTest' changed to take a 'ComponentLocalBuildInfo',
  bringing it more in line with everything else.

* New function 'readTargetInfos' which combines 'readBuildTargets'
  and 'checkBuildTargets', which is what you really wanted anyway.
Signed-off-by: default avatarEdward Z. Yang <ezyang@cs.stanford.edu>
parent 6305156f
......@@ -370,6 +370,7 @@ library
Distribution.Types.ComponentLocalBuildInfo
Distribution.Types.LocalBuildInfo
Distribution.Types.ComponentEnabledSpec
Distribution.Types.TargetInfo
Distribution.Utils.NubList
Distribution.Verbosity
Distribution.Version
......
......@@ -23,6 +23,9 @@ module Distribution.Simple.Build (
writeAutogenFiles,
) where
import Distribution.Types.LocalBuildInfo
import Distribution.Types.TargetInfo
import Distribution.Package
import qualified Distribution.Simple.GHC as GHC
import qualified Distribution.Simple.GHCJS as GHCJS
......@@ -56,12 +59,14 @@ import Distribution.System
import Distribution.Text
import Distribution.Verbosity
import Distribution.Compat.Graph (IsNode(..))
import qualified Data.Map as Map
import qualified Data.Set as Set
import Data.List
( intersect )
import Control.Monad
( when, unless )
( when, unless, forM_ )
import System.FilePath
( (</>), (<.>) )
import System.Directory
......@@ -80,18 +85,17 @@ build pkg_descr lbi flags suffixes
-- TODO: if checkBuildTargets ignores a target we may accept
-- a --assume-deps-up-to-date with multiple arguments. Arguably, we should
-- error early in this case.
targets <- readBuildTargets pkg_descr (buildArgs flags)
(cname, _) <- checkBuildTargets verbosity pkg_descr lbi targets >>= \r -> case r of
target <- readTargetInfos verbosity lbi (buildArgs flags) >>= \r -> case r of
[] -> die "In --assume-deps-up-to-date mode you must specify a target"
[target'] -> return target'
[target] -> return target
_ -> die "In --assume-deps-up-to-date mode you can only build a single target"
-- NB: do NOT 'createInternalPackageDB'; we don't want to delete it.
-- But this means we have to be careful about unregistering
-- ourselves.
let dbPath = internalPackageDBPath lbi distPref
internalPackageDB = SpecificPackageDB dbPath
clbi = getComponentLocalBuildInfo lbi cname
comp = getComponent pkg_descr cname
clbi = targetCLBI target
comp = targetComponent target
-- TODO: do we need to unregister libraries? In any case, this would
-- need to be done in the buildLib functionality.
-- Do the build
......@@ -105,11 +109,12 @@ build pkg_descr lbi flags suffixes
buildComponent verbosity (buildNumJobs flags) pkg_descr
lbi' suffixes comp clbi distPref
| otherwise = do
targets <- readBuildTargets pkg_descr (buildArgs flags)
targets' <- checkBuildTargets verbosity pkg_descr lbi targets
let componentsToBuild = componentsInBuildOrder lbi (map fst targets')
targets <- readTargetInfos verbosity lbi (buildArgs flags)
let componentsToBuild = neededTargetsInBuildOrder lbi (map nodeKey targets)
info verbosity $ "Component build order: "
++ intercalate ", " (map (showComponentName . componentLocalName) componentsToBuild)
++ intercalate ", "
(map (showComponentName . componentLocalName . targetCLBI)
componentsToBuild)
when (null targets) $
-- Only bother with this message if we're building the whole package
......@@ -117,8 +122,9 @@ build pkg_descr lbi flags suffixes
internalPackageDB <- createInternalPackageDB verbosity lbi distPref
-- TODO: we're computing this twice, do it once!
withComponentsInBuildOrder pkg_descr lbi (map fst targets') $ \comp clbi -> do
forM_ componentsToBuild $ \target -> do
let comp = targetComponent target
clbi = targetCLBI target
initialBuildSteps distPref pkg_descr lbi clbi verbosity
let bi = componentBuildInfo comp
progs' = addInternalBuildTools pkg_descr lbi bi (withPrograms lbi)
......@@ -143,18 +149,16 @@ repl pkg_descr lbi flags suffixes args = do
let distPref = fromFlag (replDistPref flags)
verbosity = fromFlag (replVerbosity flags)
targets <- readBuildTargets pkg_descr args
targets' <- case targets of
target <- readTargetInfos verbosity lbi args >>= \r -> case r of
-- This seems DEEPLY questionable.
[] -> return $ take 1 [ componentName c
| c <- pkgBuildableComponents pkg_descr ]
[target] -> fmap (map fst) (checkBuildTargets verbosity pkg_descr lbi [target])
[] -> return (head (allTargetsInBuildOrder lbi))
[target] -> return target
_ -> die $ "The 'repl' command does not support multiple targets at once."
let componentsToBuild = componentsInBuildOrder lbi targets'
componentForRepl = last componentsToBuild
let componentsToBuild = neededTargetsInBuildOrder lbi [nodeKey target]
debug verbosity $ "Component build order: "
++ intercalate ", "
[ showComponentName (componentLocalName clbi) | clbi <- componentsToBuild ]
(map (showComponentName . componentLocalName . targetCLBI)
componentsToBuild)
internalPackageDB <- createInternalPackageDB verbosity lbi distPref
......@@ -167,18 +171,17 @@ repl pkg_descr lbi flags suffixes args = do
-- build any dependent components
sequence_
[ do let cname = componentLocalName clbi
comp = getComponent pkg_descr cname
[ do let clbi = targetCLBI subtarget
comp = targetComponent subtarget
lbi' = lbiForComponent comp lbi
initialBuildSteps distPref pkg_descr lbi clbi verbosity
buildComponent verbosity NoFlag
pkg_descr lbi' suffixes comp clbi distPref
| clbi <- init componentsToBuild ]
| subtarget <- init componentsToBuild ]
-- REPL for target components
let clbi = componentForRepl
cname = componentLocalName clbi
comp = getComponent pkg_descr cname
let clbi = targetCLBI target
comp = targetComponent target
lbi' = lbiForComponent comp lbi
initialBuildSteps distPref pkg_descr lbi clbi verbosity
replComponent verbosity pkg_descr lbi' suffixes comp clbi distPref
......@@ -423,6 +426,7 @@ testSuiteLibV09AsLibAndExe pkg_descr
compat_key = computeCompatPackageKey (compiler lbi) compat_name pkg_ver (componentUnitId clbi)
libClbi = LibComponentLocalBuildInfo
{ componentPackageDeps = componentPackageDeps clbi
, componentInternalDeps = componentInternalDeps clbi
, componentLocalName = CSubLibName (testName test)
, componentIsPublic = False
, componentIncludes = componentIncludes clbi
......@@ -462,6 +466,7 @@ testSuiteLibV09AsLibAndExe pkg_descr
-- TODO: this is a hack, but as long as this is unique
-- (doesn't clobber something) we won't run into trouble
componentUnitId = mkUnitId (stubName test),
componentInternalDeps = [componentUnitId clbi],
componentLocalName = CExeName (stubName test),
componentPackageDeps = deps,
componentIncludes = zip (map fst deps) (repeat defaultRenaming)
......@@ -484,6 +489,7 @@ benchmarkExeV10asExe bm@Benchmark { benchmarkInterface = BenchmarkExeV10 _ f }
exeClbi = ExeComponentLocalBuildInfo {
componentUnitId = componentUnitId clbi,
componentLocalName = CExeName (benchmarkName bm),
componentInternalDeps = componentInternalDeps clbi,
componentPackageDeps = componentPackageDeps clbi,
componentIncludes = componentIncludes clbi
}
......
......@@ -10,10 +10,11 @@
-- Handling for user-specified build targets
-----------------------------------------------------------------------------
module Distribution.Simple.BuildTarget (
-- * Main interface
readTargetInfos,
-- * Build targets
BuildTarget(..),
readBuildTargets,
showBuildTarget,
QualLevel(..),
buildTargetComponentName,
......@@ -29,11 +30,11 @@ module Distribution.Simple.BuildTarget (
resolveBuildTargets,
BuildTargetProblem(..),
reportBuildTargetProblems,
-- * Checking build targets
checkBuildTargets
) where
import Distribution.Types.TargetInfo
import Distribution.Types.LocalBuildInfo
import Distribution.Package
import Distribution.PackageDescription
import Distribution.ModuleName
......@@ -65,6 +66,13 @@ import System.FilePath as FilePath
import System.Directory
( doesFileExist, doesDirectoryExist )
-- | Take a list of 'String' build targets, and parse and validate them
-- into actual 'TargetInfo's to be built/registered/whatever.
readTargetInfos :: Verbosity -> LocalBuildInfo -> [String] -> IO [TargetInfo]
readTargetInfos verbosity lbi args = do
build_targets <- readBuildTargets (localPkgDescr lbi) args
checkBuildTargets verbosity lbi build_targets
-- ------------------------------------------------------------
-- * User build targets
-- ------------------------------------------------------------
......@@ -951,17 +959,16 @@ caseFold = lowercase
--
-- Also swizzle into a more convenient form.
--
checkBuildTargets :: Verbosity -> PackageDescription -> LocalBuildInfo -> [BuildTarget]
-> IO [(ComponentName, Maybe (Either ModuleName FilePath))]
checkBuildTargets _ pkg lbi [] =
return [ (componentName c, Nothing) | c <- enabledComponents pkg lbi ]
checkBuildTargets :: Verbosity -> LocalBuildInfo -> [BuildTarget]
-> IO [TargetInfo]
checkBuildTargets _ lbi [] =
return (allTargetsInBuildOrder lbi)
checkBuildTargets verbosity pkg lbi targets = do
checkBuildTargets verbosity lbi targets = do
let (enabled, disabled) =
partitionEithers
[ case componentDisabledReason (componentEnabledSpec lbi)
(getComponent pkg cname) of
[ case componentNameDisabledReason (componentEnabledSpec lbi) cname of
Nothing -> Left target'
Just reason -> Right (cname, reason)
| target <- targets
......@@ -976,7 +983,14 @@ checkBuildTargets verbosity pkg lbi targets = do
++ showComponentName c ++ " will be processed. (Support for "
++ "module and file targets has not been implemented yet.)"
return enabled
-- Pick out the actual CLBIs for each of these cnames
enabled' <- forM enabled $ \(cname, _) -> do
case Map.lookup cname (componentNameMap lbi) of
Nothing -> error "checkBuildTargets: nothing enabled"
Just [clbi] -> return (mkTargetInfo lbi clbi)
Just _clbis -> error "checkBuildTargets: multiple copies enabled"
return enabled'
where
swizzleTarget (BuildTargetComponent c) = (c, Nothing)
......
......@@ -77,6 +77,8 @@ import Distribution.Simple.Register (createInternalPackageDB)
import Distribution.System
import Distribution.Version
import Distribution.Verbosity
import qualified Distribution.Compat.Graph as Graph
import Distribution.Compat.Graph (Node(..))
import qualified Distribution.Simple.GHC as GHC
import qualified Distribution.Simple.GHCJS as GHCJS
......@@ -98,7 +100,7 @@ import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy.Char8 as BLC8
import Data.List
( (\\), nub, partition, isPrefixOf, inits, stripPrefix )
( (\\), nub, partition, isPrefixOf, inits, stripPrefix, foldl' )
import Data.Maybe
( isNothing, catMaybes, fromMaybe, mapMaybe, isJust )
import Data.Either
......@@ -128,8 +130,6 @@ import Text.PrettyPrint
import Distribution.Compat.Environment ( lookupEnv )
import Distribution.Compat.Exception ( catchExit, catchIO )
import Data.Graph (graphFromEdges, topSort)
-- | The errors that can be thrown when reading the @setup-config@ file.
data ConfigStateFileError
= ConfigStateFileNoHeader -- ^ No header found.
......@@ -673,6 +673,10 @@ configure (pkg_descr0', pbi) cfg = do
then return False
else return True
let buildComponentsMap =
foldl' (\m clbi -> Map.insertWith (++) (componentLocalName clbi) [clbi] m)
Map.empty buildComponents
let lbi = LocalBuildInfo {
configFlags = cfg',
flagAssignment = flags,
......@@ -684,7 +688,8 @@ configure (pkg_descr0', pbi) cfg = do
compiler = comp,
hostPlatform = compPlatform,
buildDir = buildDir,
componentsConfigs = buildComponents,
componentGraph = Graph.fromList buildComponents,
componentNameMap = buildComponentsMap,
installedPkgs = packageDependsIndex,
pkgDescrFile = Nothing,
localPkgDescr = pkg_descr',
......@@ -1449,12 +1454,12 @@ mkComponentsGraph :: ComponentEnabledSpec
-> Either [ComponentName]
[(Component, [ComponentName])]
mkComponentsGraph enabled pkg_descr internalPkgDeps =
let graph = [ (c, componentName c, componentDeps c)
let g = Graph.fromList [ N c (componentName c) (componentDeps c)
| c <- pkgBuildableComponents pkg_descr
, componentEnabled enabled c ]
in case checkComponentsCyclic graph of
Just ccycle -> Left [ cname | (_,cname,_) <- ccycle ]
Nothing -> Right [ (c, cdeps) | (c, _, cdeps) <- topSortFromEdges graph ]
in case Graph.cycles g of
[] -> Right (map (\(N c _ cs) -> (c, cs)) (Graph.revTopSort g))
ccycles -> Left [ componentName c | N c _ _ <- concat ccycles ]
where
-- The dependencies for the given component
componentDeps component =
......@@ -1640,13 +1645,6 @@ computeCompatPackageKey comp pkg_name pkg_version (SimpleUnitId (ComponentId str
in fromMaybe rehashed_key (mb_verbatim_key `mplus` mb_truncated_key)
| otherwise = str
topSortFromEdges :: Ord key => [(node, key, [key])]
-> [(node, key, [key])]
topSortFromEdges es =
let (graph, vertexToNode, _) = graphFromEdges es
in reverse (map vertexToNode (topSort graph))
mkComponentsLocalBuildInfo :: ConfigFlags
-> Compiler
-> InstalledPackageIndex
......@@ -1655,32 +1653,32 @@ mkComponentsLocalBuildInfo :: ConfigFlags
-> [InstalledPackageInfo] -- external package deps
-> [(Component, [ComponentName])]
-> FlagAssignment
-> IO [(ComponentLocalBuildInfo,
[UnitId])]
-> IO [ComponentLocalBuildInfo]
mkComponentsLocalBuildInfo cfg comp installedPackages pkg_descr
internalPkgDeps externalPkgDeps
graph flagAssignment =
foldM go [] graph
where
go z (component, dep_cnames) = do
clbi <- componentLocalBuildInfo z component
-- NB: We want to preserve cdeps because it contains extra
-- information like build-tools ordering
let dep_uids = [ componentUnitId dep_clbi
| cname <- dep_cnames
-- Being in z relies on topsort!
, (dep_clbi, _) <- z
, dep_clbi <- z
, componentLocalName dep_clbi == cname ]
return ((clbi, dep_uids):z)
clbi <- componentLocalBuildInfo z component dep_uids
return (clbi:z)
-- The allPkgDeps contains all the package deps for the whole package
-- but we need to select the subset for this specific component.
-- we just take the subset for the package names this component
-- needs. Note, this only works because we cannot yet depend on two
-- versions of the same package.
componentLocalBuildInfo :: [(ComponentLocalBuildInfo, [UnitId])]
-> Component -> IO ComponentLocalBuildInfo
componentLocalBuildInfo internalComps component =
componentLocalBuildInfo :: [ComponentLocalBuildInfo]
-> Component -> [UnitId] -> IO ComponentLocalBuildInfo
componentLocalBuildInfo internalComps component dep_uids =
-- (putStrLn $ "configuring " ++ display (componentName component)) >>
case component of
CLib lib -> do
let exports = map (\n -> Installed.ExposedModule n Nothing)
......@@ -1695,6 +1693,7 @@ mkComponentsLocalBuildInfo cfg comp installedPackages pkg_descr
return LibComponentLocalBuildInfo {
componentPackageDeps = cpds,
componentInternalDeps = dep_uids,
componentUnitId = uid,
componentLocalName = componentName component,
componentIsPublic = libName lib == Nothing,
......@@ -1706,6 +1705,7 @@ mkComponentsLocalBuildInfo cfg comp installedPackages pkg_descr
CExe _ ->
return ExeComponentLocalBuildInfo {
componentUnitId = uid,
componentInternalDeps = dep_uids,
componentLocalName = componentName component,
componentPackageDeps = cpds,
componentIncludes = includes
......@@ -1713,6 +1713,7 @@ mkComponentsLocalBuildInfo cfg comp installedPackages pkg_descr
CTest _ ->
return TestComponentLocalBuildInfo {
componentUnitId = uid,
componentInternalDeps = dep_uids,
componentLocalName = componentName component,
componentPackageDeps = cpds,
componentIncludes = includes
......@@ -1720,6 +1721,7 @@ mkComponentsLocalBuildInfo cfg comp installedPackages pkg_descr
CBench _ ->
return BenchComponentLocalBuildInfo {
componentUnitId = uid,
componentInternalDeps = dep_uids,
componentLocalName = componentName component,
componentPackageDeps = cpds,
componentIncludes = includes
......@@ -1740,7 +1742,7 @@ mkComponentsLocalBuildInfo cfg comp installedPackages pkg_descr
lookupInternalPkg :: PackageId -> UnitId
lookupInternalPkg pkgid = do
let matcher (clbi, _)
let matcher clbi
| CLibName <- componentLocalName clbi
, pkgName pkgid == packageName pkg_descr
= Just (componentUnitId clbi)
......@@ -1750,7 +1752,9 @@ mkComponentsLocalBuildInfo cfg comp installedPackages pkg_descr
matcher _ = Nothing
case catMaybes (map matcher internalComps) of
[x] -> x
_ -> error "lookupInternalPkg"
_ -> error $ "lookupInternalPkg " ++ display pkgid
++ " " ++ intercalate ", "
(map (display . componentUnitId) internalComps)
cpds = if newPackageDepsBehaviour pkg_descr
then dedup $
......
......@@ -16,6 +16,9 @@ module Distribution.Simple.Install (
install,
) where
import Distribution.Types.TargetInfo
import Distribution.Types.LocalBuildInfo
import Distribution.PackageDescription
import Distribution.Package (Package(..))
import Distribution.Simple.LocalBuildInfo
......@@ -36,6 +39,7 @@ import qualified Distribution.Simple.JHC as JHC
import qualified Distribution.Simple.LHC as LHC
import qualified Distribution.Simple.UHC as UHC
import qualified Distribution.Simple.HaskellSuite as HaskellSuite
import Distribution.Compat.Graph (IsNode(..))
import Control.Monad (when, unless)
import System.Directory
......@@ -60,27 +64,27 @@ install :: PackageDescription -- ^information from the .cabal file
install pkg_descr lbi flags
| fromFlag (copyAssumeDepsUpToDate flags) = do
checkHasLibsOrExes
targets <- readBuildTargets pkg_descr (copyArgs flags)
targets' <- checkBuildTargets verbosity pkg_descr lbi targets
case targets' of
targets <- readTargetInfos verbosity lbi (copyArgs flags)
case targets of
_ | null (copyArgs flags)
-> copyPackage verbosity pkg_descr lbi distPref copydest
[(cname, _)] ->
let clbi = getComponentLocalBuildInfo lbi cname
comp = getComponent pkg_descr cname
[target] ->
let clbi = targetCLBI target
comp = targetComponent target
in copyComponent verbosity pkg_descr lbi comp clbi copydest
_ -> die "In --assume-deps-up-to-date mode you can only copy a single target"
| otherwise = do
checkHasLibsOrExes
targets <- readBuildTargets pkg_descr (copyArgs flags)
targets' <- checkBuildTargets verbosity pkg_descr lbi targets
targets <- readTargetInfos verbosity lbi (copyArgs flags)
copyPackage verbosity pkg_descr lbi distPref copydest
-- It's not necessary to do these in build-order, but it's harmless
withComponentsInBuildOrder pkg_descr lbi (map fst targets') $ \comp clbi ->
copyComponent verbosity pkg_descr lbi comp clbi copydest
withNeededTargetsInBuildOrder lbi (map nodeKey targets) $ \target ->
let comp = targetComponent target
clbi = targetCLBI target
in copyComponent verbosity pkg_descr lbi comp clbi copydest
where
distPref = fromFlag (copyDistPref flags)
verbosity = fromFlag (copyVerbosity flags)
......
......@@ -32,7 +32,6 @@ module Distribution.Simple.LocalBuildInfo (
showComponentName,
componentNameString,
ComponentLocalBuildInfo(..),
getLocalComponent,
componentComponentId,
componentBuildDir,
foldComponent,
......@@ -43,12 +42,9 @@ module Distribution.Simple.LocalBuildInfo (
pkgBuildableComponents,
lookupComponent,
getComponent,
maybeGetDefaultLibraryLocalBuildInfo,
maybeGetComponentLocalBuildInfo,
getComponentLocalBuildInfo,
allComponentsInBuildOrder,
componentsInBuildOrder,
checkComponentsCyclic,
depLibraryPaths,
withAllComponentsInBuildOrder,
......@@ -60,7 +56,6 @@ module Distribution.Simple.LocalBuildInfo (
withTestLBI,
enabledTestLBIs,
enabledBenchLBIs,
enabledComponents,
-- TODO: Don't export me
ComponentEnabledSpec(..),
......@@ -84,6 +79,7 @@ import Distribution.Types.ComponentEnabledSpec
import Distribution.Types.PackageDescription
import Distribution.Types.ComponentLocalBuildInfo
import Distribution.Types.LocalBuildInfo
import Distribution.Types.TargetInfo
import Distribution.Simple.InstallDirs hiding (absoluteInstallDirs,
prefixRelativeInstallDirs,
......@@ -95,22 +91,20 @@ import Distribution.Package
import Distribution.Simple.Compiler
import Distribution.Simple.PackageIndex
import Distribution.Simple.Utils
import Distribution.Text
import qualified Distribution.Compat.Graph as Graph
import Distribution.Compat.Graph (IsNode(..))
import Data.Array ((!))
import Data.Graph
import Data.List (stripPrefix)
import Data.Maybe
import Data.Tree (flatten)
import System.FilePath
import qualified Data.Map as Map
import System.Directory (doesDirectoryExist, canonicalizePath)
-- -----------------------------------------------------------------------------
-- Configuration information of buildable components
getLocalComponent :: PackageDescription -> ComponentLocalBuildInfo -> Component
getLocalComponent pkg_descr clbi = getComponent pkg_descr (componentLocalName clbi)
componentBuildDir :: LocalBuildInfo -> ComponentLocalBuildInfo -> FilePath
-- For now, we assume that libraries/executables/test-suites/benchmarks
-- are only ever built once. With Backpack, we need a special case for
......@@ -123,61 +117,39 @@ componentBuildDir lbi clbi
CTestName s -> s
CBenchName s -> s
{-# DEPRECATED getComponentLocalBuildInfo "This function is not well-defined, because a 'ComponentName' does not uniquely identify a 'ComponentLocalBuildInfo'. If you have a 'TargetInfo', you should use 'targetCLBI' to get the 'ComponentLocalBuildInfo'. Otherwise, use 'componentNameTargets' to get all possible 'ComponentLocalBuildInfo's. This will be removed in Cabal 2.2." #-}
getComponentLocalBuildInfo :: LocalBuildInfo -> ComponentName -> ComponentLocalBuildInfo
getComponentLocalBuildInfo lbi cname =
case maybeGetComponentLocalBuildInfo lbi cname of
Just clbi -> clbi
Nothing ->
case componentNameTargets lbi cname of
[target] -> targetCLBI target
[] ->
error $ "internal error: there is no configuration data "
++ "for component " ++ show cname
maybeGetComponentLocalBuildInfo
:: LocalBuildInfo -> ComponentName -> Maybe ComponentLocalBuildInfo
maybeGetComponentLocalBuildInfo lbi cname =
case [ clbi
| (clbi, _) <- componentsConfigs lbi
, cid <- componentNameToUnitIds lbi cname
, cid == componentUnitId clbi ] of
[clbi] -> Just clbi
_ -> Nothing
maybeGetDefaultLibraryLocalBuildInfo
:: LocalBuildInfo
-> Maybe ComponentLocalBuildInfo
maybeGetDefaultLibraryLocalBuildInfo lbi =
case [ clbi
| (clbi@LibComponentLocalBuildInfo{}, _) <- componentsConfigs lbi
, componentIsPublic clbi
] of
[clbi] -> Just clbi
_ -> Nothing
componentNameToUnitIds :: LocalBuildInfo -> ComponentName -> [UnitId]
componentNameToUnitIds lbi cname =
[ componentUnitId clbi
| (clbi, _) <- componentsConfigs lbi
, componentName (getLocalComponent (localPkgDescr lbi) clbi) == cname ]
targets ->
error $ "internal error: the component name " ++ show cname
++ "is ambiguous. Refers to: "
++ intercalate ", " (map (display . nodeKey) targets)
-- | Perform the action on each enabled 'library' in the package
-- description with the 'ComponentLocalBuildInfo'.
withLibLBI :: PackageDescription -> LocalBuildInfo
-> (Library -> ComponentLocalBuildInfo -> IO ()) -> IO ()
withLibLBI pkg lbi f =
sequence_
[ f lib clbi
| (clbi@LibComponentLocalBuildInfo{}, _) <- componentsConfigs lbi
, CLib lib <- [getComponent pkg (componentLocalName clbi)] ]
withLibLBI _pkg lbi f =
withAllTargetsInBuildOrder lbi $ \target ->
case targetComponent target of
CLib lib -> f lib (targetCLBI target)
_ -> return ()
-- | Perform the action on each enabled 'Executable' in the package
-- description. Extended version of 'withExe' that also gives corresponding
-- build info.
withExeLBI :: PackageDescription -> LocalBuildInfo
-> (Executable -> ComponentLocalBuildInfo -> IO ()) -> IO ()
withExeLBI pkg lbi f =
sequence_
[ f exe clbi
| (clbi@ExeComponentLocalBuildInfo{}, _) <- componentsConfigs lbi
, CExe exe <- [getComponent pkg (componentLocalName clbi)] ]
withExeLBI _pkg lbi f =
withAllTargetsInBuildOrder lbi $ \target ->
case targetComponent target of
CExe exe -> f exe (targetCLBI target)
_ -> return ()
-- | Perform the action on each enabled 'Benchmark' in the package
-- description.
...