Differentiate between C and Haskell package
authorAndrey Mokhov <andrey.mokhov@gmail.com>
Sat, 26 Aug 2017 22:31:31 +0000 (23:31 +0100)
committerAndrey Mokhov <andrey.mokhov@gmail.com>
Sat, 26 Aug 2017 22:31:31 +0000 (23:31 +0100)
17 files changed:
hadrian.cabal
src/Base.hs
src/Context.hs
src/GHC.hs
src/Hadrian/Haskell/Cabal.hs
src/Hadrian/Haskell/Cabal/Parse.hs
src/Hadrian/Haskell/Package.hs [deleted file]
src/Hadrian/Package.hs [new file with mode: 0644]
src/Rules/Data.hs
src/Rules/Install.hs
src/Rules/Library.hs
src/Rules/Program.hs
src/Settings/Builders/Ghc.hs
src/Settings/Builders/GhcCabal.hs
src/Settings/Builders/Haddock.hs
src/Settings/Packages/GhcCabal.hs
src/Utilities.hs

index 57aac79..dbe454e 100644 (file)
@@ -29,11 +29,11 @@ executable hadrian
                        , Hadrian.Expression
                        , Hadrian.Haskell.Cabal
                        , Hadrian.Haskell.Cabal.Parse
-                       , Hadrian.Haskell.Package
                        , Hadrian.Oracles.ArgsHash
                        , Hadrian.Oracles.DirectoryContents
                        , Hadrian.Oracles.Path
                        , Hadrian.Oracles.TextFile
+                       , Hadrian.Package
                        , Hadrian.Target
                        , Hadrian.Utilities
                        , Oracles.Flag
