Squashed 'hadrian/' content from commit 438dc57
[ghc.git] / src / Hadrian / Package.hs
1 -----------------------------------------------------------------------------
2 -- |
3 -- Module : Hadrian.Package
4 -- Copyright : (c) Andrey Mokhov 2014-2017
5 -- License : MIT (see the file LICENSE)
6 -- Maintainer : andrey.mokhov@gmail.com
7 -- Stability : experimental
8 --
9 -- A /package/ is a collection of files. We currently only support C and Haskell
10 -- packages and treat a package as either a library or a program. The latter is
11 -- a gross oversimplification as, for example, Haskell packages can be both.
12 -- This works for now, but should be improved in future.
13 -----------------------------------------------------------------------------
14 module Hadrian.Package (
15 -- * Data types
16 Package (..), PackageName, PackageLanguage, PackageType,
17
18 -- * Construction and properties
19 cLibrary, cProgram, hsLibrary, hsProgram,
20 isLibrary, isProgram, isCPackage, isHsPackage,
21
22 -- * Package directory structure
23 pkgCabalFile, unsafePkgCabalFile
24 ) where
25
26 import Data.Maybe
27 import Development.Shake.Classes
28 import Development.Shake.FilePath
29 import GHC.Generics
30 import GHC.Stack
31 import Hadrian.Utilities
32
33 data PackageLanguage = C | Haskell deriving (Generic, Show)
34
35 -- TODO: Make PackageType more precise.
36 -- See https://github.com/snowleopard/hadrian/issues/12.
37 data PackageType = Library | Program deriving (Generic, Show)
38
39 type PackageName = String
40
41 -- TODO: Consider turning Package into a GADT indexed with language and type.
42 data Package = Package {
43 -- | The package language. 'C' and 'Haskell' packages are supported.
44 pkgLanguage :: PackageLanguage,
45 -- | The package type. 'Library' and 'Program' packages are supported.
46 pkgType :: PackageType,
47 -- | The package name. We assume that all packages have different names,
48 -- hence two packages with the same name are considered equal.
49 pkgName :: PackageName,
50 -- | The path to the package source code relative to the root of the build
51 -- system. For example, @libraries/Cabal/Cabal@ and @ghc@ are paths to the
52 -- @Cabal@ and @ghc-bin@ packages in GHC.
53 pkgPath :: FilePath
54 } deriving (Generic, Show)
55
56 instance Eq Package where
57 p == q = pkgName p == pkgName q
58
59 instance Ord Package where
60 compare p q = compare (pkgName p) (pkgName q)
61
62 instance Binary PackageLanguage
63 instance Hashable PackageLanguage
64 instance NFData PackageLanguage
65
66 instance Binary PackageType
67 instance Hashable PackageType
68 instance NFData PackageType
69
70 instance Binary Package
71 instance Hashable Package
72 instance NFData Package
73
74 -- | Construct a C library package.
75 cLibrary :: PackageName -> FilePath -> Package
76 cLibrary = Package C Library
77
78 -- | Construct a C program package.
79 cProgram :: PackageName -> FilePath -> Package
80 cProgram = Package C Program
81
82 -- | Construct a Haskell library package.
83 hsLibrary :: PackageName -> FilePath -> Package
84 hsLibrary = Package Haskell Library
85
86 -- | Construct a Haskell program package.
87 hsProgram :: PackageName -> FilePath -> Package
88 hsProgram = Package Haskell Program
89
90 -- | Is this a library package?
91 isLibrary :: Package -> Bool
92 isLibrary (Package _ Library _ _) = True
93 isLibrary _ = False
94
95 -- | Is this a program package?
96 isProgram :: Package -> Bool
97 isProgram (Package _ Program _ _) = True
98 isProgram _ = False
99
100 -- | Is this a C package?
101 isCPackage :: Package -> Bool
102 isCPackage (Package C _ _ _) = True
103 isCPackage _ = False
104
105 -- | Is this a Haskell package?
106 isHsPackage :: Package -> Bool
107 isHsPackage (Package Haskell _ _ _) = True
108 isHsPackage _ = False
109
110 -- | The path to the Cabal file of a Haskell package, e.g. @ghc/ghc-bin.cabal@,
111 -- or @Nothing@ if the argument is not a Haskell package.
112 pkgCabalFile :: Package -> Maybe FilePath
113 pkgCabalFile p | isHsPackage p = Just $ pkgPath p -/- pkgName p <.> "cabal"
114 | otherwise = Nothing
115
116 -- | Like 'pkgCabalFile' but raises an error on a non-Haskell package.
117 unsafePkgCabalFile :: HasCallStack => Package -> FilePath
118 unsafePkgCabalFile p = fromMaybe (error msg) (pkgCabalFile p)
119 where
120 msg = "[unsafePkgCabalFile] Not a Haskell package: " ++ show p