Unverified Commit 7169ac5d authored by Andrey Mokhov's avatar Andrey Mokhov Committed by GitHub
Browse files

Rework parsing of Cabal metadata (#692)

The current implementation of parsing Cabal data is a big mess, which affects performance as described in #671 and #550. In this PR we simplify the implementation and avoid unnecessary reparsing.

As a result, the zero build time is reduced from 30 seconds to 5 seconds on my machine. The full build time seems to have been improved as well, since now all CI bots complete within the time limit. On the other hand, the speed up of the full build with `-j` on my machine does not appear to be significant.
parent 835f2766
......@@ -34,15 +34,15 @@ executable hadrian
, Hadrian.Builder.Tar
, Hadrian.Expression
, Hadrian.Haskell.Cabal
, Hadrian.Haskell.Cabal.CabalData
, Hadrian.Haskell.Cabal.PackageData
, Hadrian.Haskell.Cabal.Type
, Hadrian.Haskell.Cabal.Parse
, Hadrian.Oracles.ArgsHash
, Hadrian.Oracles.Cabal
, Hadrian.Oracles.Cabal.Rules
, Hadrian.Oracles.Cabal.Type
, Hadrian.Oracles.DirectoryContents
, Hadrian.Oracles.Path
, Hadrian.Oracles.TextFile
, Hadrian.Oracles.TextFile.Rules
, Hadrian.Oracles.TextFile.Type
, Hadrian.Package
, Hadrian.Target
, Hadrian.Utilities
......@@ -121,7 +121,7 @@ executable hadrian
, mtl == 2.2.*
, parsec >= 3.1 && < 3.2
, QuickCheck >= 2.6 && < 2.11
, shake >= 0.16.1
, shake >= 0.16.4
, transformers >= 0.4 && < 0.6
, unordered-containers >= 0.2.1 && < 0.3
build-tools: alex >= 3.1
......
......@@ -53,7 +53,7 @@ libPath context = buildRoot <&> (-/- libDir context)
pkgFile :: Context -> String -> String -> Action FilePath
pkgFile context@Context {..} prefix suffix = do
path <- buildPath context
pid <- pkgIdentifier context
pid <- pkgIdentifier package
return $ path -/- prefix ++ pid ++ suffix
-- | Path to inplace package configuration file of a given 'Context'.
......@@ -91,9 +91,9 @@ pkgGhciLibraryFile context = pkgFile context "HS" ".o"
-- | Path to the configuration file of a given 'Context'.
pkgConfFile :: Context -> Action FilePath
pkgConfFile ctx@Context {..} = do
pkgConfFile Context {..} = do
root <- buildRoot
pid <- pkgIdentifier ctx
pid <- pkgIdentifier package
return $ root -/- relativePackageDbPath stage -/- pid <.> "conf"
-- | Given a 'Context' and a 'FilePath' to a source file, compute the 'FilePath'
......
......@@ -14,7 +14,7 @@ module Expression (
-- * Convenient accessors
getBuildRoot, getContext, getOutputs, getInputs,
getInput, getOutput, getPackageData,
getInput, getOutput, getContextData,
-- * Re-exports
module Base,
......@@ -27,14 +27,14 @@ import Builder
import Context hiding (stage, package, way)
import Expression.Type
import Hadrian.Expression hiding (Expr, Predicate, Args)
import Hadrian.Haskell.Cabal.PackageData
import Hadrian.Oracles.TextFile
import Hadrian.Haskell.Cabal.Type
import Hadrian.Oracles.Cabal
-- | Get values from a configured cabal stage.
getPackageData :: (PackageData -> a) -> Expr a
getPackageData key = do
packageData <- expr . readPackageData =<< getContext
return $ key packageData
getContextData :: (ContextData -> a) -> Expr a
getContextData key = do
contextData <- expr . readContextData =<< getContext
return $ key contextData
-- | Is the build currently in the provided stage?
stage :: Stage -> Predicate
......
......@@ -19,7 +19,7 @@ module Hadrian.Expression (
import Control.Monad.Extra
import Control.Monad.Trans
import Control.Monad.Trans.Reader
import Data.Semigroup
import Data.Semigroup (Semigroup, (<>))
import Development.Shake
import Development.Shake.Classes
......
-----------------------------------------------------------------------------
-- |
-- Module : Hadrian.Haskell.Cabal
-- Copyright : (c) Andrey Mokhov 2014-2017
-- Copyright : (c) Andrey Mokhov 2014-2018
-- License : MIT (see the file LICENSE)
-- Maintainer : andrey.mokhov@gmail.com
-- Stability : experimental
......@@ -10,36 +10,47 @@
-- Cabal files.
-----------------------------------------------------------------------------
module Hadrian.Haskell.Cabal (
pkgVersion, pkgIdentifier, pkgDependencies, pkgSynopsis
pkgVersion, pkgIdentifier, pkgSynopsis, pkgDescription, pkgDependencies,
pkgGenericDescription
) where
import Development.Shake
import Distribution.PackageDescription (GenericPackageDescription)
import Context.Type
import Hadrian.Haskell.Cabal.CabalData
import Hadrian.Oracles.TextFile
import Hadrian.Haskell.Cabal.Type
import Hadrian.Oracles.Cabal
import Hadrian.Package
-- | Read a Cabal file and return the package version. The Cabal file is tracked.
pkgVersion :: Context -> Action String
pkgVersion = fmap version . readCabalData
pkgVersion :: Package -> Action String
pkgVersion = fmap version . readPackageData
-- | Read a Cabal file and return the package identifier, e.g. @base-4.10.0.0@.
-- The Cabal file is tracked.
pkgIdentifier :: Context -> Action String
pkgIdentifier context = do
cabal <- readCabalData context
pkgIdentifier :: Package -> Action String
pkgIdentifier package = do
cabal <- readPackageData package
return $ if null (version cabal)
then name cabal
else name cabal ++ "-" ++ version cabal
-- | Read a Cabal file and return the package synopsis. The Cabal file is tracked.
pkgSynopsis :: Package -> Action String
pkgSynopsis = fmap synopsis . readPackageData
-- | Read a Cabal file and return the package description. The Cabal file is
-- tracked.
pkgDescription :: Package -> Action String
pkgDescription = fmap description . readPackageData
-- | Read a Cabal file and return the sorted list of the package dependencies.
-- The current version does not take care of Cabal conditionals and therefore
-- returns a crude overapproximation of actual dependencies. The Cabal file is
-- tracked.
pkgDependencies :: Context -> Action [PackageName]
pkgDependencies = fmap (map pkgName . packageDependencies) . readCabalData
pkgDependencies :: Package -> Action [PackageName]
pkgDependencies = fmap (map pkgName . packageDependencies) . readPackageData
-- | Read a Cabal file and return the package synopsis. The Cabal file is tracked.
pkgSynopsis :: Context -> Action String
pkgSynopsis = fmap synopsis . readCabalData
-- | Read a Cabal file and return the 'GenericPackageDescription'. The Cabal
-- file is tracked.
pkgGenericDescription :: Package -> Action GenericPackageDescription
pkgGenericDescription = fmap genericPackageDescription . readPackageData
module Hadrian.Haskell.Cabal.CabalData where
import Development.Shake.Classes
import Distribution.PackageDescription
import GHC.Generics
import Hadrian.Package
-- | Haskell package metadata extracted from a Cabal file, without performing
-- the resolution of package configuration flags and associated conditionals.
-- One consequence is that 'packageDependencies' is an overappoximation of
-- actual package dependencies; for example, both @unix@ and @win32@ packages
-- may be included even if only one of them is required on the target OS.
data CabalData = CabalData
{ name :: PackageName
, version :: String
, synopsis :: String
, genericPackageDescription :: GenericPackageDescription
, packageDescription :: PackageDescription
, packageDependencies :: [Package]
} deriving (Eq, Show, Typeable, Generic)
instance Binary CabalData
instance Hashable CabalData where hashWithSalt salt = hashWithSalt salt . show
instance NFData CabalData
......@@ -10,10 +10,11 @@
-- Extracting Haskell package metadata stored in Cabal files.
-----------------------------------------------------------------------------
module Hadrian.Haskell.Cabal.Parse (
PackageData (..), parseCabalFile, parsePackageData, parseCabalPkgId,
ContextData (..), parsePackageData, resolveContextData, parseCabalPkgId,
configurePackage, copyPackage, registerPackage
) where
import Data.Bifunctor
import Data.List.Extra
import Development.Shake
import qualified Distribution.ModuleName as C
......@@ -22,7 +23,6 @@ import qualified Distribution.PackageDescription as C
import qualified Distribution.PackageDescription.Configuration as C
import qualified Distribution.PackageDescription.Parsec as C
import qualified Distribution.Simple.Compiler as C
import qualified Distribution.Simple.GHC as C
import qualified Distribution.Simple.Program.Db as C
import qualified Distribution.Simple as C
import qualified Distribution.Simple.Program.Builtin as C
......@@ -33,14 +33,15 @@ import qualified Distribution.Simple.Build as C
import qualified Distribution.Types.ComponentRequestedSpec as C
import qualified Distribution.InstalledPackageInfo as Installed
import qualified Distribution.Simple.PackageIndex as C
import qualified Distribution.Types.LocalBuildInfo as C
import qualified Distribution.Text as C
import qualified Distribution.Types.LocalBuildInfo as C
import qualified Distribution.Types.CondTree as C
import qualified Distribution.Types.MungedPackageId as C
import qualified Distribution.Verbosity as C
import Hadrian.Expression
import Hadrian.Haskell.Cabal.CabalData
import Hadrian.Haskell.Cabal.PackageData
import Hadrian.Oracles.TextFile
import Hadrian.Haskell.Cabal
import Hadrian.Haskell.Cabal.Type
import Hadrian.Oracles.Cabal
import Hadrian.Target
import Base
......@@ -50,7 +51,31 @@ import Flavour
import Packages
import Settings
-- | Parse the Cabal package identifier from a @.cabal@ file.
-- | Parse the Cabal file of a given 'Package'. This operation is cached by the
-- "Hadrian.Oracles.TextFile.readPackageData" oracle.
parsePackageData :: Package -> Action PackageData
parsePackageData pkg = do
gpd <- liftIO $ C.readGenericPackageDescription C.verbose (pkgCabalFile pkg)
let pd = C.packageDescription gpd
pkgId = C.package pd
name = C.unPackageName (C.pkgName pkgId)
version = C.display (C.pkgVersion pkgId)
libDeps = collectDeps (C.condLibrary gpd)
exeDeps = map (collectDeps . Just . snd) (C.condExecutables gpd)
allDeps = concat (libDeps : exeDeps)
sorted = sort [ C.unPackageName p | C.Dependency p _ <- allDeps ]
deps = nubOrd sorted \\ [name]
depPkgs = catMaybes $ map findPackageByName deps
return $ PackageData name version (C.synopsis pd) (C.description pd) depPkgs gpd
where
-- Collect an overapproximation of dependencies by ignoring conditionals
collectDeps :: Maybe (C.CondTree v [C.Dependency] a) -> [C.Dependency]
collectDeps Nothing = []
collectDeps (Just (C.CondNode _ deps ifs)) = deps ++ concatMap f ifs
where
f (C.CondBranch _ t mt) = collectDeps (Just t) ++ collectDeps mt
-- | Parse the package identifier from a Cabal file.
parseCabalPkgId :: FilePath -> IO String
parseCabalPkgId file = C.display . C.package . C.packageDescription <$> C.readGenericPackageDescription C.silent file
......@@ -75,46 +100,6 @@ biModules pd = go [ comp | comp@(bi,_,_) <-
go [x] = x
go _ = error "Cannot handle more than one buildinfo yet."
-- TODO: Add proper error handling for partiality due to Nothing/Left cases.
-- | Parse the Cabal file of the 'Package' from a given 'Context'. This function
-- reads the Cabal file, gets some information about the compiler to be used
-- corresponding to the 'Stage' it gets from the 'Context', and finalises the
-- package description it got from the Cabal file with additional information
-- such as platform, compiler version conditionals, and package flags.
parseCabalFile :: Context -> Action CabalData
parseCabalFile context@Context {..} = do
let file = pkgCabalFile package
-- Read the package description from the Cabal file
gpd <- liftIO $ C.readGenericPackageDescription C.verbose file
-- Configure the package with the GHC for this stage
hcPath <- builderPath (Ghc CompileHs stage)
(compiler, Just platform, _pgdb) <- liftIO $
C.configure C.silent (Just hcPath) Nothing C.emptyProgramDb
flagList <- interpret (target context (Cabal Flags stage) [] []) =<< args <$> flavour
let flags = foldr addFlag mempty flagList
where
addFlag :: String -> C.FlagAssignment -> C.FlagAssignment
addFlag ('-':name) = C.insertFlagAssignment (C.mkFlagName name) False
addFlag ('+':name) = C.insertFlagAssignment (C.mkFlagName name) True
addFlag name = C.insertFlagAssignment (C.mkFlagName name) True
let (Right (pd,_)) = C.finalizePD flags C.defaultComponentRequestedSpec
(const True) platform (C.compilerInfo compiler) [] gpd
-- depPkgs are all those packages that are needed. These should be found in
-- the known build packages even if they are not build in this stage.
let depPkgs = map (findPackageByName' . C.unPackageName . C.depPkgName)
$ flip C.enabledBuildDepends C.defaultComponentRequestedSpec pd
where
findPackageByName' p = fromMaybe (error msg) (findPackageByName p)
where
msg = "Failed to find package " ++ quote (show p)
return $ CabalData (C.unPackageName . C.pkgName . C.package $ pd)
(C.display . C.pkgVersion . C.package $ pd)
(C.synopsis pd) gpd pd depPkgs
-- TODO: Track command line arguments and package configuration flags.
-- | Configure a package using the Cabal library by collecting all the command
-- line arguments (to be passed to the setup script) and package configuration
......@@ -124,7 +109,8 @@ configurePackage :: Context -> Action ()
configurePackage context@Context {..} = do
putLoud $ "| Configure package " ++ quote (pkgName package)
CabalData _ _ _ gpd _pd depPkgs <- readCabalData context
gpd <- pkgGenericDescription package
depPkgs <- packageDependencies <$> readPackageData package
-- Stage packages are those we have in this stage.
stagePkgs <- stagePackages stage
......@@ -136,22 +122,21 @@ configurePackage context@Context {..} = do
-- Figure out what hooks we need.
hooks <- case C.buildType (C.flattenPackageDescription gpd) of
C.Configure -> pure C.autoconfUserHooks
-- time has a "Custom" Setup.hs, but it's actually Configure
-- plus a "./Setup test" hook. However, Cabal is also
-- "Custom", but doesn't have a configure script.
-- The 'time' package has a 'C.Custom' Setup.hs, but it's actually
-- 'C.Configure' plus a @./Setup test@ hook. However, Cabal is also
-- 'C.Custom', but doesn't have a configure script.
C.Custom -> do
configureExists <- doesFileExist $
replaceFileName (pkgCabalFile package) "configure"
pure $ if configureExists then C.autoconfUserHooks else C.simpleUserHooks
-- Not quite right, but good enough for us:
_ | package == rts ->
-- Don't try to do post conf validation for rts. This will simply
-- not work, due to the ld-options and the Stg.h.
-- Don't try to do post configuration validation for 'rts'. This
-- will simply not work, due to the @ld-options@ and @Stg.h@.
pure $ C.simpleUserHooks { C.postConf = \_ _ _ _ -> return () }
| otherwise -> pure C.simpleUserHooks
-- Compute the list of flags
-- Compute the Cabal configurartion arguments
-- Compute the list of flags, and the Cabal configurartion arguments
flavourArgs <- args <$> flavour
flagList <- interpret (target context (Cabal Flags stage) [] []) flavourArgs
argList <- interpret (target context (Cabal Setup stage) [] []) flavourArgs
......@@ -165,7 +150,7 @@ configurePackage context@Context {..} = do
copyPackage :: Context -> Action ()
copyPackage context@Context {..} = do
putLoud $ "| Copy package " ++ quote (pkgName package)
CabalData _ _ _ gpd _ _ <- readCabalData context
gpd <- pkgGenericDescription package
ctxPath <- Context.contextPath context
pkgDbPath <- packageDbPath stage
verbosity <- getVerbosity
......@@ -178,15 +163,15 @@ registerPackage :: Context -> Action ()
registerPackage context@Context {..} = do
putLoud $ "| Register package " ++ quote (pkgName package)
ctxPath <- Context.contextPath context
CabalData _ _ _ gpd _ _ <- readCabalData context
gpd <- pkgGenericDescription package
verbosity <- getVerbosity
let v = if verbosity >= Loud then "-v3" else "-v0"
liftIO $ C.defaultMainWithHooksNoReadArgs C.autoconfUserHooks gpd
[ "register", "--builddir", ctxPath, v ]
-- | Parse the 'PackageData' of the 'Package' of a given 'Context'.
parsePackageData :: Context -> Action PackageData
parsePackageData context@Context {..} = do
-- | Parse the 'ContextData' of a given 'Context'.
resolveContextData :: Context -> Action ContextData
resolveContextData context@Context {..} = do
-- TODO: This is conceptually wrong!
-- We should use the gpd, the flagAssignment and compiler, hostPlatform, and
-- other information from the lbi. And then compute the finalised PD (flags,
......@@ -195,18 +180,34 @@ parsePackageData context@Context {..} = do
-- let (Right (pd,_)) = C.finalizePackageDescription flags (const True) platform (compilerInfo compiler) [] gpd
--
-- However when using the new-build path's this might change.
CabalData _ _ _ _gpd pd _depPkgs <- readCabalData context
-- Read the package description from the Cabal file
gpd <- genericPackageDescription <$> readPackageData package
-- Configure the package with the GHC for this stage
(compiler, platform) <- configurePackageGHC package stage
flagList <- interpret (target context (Cabal Flags stage) [] []) =<< args <$> flavour
let flags = foldr addFlag mempty flagList
where
addFlag :: String -> C.FlagAssignment -> C.FlagAssignment
addFlag ('-':name) = C.insertFlagAssignment (C.mkFlagName name) False
addFlag ('+':name) = C.insertFlagAssignment (C.mkFlagName name) True
addFlag name = C.insertFlagAssignment (C.mkFlagName name) True
let (Right (pd,_)) = C.finalizePD flags C.defaultComponentRequestedSpec
(const True) platform (C.compilerInfo compiler) [] gpd
cPath <- Context.contextPath context
need [cPath -/- "setup-config"]
lbi <- liftIO $ C.getPersistBuildConfig cPath
-- TODO: Move this into its own rule for "build/autogen/cabal_macros.h", and
-- "build/autogen/Path_*.hs" and 'need' them here.
-- create the cabal_macros.h, ...
-- Note: the `cPath` is ignored. The path that's used is the 'buildDir' path
-- from the local build info (lbi).
-- TODO: Move this into its own rule for @build/autogen/cabal_macros.h@, and
-- @build/autogen/Path_*.hs@ and 'need' these files here.
-- Create the @cabal_macros.h@, ...
-- Note: the @cPath@ is ignored. The path that's used is the 'buildDir' path
-- from the local build info @lbi@.
pdi <- liftIO $ getHookedBuildInfo (pkgPath package)
let pd' = C.updatePackageDescription pdi pd
lbi' = lbi { C.localPkgDescr = pd' }
......@@ -216,12 +217,12 @@ parsePackageData context@Context {..} = do
-- See: https://github.com/snowleopard/hadrian/issues/548
let extDeps = C.externalPackageDeps lbi'
deps = map (C.display . snd) extDeps
dep_direct = map (fromMaybe (error "parsePackageData: dep_keys failed")
. C.lookupUnitId (C.installedPkgs lbi') . fst) extDeps
dep_ipids = map (C.display . Installed.installedUnitId) dep_direct
depDirect = map (fromMaybe (error "resolveContextData: depDirect failed")
. C.lookupUnitId (C.installedPkgs lbi') . fst) extDeps
depIds = map (C.display . Installed.installedUnitId) depDirect
Just ghcProg = C.lookupProgram C.ghcProgram (C.withPrograms lbi')
dep_pkgs = C.topologicalOrder (packageHacks (C.installedPkgs lbi'))
forDeps f = concatMap f dep_pkgs
depPkgs = C.topologicalOrder (packageHacks (C.installedPkgs lbi'))
forDeps f = concatMap f depPkgs
-- Copied from Distribution.Simple.PreProcess.ppHsc2Hs
packageHacks = case C.compilerFlavor (C.compiler lbi') of
......@@ -236,37 +237,28 @@ parsePackageData context@Context {..} = do
hackRtsPackage index | null (C.allPackages index) = index
-- ^ do not hack the empty index
hackRtsPackage index = case C.lookupPackageName index (C.mkPackageName "rts") of
[(_,[rts])] -> C.insert rts {
[(_, [rts])] -> C.insert rts {
Installed.ldOptions = [],
Installed.libraryDirs = filter (not . ("gcc-lib" `isSuffixOf`))
(Installed.libraryDirs rts)} index
-- GHC <= 6.12 had $topdir/gcc-lib in their library-dirs for the rts
-- package, which causes problems when we try to use the in-tree
-- mingw, due to accidentally picking up the incompatible libraries
-- there. So we filter out gcc-lib from the RTS's library-dirs here.
-- GHC <= 6.12 had @$topdir/gcc-lib@ in their @library-dirs@ for the
-- 'rts' package, which causes problems when we try to use the
-- in-tree @mingw@, due to accidentally picking up the incompatible
-- libraries there. So we filter out @gcc-lib@ from the RTS's
-- @library-dirs@ here.
_ -> error "No (or multiple) GHC rts package is registered!"
(buildInfo, modules, mainIs) = biModules pd'
in return $ PackageData
in return $ ContextData
{ dependencies = deps
, name = C.unPackageName . C.pkgName . C.package $ pd'
, version = C.display . C.pkgVersion . C.package $ pd'
, componentId = C.localCompatPackageKey lbi'
, mainIs = case mainIs of
Just (mod, filepath) -> Just (C.display mod, filepath)
Nothing -> Nothing
, modules = map C.display $ modules
, otherModules = map C.display . C.otherModules $ buildInfo
, synopsis = C.synopsis pd'
, description = C.description pd'
, mainIs = fmap (first C.display) mainIs
, modules = map C.display modules
, otherModules = map C.display $ C.otherModules buildInfo
, srcDirs = C.hsSourceDirs buildInfo
, deps = deps
, depIpIds = dep_ipids
, depIds = depIds
, depNames = map (C.display . C.mungedName . snd) extDeps
, depCompIds = if C.packageKeySupported (C.compiler lbi')
then dep_ipids
else deps
, includeDirs = C.includeDirs buildInfo
, includes = C.includes buildInfo
, installIncludes = C.installIncludes buildInfo
......@@ -275,7 +267,6 @@ parsePackageData context@Context {..} = do
, asmSrcs = C.asmSources buildInfo
, cSrcs = C.cSources buildInfo
, cmmSrcs = C.cmmSources buildInfo
, dataFiles = C.dataFiles pd'
, hcOpts = C.programDefaultArgs ghcProg
++ C.hcOptions C.GHC buildInfo
++ C.languageToFlags (C.compiler lbi') (C.defaultLanguage buildInfo)
......@@ -293,8 +284,9 @@ parsePackageData context@Context {..} = do
getHookedBuildInfo :: FilePath -> IO C.HookedBuildInfo
getHookedBuildInfo baseDir = do
-- TODO: We should probably better generate this in the build dir, rather
-- than in the base dir? However, @configure@ is run in the baseDir.
-- TODO: We should probably better generate this in the build directory,
-- rather than in the base directory? However, @configure@ is run in the
-- base directory.
maybeInfoFile <- C.findHookedPackageDesc baseDir
case maybeInfoFile of
Nothing -> return C.emptyHookedBuildInfo
......
module Hadrian.Haskell.Cabal.PackageData where
-----------------------------------------------------------------------------
-- |
-- Module : Hadrian.Haskell.Cabal.Type
-- Copyright : (c) Andrey Mokhov 2014-2018
-- License : MIT (see the file LICENSE)
-- Maintainer : andrey.mokhov@gmail.com
-- Stability : experimental
--
-- Data types for storing basic Haskell package metadata, such as package name,
-- version and dependencies, extracted from a Cabal file.
-----------------------------------------------------------------------------
module Hadrian.Haskell.Cabal.Type where
import Development.Shake.Classes
import Distribution.PackageDescription
import GHC.Generics
import Hadrian.Package
-- | Most of these fields used to be provided in @package-data.mk@ files.
-- | Haskell package metadata extracted from a Cabal file without performing
-- the resolution of package configuration flags and associated conditionals,
-- which are build context specific. Note that 'packageDependencies' is an
-- overappoximation of actual package dependencies; for example, both @unix@ and
-- @win32@ packages may be included even if only one of them is required on the
-- target OS. See 'ContextData' for metadata obtained after resolving package
-- configuration flags and conditionals according to the current build context.
data PackageData = PackageData
{ name :: PackageName
, version :: String
, synopsis :: String
, description :: String
, packageDependencies :: [Package]
, genericPackageDescription :: GenericPackageDescription
} deriving (Eq, Generic, Show, Typeable)
-- | Haskell package metadata obtained after resolving package configuration
-- flags and associated conditionals according to the current build context.
-- See 'PackageData' for metadata that can be obtained without resolving package
-- configuration flags and conditionals.
data ContextData = ContextData
{ dependencies :: [PackageName]
, name :: PackageName
, version :: String
, componentId :: String
, mainIs :: Maybe (String, FilePath) -- ("Main", filepath)
, modules :: [String]
, otherModules :: [String]
, synopsis :: String
, description :: String
, srcDirs :: [String]
, deps :: [String]
, depIpIds :: [String]
, depIds :: [String]
, depNames :: [String]
, depCompIds :: [String]
, includeDirs :: [String]
, includes :: [String]
, installIncludes :: [String]
......@@ -28,7 +54,6 @@ data PackageData = PackageData
, asmSrcs :: [String]
, cSrcs :: [String]
, cmmSrcs :: [String]
, dataFiles :: [String]
, hcOpts :: [String]
, asmOpts :: [String]
, ccOpts :: [String]
......@@ -39,8 +64,12 @@ data PackageData = PackageData
, depCcOpts :: [String]
, depLdOpts :: [String]
, buildGhciLib :: Bool
} deriving (Eq, Read, Show, Typeable, Generic)
} deriving (Eq, Generic, Show, Typeable)
instance Binary PackageData
instance Hashable PackageData
instance Hashable PackageData where hashWithSalt salt = hashWithSalt salt . show
instance NFData PackageData
instance Binary ContextData
instance Hashable ContextData
instance NFData ContextData
-----------------------------------------------------------------------------
-- |
-- Module : Hadrian.Oracles.Cabal
-- Copyright : (c) Andrey Mokhov 2014-2018
-- License : MIT (see the file LICENSE)
-- Maintainer : andrey.mokhov@gmail.com
-- Stability : experimental
--
-- This module defines oracles for reading and parsing Cabal files, as well as
-- for configuring Haskell packages.
-----------------------------------------------------------------------------
module Hadrian.Oracles.Cabal (
readPackageData, readContextData, configurePackageGHC
) where
import Development.Shake
import Distribution.Simple (Compiler)
import Distribution.System (Platform)