index 9bba7ed..a27a658 100644 (file)
@@ -15,7 +15,7 @@ module Base (
 
     -- * Basic data types
     module Builder,
-    module Hadrian.Haskell.Package,
+    module Hadrian.Package,
     module Stage,
     module Way,
 
@@ -37,7 +37,7 @@ import Development.Shake.Classes
 import Development.Shake.FilePath
 import Development.Shake.Util
 import Hadrian.Utilities
-import Hadrian.Haskell.Package
+import Hadrian.Package
 
 import Builder
 import Stage
index b4258a6..eff69fa 100644 (file)
@@ -4,6 +4,7 @@ module Context (
 
     -- * Expressions
     getStage, getPackage, getWay, getStagedSettingList, getBuildPath,
+    withHsPackage,
 
     -- * Paths
     contextDir, buildPath, pkgInplaceConfig, pkgDataFile, pkgSetupConfigFile,
@@ -55,23 +56,37 @@ getWay = way <$> getContext
 getStagedSettingList :: (Stage -> SettingList) -> Args Context b
 getStagedSettingList f = getSettingList . f =<< getStage
 
--- | Get the build path of the current 'Context'.
-getBuildPath :: Expr Context b FilePath
-getBuildPath = expr . buildPath =<< getContext
+-- | Construct an expression that depends on the Cabal file of the current
+-- package and is empty in a non-Haskell context.
+withHsPackage :: (Monoid a, Semigroup a) => (FilePath -> Expr Context b a) -> Expr Context b a
+withHsPackage expr = do
+    pkg <- getPackage
+    case pkgCabalFile pkg of
+        Just file -> expr file
+        Nothing   -> mempty
+
+-- | The directory in 'buildRoot' containing build artefacts of a given 'Context'.
+contextDir :: Context -> FilePath
+contextDir Context {..} = stageString stage -/- pkgPath package
 
 -- | Path to the directory containing build artefacts of a given 'Context'.
 buildPath :: Context -> Action FilePath
 buildPath context = buildRoot <&> (-/- contextDir context)
 
--- | The directory in 'buildRoot' containing build artefacts of a given 'Context'.
-contextDir :: Context -> FilePath
-contextDir Context {..} = stageString stage -/- pkgPath package
+-- | Get the build path of the current 'Context'.
+getBuildPath :: Expr Context b FilePath
+getBuildPath = expr . buildPath =<< getContext
+
+pkgId :: Package -> Action FilePath
+pkgId package = case pkgCabalFile package of
+    Just file -> pkgIdentifier file
+    Nothing   -> return (pkgName package) -- Non-Haskell packages, e.g. rts
 
 pkgFile :: Context -> String -> String -> Action FilePath
 pkgFile context@Context {..} prefix suffix = do
-    path  <- buildPath context
-    pkgId <- pkgIdentifier package
-    return $ path -/- prefix ++ pkgId ++ suffix
+    path <- buildPath context
+    pid  <- pkgId package
+    return $ path -/- prefix ++ pid ++ suffix
 
 -- | Path to inplace package configuration file of a given 'Context'.
 pkgInplaceConfig :: Context -> Action FilePath
@@ -122,10 +137,10 @@ pkgGhciLibraryFile context = pkgFile context "HS" ".o"
 pkgConfFile :: Context -> Action FilePath
 pkgConfFile Context {..} = do
     root  <- buildRoot
-    pkgId <- pkgIdentifier package
+    pid   <- pkgId package
     let dbDir | stage == Stage0 = root -/- stage0PackageDbDir
               | otherwise       = inplacePackageDbPath
-    return $ dbDir -/- pkgId <.> "conf"
+    return $ dbDir -/- pid <.> "conf"
 
 -- | Given a 'Context' and a 'FilePath' to a source file, compute the 'FilePath'
 -- to its object file. For example:
index 0adf259..7ed96d2 100644 (file)
@@ -41,82 +41,89 @@ defaultKnownPackages =
     , win32, xhtml ]
 
 -- | Package definitions, see 'Package'.
-array               = lib  "array"
-base                = lib  "base"
-binary              = lib  "binary"
-bytestring          = lib  "bytestring"
-cabal               = lib  "Cabal"           `setPath` "libraries/Cabal/Cabal"
-checkApiAnnotations = util "check-api-annotations"
-compareSizes        = util "compareSizes"    `setPath` "utils/compare_sizes"
-compiler            = top  "ghc"             `setPath` "compiler"
-containers          = lib  "containers"
-deepseq             = lib  "deepseq"
-deriveConstants     = util "deriveConstants"
-directory           = lib  "directory"
-dllSplit            = util "dll-split"
-filepath            = lib  "filepath"
-genapply            = util "genapply"
-genprimopcode       = util "genprimopcode"
-ghc                 = prg  "ghc-bin"         `setPath` "ghc"
-ghcBoot             = lib  "ghc-boot"
-ghcBootTh           = lib  "ghc-boot-th"
-ghcCabal            = util "ghc-cabal"
-ghcCompact          = lib  "ghc-compact"
-ghci                = lib  "ghci"
-ghcPkg              = util "ghc-pkg"
-ghcPrim             = lib  "ghc-prim"
-ghcTags             = util "ghctags"
-ghcSplit            = util "ghc-split"
-haddock             = util "haddock"
-haskeline           = lib  "haskeline"
-hsc2hs              = util "hsc2hs"
-hp2ps               = util "hp2ps"
-hpc                 = lib  "hpc"
-hpcBin              = util "hpc-bin"         `setPath` "utils/hpc"
-integerGmp          = lib  "integer-gmp"
-integerSimple       = lib  "integer-simple"
-iservBin            = prg  "iserv-bin"       `setPath` "iserv"
-libffi              = top  "libffi"
-mtl                 = lib  "mtl"
-parsec              = lib  "parsec"
-parallel            = lib  "parallel"
-pretty              = lib  "pretty"
-primitive           = lib  "primitive"
-process             = lib  "process"
-rts                 = top  "rts"
-runGhc              = util "runghc"
-stm                 = lib  "stm"
-templateHaskell     = lib  "template-haskell"
-terminfo            = lib  "terminfo"
-text                = lib  "text"
-time                = lib  "time"
-touchy              = util "touchy"
-transformers        = lib  "transformers"
-unlit               = util "unlit"
-unix                = lib  "unix"
-win32               = lib  "Win32"
-xhtml               = lib  "xhtml"
-
--- | Construct a library package, e.g. @array@.
-lib :: PackageName -> Package
-lib name = library name ("libraries" -/- name)
-
--- | Construct a top-level library package, e.g. @compiler@.
-top :: PackageName -> Package
-top name = library name name
-
--- | Construct a top-level program package, e.g. @ghc@.
-prg :: PackageName -> Package
-prg name = program name name
-
--- | Construct a utility package, e.g. @haddock@.
-util :: PackageName -> Package
-util name = program name ("utils" -/- name)
+array               = hsLib  "array"
+base                = hsLib  "base"
+binary              = hsLib  "binary"
+bytestring          = hsLib  "bytestring"
+cabal               = hsLib  "Cabal"           `setPath` "libraries/Cabal/Cabal"
+checkApiAnnotations = hsUtil "check-api-annotations"
+compareSizes        = hsUtil "compareSizes"    `setPath` "utils/compare_sizes"
+compiler            = hsTop  "ghc"             `setPath` "compiler"
+containers          = hsLib  "containers"
+deepseq             = hsLib  "deepseq"
+deriveConstants     = hsUtil "deriveConstants"
+directory           = hsLib  "directory"
+dllSplit            = hsUtil "dll-split"
+filepath            = hsLib  "filepath"
+genapply            = hsUtil "genapply"
+genprimopcode       = hsUtil "genprimopcode"
+ghc                 = hsPrg  "ghc-bin"         `setPath` "ghc"
+ghcBoot             = hsLib  "ghc-boot"
+ghcBootTh           = hsLib  "ghc-boot-th"
+ghcCabal            = hsUtil "ghc-cabal"
+ghcCompact          = hsLib  "ghc-compact"
+ghci                = hsLib  "ghci"
+ghcPkg              = hsUtil "ghc-pkg"
+ghcPrim             = hsLib  "ghc-prim"
+ghcTags             = hsUtil "ghctags"
+ghcSplit            = hsUtil "ghc-split"
+haddock             = hsUtil "haddock"
+haskeline           = hsLib  "haskeline"
+hsc2hs              = hsUtil "hsc2hs"
+hp2ps               = cUtil  "hp2ps"
+hpc                 = hsLib  "hpc"
+hpcBin              = hsUtil "hpc-bin"         `setPath` "utils/hpc"
+integerGmp          = hsLib  "integer-gmp"
+integerSimple       = hsLib  "integer-simple"
+iservBin            = hsPrg  "iserv-bin"       `setPath` "iserv"
+libffi              = cTop   "libffi"
+mtl                 = hsLib  "mtl"
+parsec              = hsLib  "parsec"
+parallel            = hsLib  "parallel"
+pretty              = hsLib  "pretty"
+primitive           = hsLib  "primitive"
+process             = hsLib  "process"
+rts                 = cTop   "rts"
+runGhc              = hsUtil "runghc"
+stm                 = hsLib  "stm"
+templateHaskell     = hsLib  "template-haskell"
+terminfo            = hsLib  "terminfo"
+text                = hsLib  "text"
+time                = hsLib  "time"
+touchy              = cUtil  "touchy"
+transformers        = hsLib  "transformers"
+unlit               = cUtil  "unlit"
+unix                = hsLib  "unix"
+win32               = hsLib  "Win32"
+xhtml               = hsLib  "xhtml"
+
+-- | Construct a Haskell library package, e.g. @array@.
+hsLib :: PackageName -> Package
+hsLib name = hsLibrary name ("libraries" -/- name)
+
+-- | Construct a top-level Haskell library package, e.g. @compiler@.
+hsTop :: PackageName -> Package
+hsTop name = hsLibrary name name
+
+-- | Construct a top-level C library package, e.g. @rts@.
+cTop :: PackageName -> Package
+cTop name = cLibrary name name
+
+-- | Construct a top-level Haskell program package, e.g. @ghc@.
+hsPrg :: PackageName -> Package
+hsPrg name = hsProgram name name
+
+-- | Construct a Haskell utility package, e.g. @haddock@.
+hsUtil :: PackageName -> Package
+hsUtil name = hsProgram name ("utils" -/- name)
+
+-- | Construct a C utility package, e.g. @haddock@.
+cUtil :: PackageName -> Package
+cUtil name = cProgram name ("utils" -/- name)
 
 -- | Amend a package path if it doesn't conform to a typical pattern.
 setPath :: Package -> FilePath -> Package
-setPath pkg path | isLibrary pkg = library (pkgName pkg) path
-                 | otherwise     = program (pkgName pkg) path
+setPath pkg path = pkg { pkgPath = path }
 
 -- | Some builders are built by this very build system, in which case
 -- 'builderProvenance' returns the corresponding build 'Context' (which includes
index be2b32a..bc70efb 100644 (file)
@@ -7,64 +7,38 @@
 -- Stability  : experimental
 --
 -- Basic functionality for extracting Haskell package metadata stored in
--- @.cabal@ files.
+-- Cabal files.
 -----------------------------------------------------------------------------
 module Hadrian.Haskell.Cabal (
     pkgVersion, pkgIdentifier, pkgDependencies, pkgSynopsis
     ) where
 
-import Control.Monad
 import Development.Shake
 
 import Hadrian.Haskell.Cabal.Parse
-import Hadrian.Haskell.Package
+import Hadrian.Package
 import Hadrian.Oracles.TextFile
-import Hadrian.Utilities
 
--- | Read the @.cabal@ file of a given package and return the package version.
--- The @.cabal@ file is tracked.
-pkgVersion :: Package -> Action String
-pkgVersion pkg = do
-    cabal <- readCabalFile (pkgCabalFile pkg)
-    return (version cabal)
+-- | Read a Cabal file and return the package version. The Cabal file is tracked.
+pkgVersion :: FilePath -> Action String
+pkgVersion cabalFile = version <$> readCabalFile cabalFile
 
--- | Read the @.cabal@ file of a given package and return the package identifier,
--- e.g. @base-4.10.0.0@. If the @.cabal@ file does not exist return just the
--- package name, e.g. @rts@. If the @.cabal@ file exists then it is tracked, and
--- furthermore we check that the recorded package name matches the name of the
--- package passed as the parameter, and raise an error otherwise.
-pkgIdentifier :: Package -> Action String
-pkgIdentifier pkg = do
-    cabalExists <- doesFileExist (pkgCabalFile pkg)
-    if not cabalExists
-    then return (pkgName pkg)
-    else do
-        cabal <- readCabalFile (pkgCabalFile pkg)
-        when (pkgName pkg /= name cabal) $
-            error $ "[Hadrian.Haskell.Cabal] Inconsistent package name: expected "
-                 ++ quote (pkgName pkg) ++ ", but " ++ quote (pkgCabalFile pkg)
-                 ++ " specifies " ++ quote (name cabal) ++ "."
-        return $ if (null $ version cabal)
-            then pkgName pkg
-            else pkgName pkg ++ "-" ++ version cabal
+-- | Read a Cabal file and return the package identifier, e.g. @base-4.10.0.0@.
+-- The Cabal file is tracked.
+pkgIdentifier :: FilePath -> Action String
+pkgIdentifier cabalFile = do
+    cabal <- readCabalFile cabalFile
+    return $ if (null $ version cabal)
+        then name cabal
+        else name cabal ++ "-" ++ version cabal
 
--- | Read the @.cabal@ file of a given package and return the sorted list of its
--- 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 :: Package -> Action [PackageName]
-pkgDependencies pkg = do
-    cabal <- readCabalFile (pkgCabalFile pkg)
-    return (dependencies cabal)
+-- | 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 :: FilePath -> Action [PackageName]
+pkgDependencies cabalFile = dependencies <$> readCabalFile cabalFile
 
--- | Read the @.cabal@ file of a given package and return the package synopsis
--- or @Nothing@ if the @.cabal@ file does not exist. The existence and contents
--- of the @.cabal@ file are tracked.
-pkgSynopsis :: Package -> Action (Maybe String)
-pkgSynopsis pkg = do
-    cabalExists <- doesFileExist (pkgCabalFile pkg)
-    if not cabalExists
-    then return Nothing
-    else do
-        cabal <- readCabalFile (pkgCabalFile pkg)
-        return $ Just (synopsis cabal)
+-- | Read a Cabal file and return the package synopsis. The Cabal file is tracked.
+pkgSynopsis :: FilePath -> Action String
+pkgSynopsis cabalFile = synopsis <$> readCabalFile cabalFile
index 8e9273d..578eeac 100644 (file)
@@ -6,7 +6,7 @@
 -- Maintainer : andrey.mokhov@gmail.com
 -- Stability  : experimental
 --
--- Extracting Haskell package metadata stored in @.cabal@ files.
+-- Extracting Haskell package metadata stored in Cabal files.
 -----------------------------------------------------------------------------
 module Hadrian.Haskell.Cabal.Parse (Cabal (..), parseCabal) where
 
@@ -20,10 +20,10 @@ import qualified Distribution.Text                     as C
 import qualified Distribution.Types.CondTree           as C
 import qualified Distribution.Verbosity                as C
 
-import Hadrian.Haskell.Package
+import Hadrian.Package
 
--- TODO: Use fine-grain tracking instead of tracking the whole @.cabal@ file.
--- | Haskell package metadata extracted from a @.cabal@ file.
+-- TODO: Use fine-grain tracking instead of tracking the whole Cabal file.
+-- | Haskell package metadata extracted from a Cabal file.
 data Cabal = Cabal
     { dependencies :: [PackageName]
     , name         :: PackageName
@@ -41,7 +41,7 @@ instance Hashable Cabal where
 instance NFData Cabal where
     rnf (Cabal a b c d) = a `seq` b `seq` c `seq` d `seq` ()
 
--- | Parse a @.cabal@ file.
+-- | Parse a Cabal file.
 parseCabal :: FilePath -> IO Cabal
 parseCabal file = do
     gpd <- liftIO $ C.readGenericPackageDescription C.silent file
diff --git a/src/Hadrian/Haskell/Package.hs b/src/Hadrian/Haskell/Package.hs
deleted file mode 100644 (file)
index bcba5cf..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module     : Hadrian.Haskell.Package
--- Copyright  : (c) Andrey Mokhov 2014-2017
--- License    : MIT (see the file LICENSE)
--- Maintainer : andrey.mokhov@gmail.com
--- Stability  : experimental
---
--- Haskell packages and operations on them.
------------------------------------------------------------------------------
-module Hadrian.Haskell.Package (
-    -- * Data type
-    Package, PackageName,
-
-    -- * Construction and properties
-    library, program, pkgName, pkgPath, isLibrary, isProgram,
-
-    -- * Package directory structure
-    pkgCabalFile
-    ) where
-
-import Development.Shake.Classes
-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)
-
--- | A Haskell package. The current implementation treats a package as either
--- a library or a program, which is a gross oversimplification as Haskell
--- 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 PackageName FilePath deriving Generic
-
--- | The name of a Haskell package. Examples: @Cabal@, @ghc-bin@.
-pkgName :: Package -> PackageName
-pkgName (Package _ name _) = name
-
--- | The path to the package source code relative to the root of the build
--- system. For example, @libraries/Cabal/Cabal@ and @ghc@ are paths to the
--- @Cabal@ and @ghc-bin@ packages in GHC.
-pkgPath :: Package -> FilePath
-pkgPath (Package _ _ path) = path
-
-instance Show Package where
-    show (Package Library n p) = "library " ++ show n ++ " " ++ show p
-    show (Package Program n p) = "program " ++ show n ++ " " ++ show p
-
-instance Eq Package where
-    p == q = pkgName p == pkgName q
-
-instance Ord Package where
-    compare p q = compare (pkgName p) (pkgName q)
-
-instance Binary   Package
-instance Hashable Package
-instance NFData   Package
-
-instance Binary   PackageType
-instance Hashable PackageType
-instance NFData   PackageType
-
--- | Construct a library package.
-library :: PackageName -> FilePath -> Package
-library = Package Library
-
--- | Construct a program package.
-program :: PackageName -> FilePath -> Package
-program = Package Program
-
--- | Check whether a package is a library.
-isLibrary :: Package -> Bool
-isLibrary (Package Library _ _) = True
-isLibrary _ = False
-
--- | Check whether a package is a program.
-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"
diff --git a/src/Hadrian/Package.hs b/src/Hadrian/Package.hs
new file mode 100644 (file)
index 0000000..c7dc525
--- /dev/null
@@ -0,0 +1,119 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module     : Hadrian.Package
+-- Copyright  : (c) Andrey Mokhov 2014-2017
+-- License    : MIT (see the file LICENSE)
+-- Maintainer : andrey.mokhov@gmail.com
+-- Stability  : experimental
+--
+-- A /package/ is a collection of files. We currently only support C and Haskell
+-- packages and treat a package as either a library or a program. The latter is
+-- a gross oversimplification as, for example, Haskell packages can be both.
+-- This works for now, but should be improved in future.
+-----------------------------------------------------------------------------
+module Hadrian.Package (
+    -- * Data types
+    Package (..), PackageName, PackageLanguage, PackageType,
+
+    -- * Construction and properties
+    cLibrary, cProgram, hsLibrary, hsProgram,
+    isLibrary, isProgram, isCPackage, isHsPackage,
+
+    -- * Package directory structure
+    pkgCabalFile, unsafePkgCabalFile
+    ) where
+
+import Data.Maybe
+import Development.Shake.Classes
+import Development.Shake.FilePath
+import GHC.Generics
+import GHC.Stack
+import Hadrian.Utilities
+
+data PackageLanguage = C | Haskell deriving (Generic, Show)
+
+-- TODO: Make PackageType more precise, #12.
+data PackageType = Library | Program deriving (Generic, Show)
+
+type PackageName = String
+
+-- TODO: Consider turning Package into a GADT indexed with language and type.
+data Package = Package {
+    -- | The package language. 'C' and 'Haskell' packages are supported.
+    pkgLanguage :: PackageLanguage,
+    -- | The package type. 'Library' and 'Program' packages are supported.
+    pkgType :: PackageType,
+    -- | The package name. We assume that all packages have different names,
+    -- hence two packages with the same name are considered equal.
+    pkgName :: PackageName,
+    -- | The path to the package source code relative to the root of the build
+    -- system. For example, @libraries/Cabal/Cabal@ and @ghc@ are paths to the
+    -- @Cabal@ and @ghc-bin@ packages in GHC.
+    pkgPath :: FilePath
+    } deriving (Generic, Show)
+
+instance Eq Package where
+    p == q = pkgName p == pkgName q
+
+instance Ord Package where
+    compare p q = compare (pkgName p) (pkgName q)
+
+instance Binary   PackageLanguage
+instance Hashable PackageLanguage
+instance NFData   PackageLanguage
+
+instance Binary   PackageType
+instance Hashable PackageType
+instance NFData   PackageType
+
+instance Binary   Package
+instance Hashable Package
+instance NFData   Package
+
+-- | Construct a C library package.
+cLibrary :: PackageName -> FilePath -> Package
+cLibrary = Package C Library
+
+-- | Construct a C program package.
+cProgram :: PackageName -> FilePath -> Package
+cProgram = Package C Program
+
+-- | Construct a Haskell library package.
+hsLibrary :: PackageName -> FilePath -> Package
+hsLibrary = Package Haskell Library
+
+-- | Construct a Haskell program package.
+hsProgram :: PackageName -> FilePath -> Package
+hsProgram = Package Haskell Program
+
+-- | Is this a library package?
+isLibrary :: Package -> Bool
+isLibrary (Package _ Library _ _) = True
+isLibrary _ = False
+
+-- | Is this a program package?
+isProgram :: Package -> Bool
+isProgram (Package _ Program _ _) = True
+isProgram _ = False
+
+-- | Is this a C package?
+isCPackage :: Package -> Bool
+isCPackage (Package C _ _ _) = True
+isCPackage _ = False
+
+-- | Is this a Haskell package?
+isHsPackage :: Package -> Bool
+isHsPackage (Package Haskell _ _ _) = True
+isHsPackage _ = False
+
+-- | The path to the Cabal file of a Haskell package, e.g. @ghc/ghc-bin.cabal@,
+-- or @Nothing@ if the argument is not a Haskell package.
+pkgCabalFile :: Package -> Maybe FilePath
+pkgCabalFile p | isHsPackage p = Just $ pkgPath p -/- pkgName p <.> "cabal"
+               | otherwise     = Nothing
+
+-- | Like 'pkgCabalFile' but raises an error on a non-Haskell package.
+unsafePkgCabalFile :: HasCallStack => Package -> FilePath
+unsafePkgCabalFile p = fromMaybe (error msg) (pkgCabalFile p)
+  where
+    msg = "[unsafePkgCabalFile] Not a Haskell package: " ++ show p
index 7715eff..eb3516d 100644 (file)
@@ -14,7 +14,7 @@ import Utilities
 buildPackageData :: Context -> Rules ()
 buildPackageData context@Context {..} = do
     let dir       = "//" ++ contextDir context
-        cabalFile = pkgCabalFile package
+        cabalFile = unsafePkgCabalFile package -- TODO: improve
         configure = pkgPath package -/- "configure"
     -- TODO: Get rid of hardcoded file paths.
     [dir -/- "package-data.mk", dir -/- "setup-config"] &%> \[mk, setupConfig] -> do
index 4858f40..6732935 100644 (file)
@@ -189,8 +189,9 @@ installPackages = do
     copyFile (pkgPath integerGmp -/- "gmp/ghc-gmp.h") (pkgPath integerGmp -/- "ghc-gmp.h")
 
     forM_ installLibPkgs $ \pkg -> do
-        when (isLibrary pkg) $
-            withLatestBuildStage pkg $ \stage -> do
+        case pkgCabalFile pkg of
+            Nothing -> error $ "Non-Haskell project in installLibPkgs" ++ show pkg
+            Just cabalFile -> withLatestBuildStage pkg $ \stage -> do
                 let context = vanillaContext stage pkg
                 top <- topDirectory
                 installDistDir <- buildPath context
@@ -206,8 +207,6 @@ installPackages = do
                 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal" <.> exe -- HACK?
                 need [ghcCabalInplace]
 
-                let cabalFile = pkgCabalFile pkg
-
                 pkgConf <- pkgConfFile context
                 need [cabalFile, pkgConf] -- TODO: check if need pkgConf
 
index d261554..dd59018 100644 (file)
@@ -61,7 +61,7 @@ buildPackageLibrary context@Context {..} = do
         if isLib0 then build $ target context (Ar stage) []   [a] -- TODO: Scan for dlls
                   else build $ target context (Ar stage) objs [a]
 
-        synopsis <- pkgSynopsis package
+        synopsis <- traverse pkgSynopsis (pkgCabalFile package)
         unless isLib0 . putSuccess $ renderLibrary
             (quote (pkgName package) ++ " (" ++ show stage ++ ", way "
             ++ show way ++ ").") a synopsis
index 5fad4b2..1d536da 100644 (file)
@@ -105,6 +105,6 @@ buildBinary rs context@Context {..} bin = do
                   ++ [ path -/- "Paths_haddock.o" | package == haddock ]
     need binDeps
     buildWithResources rs $ target context (Ghc LinkHs stage) binDeps [bin]
-    synopsis <- pkgSynopsis package
+    synopsis <- traverse pkgSynopsis (pkgCabalFile package)
     putSuccess $ renderProgram
         (quote (pkgName package) ++ " (" ++ show stage ++ ").") bin synopsis
index 8c2efb1..50bdd6e 100644 (file)
@@ -117,9 +117,8 @@ wayGhcArgs = do
 
 -- FIXME: Get rid of to-be-deprecated -this-package-key.
 packageGhcArgs :: Args
-packageGhcArgs = do
-    pkg     <- getPackage
-    pkgId   <- expr $ pkgIdentifier pkg
+packageGhcArgs = withHsPackage $ \cabalFile -> do
+    pkgId   <- expr $ pkgIdentifier cabalFile
     thisArg <- do
         not0 <- notStage0
         unit <- expr $ flag SupportsThisUnitId
index cf6bcb3..0e7750e 100644 (file)
@@ -94,9 +94,9 @@ bootPackageConstraints :: Args
 bootPackageConstraints = stage0 ? do
     bootPkgs <- expr $ stagePackages Stage0
     let pkgs = filter (\p -> p /= compiler && isLibrary p) bootPkgs
-    constraints <- expr $ forM (sort pkgs) $ \pkg -> do
-        version <- pkgVersion pkg
-        return (pkgName pkg ++ " == " ++ version)
+    constraints <- expr $ fmap catMaybes $ forM (sort pkgs) $ \pkg -> do
+        version <- traverse pkgVersion (pkgCabalFile pkg)
+        return $ fmap ((pkgName pkg ++ " == ") ++) version
     pure $ concat [ ["--constraint", c] | c <- constraints ]
 
 cppArgs :: Args
index 834190e..9e410a1 100644 (file)
@@ -14,15 +14,15 @@ versionToInt s = case map read . words $ replaceEq '.' ' ' s of
     _                     -> error "versionToInt: cannot parse version."
 
 haddockBuilderArgs :: Args
-haddockBuilderArgs = builder Haddock ? do
+haddockBuilderArgs = withHsPackage $ \cabalFile -> builder Haddock ? do
     output   <- getOutput
     pkg      <- getPackage
     path     <- getBuildPath
-    version  <- expr $ pkgVersion pkg
-    synopsis <- fromMaybe "" <$> expr (pkgSynopsis pkg)
+    version  <- expr $ pkgVersion  cabalFile
+    synopsis <- expr $ pkgSynopsis cabalFile
     deps     <- getPkgDataList Deps
     haddocks <- expr . haddockDependencies =<< getContext
-    hVersion <- expr $ pkgVersion haddock
+    hVersion <- expr $ pkgVersion (unsafePkgCabalFile haddock) -- TODO: improve
     ghcOpts  <- haddockGhcArgs
     mconcat
         [ arg $ "--odir=" ++ takeDirectory output
index dba4f9b..2c3da00 100644 (file)
@@ -10,7 +10,7 @@ import Utilities
 ghcCabalPackageArgs :: Args
 ghcCabalPackageArgs = stage0 ? package ghcCabal ? builder Ghc ? do
     cabalDeps    <- expr $ stage1Dependencies cabal
-    cabalVersion <- expr $ pkgVersion cabal
+    cabalVersion <- expr $ pkgVersion (unsafePkgCabalFile cabal) -- TODO: improve
     mconcat
         [ pure [ "-package " ++ pkgName pkg | pkg <- cabalDeps, pkg /= parsec ]
         , arg "--make"
index ab8dedb..92c2465 100644 (file)
@@ -190,11 +190,11 @@ runBuilderWith options builder args = do
 -- dependencies we scan package @.cabal@ files, see 'pkgDependencies' defined
 -- in "Hadrian.Haskell.Cabal".
 contextDependencies :: Context -> Action [Context]
-contextDependencies Context {..} = do
-    exists <- doesFileExist (pkgCabalFile package)
-    if not exists then return [] else do
+contextDependencies Context {..} = case pkgCabalFile package of
+    Nothing        -> return [] -- Non-Cabal packages have no dependencies.
+    Just cabalFile -> do
         let pkgContext = \pkg -> Context (min stage Stage1) pkg way
-        deps <- pkgDependencies package
+        deps <- pkgDependencies cabalFile
         pkgs <- sort <$> interpretInContext (pkgContext package) getPackages
         return . map pkgContext $ intersectOrd (compare . pkgName) pkgs deps