Commit 9fa04f06 authored by Andrey Mokhov's avatar Andrey Mokhov
Browse files

Minor revision

parent d2dddad4
......@@ -99,19 +99,19 @@ win32 = lib "Win32"
xhtml = lib "xhtml"
-- | Construct a library package, e.g. @array@.
lib :: String -> Package
lib :: PackageName -> Package
lib name = library name ("libraries" -/- name)
-- | Construct a top-level library package, e.g. @compiler@.
top :: String -> Package
top :: PackageName -> Package
top name = library name name
-- | Construct a top-level program package, e.g. @ghc@.
prg :: String -> Package
prg :: PackageName -> Package
prg name = program name name
-- | Construct a utility package, e.g. @haddock@.
util :: String -> Package
util :: PackageName -> Package
util name = program name ("utils" -/- name)
-- | Amend a package path if it doesn't conform to a typical pattern.
......
......@@ -9,41 +9,44 @@
-- Basic functionality for extracting Haskell package metadata stored in
-- @.cabal@ files.
-----------------------------------------------------------------------------
module Hadrian.Haskell.Cabal (readCabal, cabalNameVersion, cabalDependencies) where
module Hadrian.Haskell.Cabal (readCabal, pkgNameVersion, pkgDependencies) where
import Development.Shake
import Distribution.Package
import Distribution.PackageDescription
import Distribution.PackageDescription.Parse
import Distribution.Text
import Distribution.Types.CondTree
import Distribution.Verbosity
import qualified Distribution.Package as C
import qualified Distribution.PackageDescription as C
import qualified Distribution.PackageDescription.Parse as C
import qualified Distribution.Text as C
import qualified Distribution.Types.CondTree as C
import qualified Distribution.Verbosity as C
-- | Read a given @.cabal@ file and return the 'GenericPackageDescription'. The
-- @.cabal@ file is tracked.
readCabal :: FilePath -> Action GenericPackageDescription
readCabal cabal = do
need [cabal]
liftIO $ readGenericPackageDescription silent cabal
import Hadrian.Haskell.Package
-- | Read a given @.cabal@ file and return the package name and version. The
-- @.cabal@ file is tracked.
cabalNameVersion :: FilePath -> Action (String, String)
cabalNameVersion cabal = do
identifier <- package . packageDescription <$> readCabal cabal
return (unPackageName $ pkgName identifier, display $ pkgVersion identifier)
-- | Read the @.cabal@ file of a given package and return the
-- 'GenericPackageDescription'. The @.cabal@ file is tracked.
readCabal :: Package -> Action C.GenericPackageDescription
readCabal pkg = do
need [pkgCabalFile pkg]
liftIO $ C.readGenericPackageDescription C.silent (pkgCabalFile pkg)
-- | Read a given @.cabal@ file and return the package dependencies. The
-- @.cabal@ file is tracked.
cabalDependencies :: FilePath -> Action [String]
cabalDependencies cabal = do
gpd <- readCabal cabal
let libDeps = collectDeps (condLibrary gpd)
exeDeps = map (collectDeps . Just . snd) (condExecutables gpd)
return [ unPackageName p | Dependency p _ <- concat (libDeps : exeDeps) ]
-- | Read the @.cabal@ file of a given package and return the package name and
-- version. The @.cabal@ file is tracked.
pkgNameVersion :: Package -> Action (PackageName, String)
pkgNameVersion pkg = do
pkgId <- C.package . C.packageDescription <$> readCabal pkg
return (C.unPackageName $ C.pkgName pkgId, C.display $ C.pkgVersion pkgId)
collectDeps :: Maybe (CondTree v [Dependency] a) -> [Dependency]
-- | Read the @.cabal@ file of a given package and return the list of its
-- dependencies. The current version does not take care of Cabal conditionals
-- and therefore returns a crude overapproximation of The @.cabal@ file is tracked.
pkgDependencies :: Package -> Action [PackageName]
pkgDependencies pkg = do
gpd <- readCabal pkg
let libDeps = collectDeps (C.condLibrary gpd)
exeDeps = map (collectDeps . Just . snd) (C.condExecutables gpd)
return [ C.unPackageName p | C.Dependency p _ <- concat (libDeps : exeDeps) ]
collectDeps :: Maybe (C.CondTree v [C.Dependency] a) -> [C.Dependency]
collectDeps Nothing = []
collectDeps (Just (CondNode _ deps ifs)) = deps ++ concatMap f ifs
collectDeps (Just (C.CondNode _ deps ifs)) = deps ++ concatMap f ifs
where
f (CondBranch _ t mt) = collectDeps (Just t) ++ collectDeps mt
f (C.CondBranch _ t mt) = collectDeps (Just t) ++ collectDeps mt
......@@ -10,7 +10,7 @@
-----------------------------------------------------------------------------
module Hadrian.Haskell.Package (
-- * Data type
Package,
Package, PackageName,
-- * Construction and properties
library, program, pkgName, pkgPath, isLibrary, isProgram,
......@@ -24,6 +24,8 @@ import Development.Shake.FilePath
import GHC.Generics
import Hadrian.Utilities
type PackageName = String
-- TODO: Make PackageType more precise, #12.
data PackageType = Library | Program deriving (Generic, Show)
......@@ -32,10 +34,10 @@ data PackageType = Library | Program deriving (Generic, Show)
-- packages can be both. This works for now, but in future we plan to support
-- general Haskell packages. Also note that we assume that all packages have
-- different names, hence two packages with the same name are considered equal.
data Package = Package PackageType String FilePath deriving Generic
data Package = Package PackageType PackageName FilePath deriving Generic
-- | The name of a Haskell package. Examples: @Cabal@, @ghc-bin@.
pkgName :: Package -> String
pkgName :: Package -> PackageName
pkgName (Package _ name _) = name
-- | The path to the package source code relative to the root of the build
......@@ -63,17 +65,13 @@ instance Hashable PackageType
instance NFData PackageType
-- | Construct a library package.
library :: String -> FilePath -> Package
library :: PackageName -> FilePath -> Package
library = Package Library
-- | Construct a program package.
program :: String -> FilePath -> Package
program :: PackageName -> FilePath -> Package
program = Package Program
-- | The path to a package cabal file, e.g.: @ghc/ghc-bin.cabal@.
pkgCabalFile :: Package -> FilePath
pkgCabalFile pkg = pkgPath pkg -/- pkgName pkg <.> "cabal"
-- | Check whether a package is a library.
isLibrary :: Package -> Bool
isLibrary (Package Library _ _) = True
......@@ -83,3 +81,7 @@ isLibrary _ = False
isProgram :: Package -> Bool
isProgram (Package Program _ _) = True
isProgram _ = False
-- | The path to a package cabal file, e.g.: @ghc/ghc-bin.cabal@.
pkgCabalFile :: Package -> FilePath
pkgCabalFile pkg = pkgPath pkg -/- pkgName pkg <.> "cabal"
......@@ -62,7 +62,7 @@ knownPackages = sort $ defaultKnownPackages ++ userKnownPackages
-- TODO: Speed up? Switch to Set?
-- Note: this is slow but we keep it simple as there are just ~50 packages
findKnownPackage :: String -> Maybe Package
findKnownPackage :: PackageName -> Maybe Package
findKnownPackage name = find (\pkg -> pkgName pkg == name) knownPackages
-- | Determine the location of a 'Builder'.
......
......@@ -96,7 +96,7 @@ bootPackageConstraintsGenerator _ = do
bootPkgs <- stagePackages Stage0
let pkgs = filter (\p -> p /= compiler && isLibrary p) bootPkgs
constraints <- forM (sort pkgs) $ \pkg -> do
(name, version) <- cabalNameVersion (pkgCabalFile pkg)
(name, version) <- pkgNameVersion pkg
return (name ++ " == " ++ version)
return (unlines constraints)
......
......@@ -9,8 +9,8 @@ import Utilities
ghcCabalPackageArgs :: Args
ghcCabalPackageArgs = stage0 ? package ghcCabal ? builder Ghc ? do
cabalDeps <- expr $ pkgDependencies cabal
(_, cabalVersion) <- expr $ cabalNameVersion (pkgCabalFile cabal)
cabalDeps <- expr $ stage1Dependencies cabal
(_, cabalVersion) <- expr $ pkgNameVersion cabal
mconcat
[ pure [ "-package " ++ pkgName pkg | pkg <- cabalDeps, pkg /= parsec ]
, arg "--make"
......
......@@ -2,7 +2,7 @@ module Utilities (
build, buildWithCmdOptions, buildWithResources, applyPatch, runBuilder,
runBuilderWith, builderEnvironment, needBuilder, needLibrary,
installDirectory, installData, installScript, installProgram, linkSymbolic,
contextDependencies, pkgDependencies, libraryTargets, topsortPackages,
contextDependencies, stage1Dependencies, libraryTargets, topsortPackages,
packageDependenciesGenerator
) where
......@@ -191,7 +191,7 @@ packageDependenciesGenerator _ = do
exists <- doesFileExist (pkgCabalFile pkg)
if not exists then return (pkgName pkg)
else do
deps <- nubOrd . sort <$> cabalDependencies (pkgCabalFile pkg)
deps <- nubOrd . sort <$> pkgDependencies pkg
return . unwords $ pkgName pkg : (deps \\ [pkgName pkg])
return (unlines pkgDeps)
......@@ -200,7 +200,7 @@ packageDependenciesGenerator _ = do
-- The only subtlety here is that we never depend on packages built in 'Stage2'
-- or later, therefore the stage of the resulting dependencies is bounded from
-- above at 'Stage1'. To compute package dependencies we scan package cabal
-- files, see 'cabalDependencies' defined in "Hadrian.Haskell.Cabal".
-- files, see 'pkgDependencies' defined in "Hadrian.Haskell.Cabal".
contextDependencies :: Context -> Action [Context]
contextDependencies Context {..} = do
let pkgContext = \pkg -> Context (min stage Stage1) pkg way
......@@ -211,8 +211,9 @@ contextDependencies Context {..} = do
return . map pkgContext $ intersectOrd (compare . pkgName) pkgs deps
-- | Lookup dependencies of a 'Package' in the vanilla Stage1 context.
pkgDependencies :: Package -> Action [Package]
pkgDependencies = fmap (map Context.package) . contextDependencies . vanillaContext Stage1
stage1Dependencies :: Package -> Action [Package]
stage1Dependencies =
fmap (map Context.package) . contextDependencies . vanillaContext Stage1
-- | Given a library 'Package' this action computes all of its targets.
libraryTargets :: Context -> Action [FilePath]
......@@ -234,7 +235,7 @@ needLibrary cs = need =<< concatMapM libraryTargets cs
-- | Topological sort of packages according to their dependencies.
topsortPackages :: [Package] -> Action [Package]
topsortPackages pkgs = do
elems <- mapM (\p -> (p,) <$> pkgDependencies p) pkgs
elems <- mapM (\p -> (p,) <$> stage1Dependencies p) pkgs
return $ map fst $ topSort elems
where
annotateInDeg es e =
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment