Bump Cabal upper bound (#651)
[hadrian.git] / src / Rules.hs
1 module Rules (buildRules, oracleRules, packageTargets, topLevelTargets) where
2
3 import qualified Hadrian.Oracles.ArgsHash
4 import qualified Hadrian.Oracles.DirectoryContents
5 import qualified Hadrian.Oracles.Path
6 import qualified Hadrian.Oracles.TextFile
7
8 import Expression
9 import GHC
10 import qualified Oracles.ModuleFiles
11 import qualified Rules.BinaryDist
12 import qualified Rules.Compile
13 import qualified Rules.Configure
14 import qualified Rules.Dependencies
15 import qualified Rules.Documentation
16 import qualified Rules.Generate
17 import qualified Rules.Gmp
18 import qualified Rules.Libffi
19 import qualified Rules.Library
20 import qualified Rules.Program
21 import qualified Rules.Register
22 import Settings
23 import Target
24 import Utilities
25
26 allStages :: [Stage]
27 allStages = [minBound .. maxBound]
28
29 -- | This rule calls 'need' on all top-level build targets, respecting the
30 -- 'Stage1Only' flag.
31 topLevelTargets :: Rules ()
32 topLevelTargets = action $ do
33 (programs, libraries) <- partition isProgram <$> stagePackages Stage1
34 pgmNames <- mapM (g Stage1) programs
35 libNames <- mapM (g Stage1) libraries
36
37 verbosity <- getVerbosity
38 when (verbosity >= Loud) $ do
39 putNormal "Building stage2"
40 putNormal . unlines $
41 [ "| Building Programs : " ++ intercalate ", " pgmNames
42 , "| Building Libraries: " ++ intercalate ", " libNames ]
43
44 targets <- mapM (f Stage1) =<< stagePackages Stage1
45 need targets
46 where
47 -- either the package database config file for libraries or
48 -- the programPath for programs. However this still does
49 -- not support multiple targets, where a cabal package has
50 -- a library /and/ a program.
51 f :: Stage -> Package -> Action FilePath
52 f stage pkg | isLibrary pkg = pkgConfFile (Context stage pkg (read "v"))
53 | otherwise = programPath =<< programContext stage pkg
54 g :: Stage -> Package -> Action String
55 g stage pkg | isLibrary pkg = return $ pkgName pkg
56 | otherwise = programName (Context stage pkg (read "v"))
57
58 -- TODO: Get rid of the @includeGhciLib@ hack.
59 -- | Return the list of targets associated with a given 'Stage' and 'Package'.
60 -- By setting the Boolean parameter to False it is possible to exclude the GHCi
61 -- library from the targets, and avoid running @ghc-cabal@ to determine whether
62 -- GHCi library needs to be built for this package. We typically want to set
63 -- this parameter to True, however it is important to set it to False when
64 -- computing 'topLevelTargets', as otherwise the whole build gets sequentialised
65 -- because we need to run @ghc-cabal@ in the order respecting package dependencies.
66 packageTargets :: Bool -> Stage -> Package -> Action [FilePath]
67 packageTargets includeGhciLib stage pkg = do
68 let context = vanillaContext stage pkg
69 activePackages <- stagePackages stage
70 if pkg `notElem` activePackages
71 then return [] -- Skip inactive packages.
72 else if isLibrary pkg
73 then do -- Collect all targets of a library package.
74 let pkgWays = if pkg == rts then getRtsWays else getLibraryWays
75 ways <- interpretInContext context pkgWays
76 libs <- mapM (pkgLibraryFile . Context stage pkg) ways
77 more <- libraryTargets includeGhciLib context
78 setup <- pkgSetupConfigFile context
79 return $ [ setup | not (nonCabalContext context) ] ++ libs ++ more
80 else do -- The only target of a program package is the executable.
81 prgContext <- programContext stage pkg
82 prgPath <- programPath prgContext
83 return [prgPath]
84
85 packageRules :: Rules ()
86 packageRules = do
87 -- We cannot register multiple GHC packages in parallel. Also we cannot run
88 -- GHC when the package database is being mutated by "ghc-pkg". This is a
89 -- classic concurrent read exclusive write (CREW) conflict.
90 let maxConcurrentReaders = 1000
91 packageDb <- newResource "package-db" maxConcurrentReaders
92 let readPackageDb = [(packageDb, 1)]
93 writePackageDb = [(packageDb, maxConcurrentReaders)]
94
95 let contexts = liftM3 Context allStages knownPackages allWays
96 vanillaContexts = liftM2 vanillaContext allStages knownPackages
97
98 -- TODO: we might want to look into converting more and more
99 -- rules to the style introduced in Rules.Library in
100 -- https://github.com/snowleopard/hadrian/pull/571,
101 -- where "catch-all" rules are used to "catch" the need
102 -- for library files, and we then use parsec parsers to
103 -- extract all sorts of information needed to build them, like
104 -- the package, the stage, the way, etc.
105
106 forM_ contexts (Rules.Compile.compilePackage readPackageDb)
107
108 Rules.Program.buildProgram readPackageDb
109
110 forM_ [Stage0 .. ] $ \stage ->
111 -- we create a dummy context, that has the correct state, but contains
112 -- @dummyPackage@ as a... dummy package. The package isn't accessed but the record
113 -- need to be set properly. @undefined@ is not an option as it ends up
114 -- being forced.
115 Rules.Register.registerPackage writePackageDb (Context stage dummyPackage vanilla)
116
117 forM_ vanillaContexts $ mconcat
118 [ Rules.Register.configurePackage
119 , Rules.Dependencies.buildPackageDependencies readPackageDb
120 , Rules.Documentation.buildPackageDocumentation
121 , Rules.Generate.generatePackageCode ]
122
123 buildRules :: Rules ()
124 buildRules = do
125 Rules.BinaryDist.bindistRules
126 Rules.Configure.configureRules
127 Rules.Generate.copyRules
128 Rules.Generate.generateRules
129 Rules.Gmp.gmpRules
130 Rules.Libffi.libffiRules
131 Rules.Library.libraryRules
132 packageRules
133
134 oracleRules :: Rules ()
135 oracleRules = do
136 Hadrian.Oracles.ArgsHash.argsHashOracle trackArgument getArgs
137 Hadrian.Oracles.DirectoryContents.directoryContentsOracle
138 Hadrian.Oracles.Path.pathOracle
139 Hadrian.Oracles.TextFile.textFileOracle
140 Oracles.ModuleFiles.moduleFilesOracle