hadrian: eliminate most of the remaining big rule enumerations
[ghc.git] / hadrian / src / Rules.hs
1 module Rules (buildRules, oracleRules, packageTargets, topLevelTargets) where
2
3 import qualified Hadrian.Oracles.ArgsHash
4 import qualified Hadrian.Oracles.Cabal.Rules
5 import qualified Hadrian.Oracles.DirectoryContents
6 import qualified Hadrian.Oracles.Path
7 import qualified Hadrian.Oracles.TextFile
8
9 import Expression
10 import qualified Oracles.ModuleFiles
11 import Packages
12 import qualified Rules.BinaryDist
13 import qualified Rules.Compile
14 import qualified Rules.Configure
15 import qualified Rules.Dependencies
16 import qualified Rules.Documentation
17 import qualified Rules.Generate
18 import qualified Rules.Gmp
19 import qualified Rules.Libffi
20 import qualified Rules.Library
21 import qualified Rules.Program
22 import qualified Rules.Register
23 import Settings
24 import Target
25 import UserSettings
26 import Utilities
27
28 allStages :: [Stage]
29 allStages = [minBound .. maxBound]
30
31 -- | This rule calls 'need' on all top-level build targets that Hadrian builds
32 -- by default, respecting the 'stage1Only' flag.
33 topLevelTargets :: Rules ()
34 topLevelTargets = action $ do
35 verbosity <- getVerbosity
36 when (verbosity >= Loud) $ do
37 (libraries, programs) <- partition isLibrary <$> stagePackages Stage1
38 libNames <- mapM (name Stage1) libraries
39 pgmNames <- mapM (name Stage1) programs
40 putNormal . unlines $
41 [ "| Building Stage1 libraries: " ++ intercalate ", " libNames
42 , "| Building Stage1 programs : " ++ intercalate ", " pgmNames ]
43 let buildStages = [Stage0, Stage1] ++ [Stage2 | not stage1Only]
44 targets <- concatForM buildStages $ \stage -> do
45 packages <- stagePackages stage
46 mapM (path stage) packages
47 need targets
48 where
49 -- either the package database config file for libraries or
50 -- the programPath for programs. However this still does
51 -- not support multiple targets, where a cabal package has
52 -- a library /and/ a program.
53 path :: Stage -> Package -> Action FilePath
54 path stage pkg | isLibrary pkg = pkgConfFile (vanillaContext stage pkg)
55 | otherwise = programPath =<< programContext stage pkg
56 name :: Stage -> Package -> Action String
57 name stage pkg | isLibrary pkg = return (pkgName pkg)
58 | otherwise = programName (vanillaContext stage pkg)
59
60 -- TODO: Get rid of the @includeGhciLib@ hack.
61 -- | Return the list of targets associated with a given 'Stage' and 'Package'.
62 -- By setting the Boolean parameter to False it is possible to exclude the GHCi
63 -- library from the targets, and avoid configuring the package to determine
64 -- whether GHCi library needs to be built for it. We typically want to set
65 -- this parameter to True, however it is important to set it to False when
66 -- computing 'topLevelTargets', as otherwise the whole build gets sequentialised
67 -- because packages are configured in the order respecting their dependencies.
68 packageTargets :: Bool -> Stage -> Package -> Action [FilePath]
69 packageTargets includeGhciLib stage pkg = do
70 let context = vanillaContext stage pkg
71 activePackages <- stagePackages stage
72 if pkg `notElem` activePackages
73 then return [] -- Skip inactive packages.
74 else if isLibrary pkg
75 then do -- Collect all targets of a library package.
76 let pkgWays = if pkg == rts then getRtsWays else getLibraryWays
77 ways <- interpretInContext context pkgWays
78 libs <- mapM (pkgLibraryFile . Context stage pkg) ways
79 more <- libraryTargets includeGhciLib context
80 setup <- pkgSetupConfigFile context
81 return $ [setup] ++ libs ++ more
82 else do -- The only target of a program package is the executable.
83 prgContext <- programContext stage pkg
84 prgPath <- programPath prgContext
85 return [prgPath]
86
87 packageRules :: Rules ()
88 packageRules = do
89 -- We cannot register multiple GHC packages in parallel. Also we cannot run
90 -- GHC when the package database is being mutated by "ghc-pkg". This is a
91 -- classic concurrent read exclusive write (CREW) conflict.
92 let maxConcurrentReaders = 1000
93 packageDb <- newResource "package-db" maxConcurrentReaders
94 let readPackageDb = [(packageDb, 1)]
95 writePackageDb = [(packageDb, maxConcurrentReaders)]
96
97 Rules.Compile.compilePackage readPackageDb
98 Rules.Dependencies.buildPackageDependencies readPackageDb
99 Rules.Documentation.buildPackageDocumentation
100 Rules.Program.buildProgramRules readPackageDb
101 Rules.Register.configurePackageRules
102
103 forM_ [Stage0, Stage1] (Rules.Register.registerPackageRules writePackageDb)
104
105 -- TODO: Can we get rid of this enumeration of contexts? Since we iterate
106 -- over it to generate all 4 types of rules below, all the time, we
107 -- might want to see whether the parse-and-extract approach of
108 -- Rules.Compile and Rules.Library could save us some time there.
109 let vanillaContexts = liftM2 vanillaContext allStages knownPackages
110
111 forM_ vanillaContexts Rules.Generate.generatePackageCode
112
113 buildRules :: Rules ()
114 buildRules = do
115 Rules.BinaryDist.bindistRules
116 Rules.Configure.configureRules
117 Rules.Generate.copyRules
118 Rules.Generate.generateRules
119 Rules.Gmp.gmpRules
120 Rules.Libffi.libffiRules
121 Rules.Library.libraryRules
122 packageRules
123
124 oracleRules :: Rules ()
125 oracleRules = do
126 Hadrian.Oracles.ArgsHash.argsHashOracle trackArgument getArgs
127 Hadrian.Oracles.Cabal.Rules.cabalOracle
128 Hadrian.Oracles.DirectoryContents.directoryContentsOracle
129 Hadrian.Oracles.Path.pathOracle
130 Hadrian.Oracles.TextFile.textFileOracle
131 Oracles.ModuleFiles.moduleFilesOracle