Refactor Libffi and RTS rules
[ghc.git] / hadrian / src / Rules.hs
1 module Rules (buildRules, oracleRules, packageTargets, topLevelTargets
2 , toolArgsTarget ) where
3
4 import qualified Hadrian.Oracles.ArgsHash
5 import qualified Hadrian.Oracles.Cabal.Rules
6 import qualified Hadrian.Oracles.DirectoryContents
7 import qualified Hadrian.Oracles.Path
8 import qualified Hadrian.Oracles.TextFile
9
10 import Expression
11 import qualified Oracles.ModuleFiles
12 import Packages
13 import qualified Rules.BinaryDist
14 import qualified Rules.Compile
15 import qualified Rules.Configure
16 import qualified Rules.Dependencies
17 import qualified Rules.Documentation
18 import qualified Rules.Generate
19 import qualified Rules.Gmp
20 import qualified Rules.Libffi
21 import qualified Rules.Library
22 import qualified Rules.Program
23 import qualified Rules.Register
24 import qualified Rules.Rts
25 import qualified Rules.SimpleTargets
26 import Settings
27 import Target
28 import UserSettings
29
30
31 -- | @tool-args@ is used by tooling in order to get the arguments necessary
32 -- to set up a GHC API session which can compile modules from GHC. When
33 -- run, the target prints out the arguments that would be passed to @ghc@
34 -- during normal compilation to @stdout@.
35 --
36 -- This target is called by the `ghci.sh` script in order to load all of GHC's
37 -- modules into GHCi.
38 toolArgsTarget :: Rules ()
39 toolArgsTarget = do
40 "tool-args" ~> do
41 let fake_target = target (Context Stage0 compiler dynamic)
42 (Ghc ToolArgs Stage0) [] ["ignored"]
43
44 -- need the autogenerated files so that they are precompiled
45 generatedGhcDependencies Stage0 >>= need
46 interpret fake_target Rules.Generate.compilerDependencies >>= need
47
48 root <- buildRoot
49 let dir = buildDir (vanillaContext Stage0 compiler)
50 need [ root <//> dir -/- "Config.hs" ]
51 need [ root <//> dir -/- "Fingerprint.hs" ]
52 need [ root <//> dir -/- "Parser.hs" ]
53 need [ root <//> dir -/- "Lexer.hs" ]
54 need [ root <//> dir -/- "CmmParse.hs" ]
55 need [ root <//> dir -/- "CmmLex.hs" ]
56
57 -- Find out the arguments that are needed to load a module into the
58 -- session
59 arg_list <- interpret fake_target getArgs
60 liftIO $ putStrLn (intercalate " " arg_list)
61
62 allStages :: [Stage]
63 allStages = [minBound .. maxBound]
64
65 -- | This rule calls 'need' on all top-level build targets that Hadrian builds
66 -- by default, respecting the 'finalStage' flag.
67 topLevelTargets :: Rules ()
68 topLevelTargets = action $ do
69 verbosity <- getVerbosity
70 forM_ [ Stage1 ..] $ \stage -> do
71 when (verbosity >= Loud) $ do
72 (libraries, programs) <- partition isLibrary <$> stagePackages stage
73 libNames <- mapM (name stage) libraries
74 pgmNames <- mapM (name stage) programs
75 let stageHeader t ps =
76 "| Building " ++ show stage ++ " "
77 ++ t ++ ": " ++ intercalate ", " ps
78 putNormal . unlines $
79 [ stageHeader "libraries" libNames
80 , stageHeader "programs" pgmNames ]
81 let buildStages = [ s | s <- [Stage0 ..], s < finalStage ]
82 targets <- concatForM buildStages $ \stage -> do
83 packages <- stagePackages stage
84 mapM (path stage) packages
85
86 -- Why we need wrappers: https://gitlab.haskell.org/ghc/ghc/issues/16534.
87 root <- buildRoot
88 let wrappers = [ root -/- ("ghc-" ++ stageString s) | s <- [Stage1 ..]
89 , s < finalStage ]
90 need (targets ++ wrappers)
91 where
92 -- either the package database config file for libraries or
93 -- the programPath for programs. However this still does
94 -- not support multiple targets, where a cabal package has
95 -- a library /and/ a program.
96 path :: Stage -> Package -> Action FilePath
97 path stage pkg | isLibrary pkg = pkgConfFile (vanillaContext stage pkg)
98 | otherwise = programPath =<< programContext stage pkg
99 name :: Stage -> Package -> Action String
100 name stage pkg | isLibrary pkg = return (pkgName pkg)
101 | otherwise = programName (vanillaContext stage pkg)
102
103 -- TODO: Get rid of the @includeGhciLib@ hack.
104 -- | Return the list of targets associated with a given 'Stage' and 'Package'.
105 -- By setting the Boolean parameter to False it is possible to exclude the GHCi
106 -- library from the targets, and avoid configuring the package to determine
107 -- whether GHCi library needs to be built for it. We typically want to set
108 -- this parameter to True, however it is important to set it to False when
109 -- computing 'topLevelTargets', as otherwise the whole build gets sequentialised
110 -- because packages are configured in the order respecting their dependencies.
111 packageTargets :: Bool -> Stage -> Package -> Action [FilePath]
112 packageTargets includeGhciLib stage pkg = do
113 let context = vanillaContext stage pkg
114 activePackages <- stagePackages stage
115 if pkg `notElem` activePackages
116 then return [] -- Skip inactive packages.
117 else if isLibrary pkg
118 then do -- Collect all targets of a library package.
119 let pkgWays = if pkg == rts then getRtsWays else getLibraryWays
120 ways <- interpretInContext context pkgWays
121 libs <- mapM (pkgLibraryFile . Context stage pkg) ways
122 more <- Rules.Library.libraryTargets includeGhciLib context
123 setupConfig <- pkgSetupConfigFile context
124 return $ [setupConfig] ++ libs ++ more
125 else do -- The only target of a program package is the executable.
126 prgContext <- programContext stage pkg
127 prgPath <- programPath prgContext
128 return [prgPath]
129
130 packageRules :: Rules ()
131 packageRules = do
132 -- We cannot register multiple GHC packages in parallel. Also we cannot run
133 -- GHC when the package database is being mutated by "ghc-pkg". This is a
134 -- classic concurrent read exclusive write (CREW) conflict.
135 let maxConcurrentReaders = 1000
136 packageDb <- newResource "package-db" maxConcurrentReaders
137 let readPackageDb = [(packageDb, 1)]
138 writePackageDb = [(packageDb, maxConcurrentReaders)]
139
140 Rules.Compile.compilePackage readPackageDb
141 Rules.Dependencies.buildPackageDependencies readPackageDb
142 Rules.Documentation.buildPackageDocumentation
143 Rules.Program.buildProgramRules readPackageDb
144 Rules.Register.configurePackageRules
145
146 forM_ [Stage0 ..] (Rules.Register.registerPackageRules writePackageDb)
147
148 -- TODO: Can we get rid of this enumeration of contexts? Since we iterate
149 -- over it to generate all 4 types of rules below, all the time, we
150 -- might want to see whether the parse-and-extract approach of
151 -- Rules.Compile and Rules.Library could save us some time there.
152 let vanillaContexts = liftM2 vanillaContext allStages knownPackages
153
154 forM_ vanillaContexts Rules.Generate.generatePackageCode
155 Rules.SimpleTargets.simplePackageTargets
156
157 buildRules :: Rules ()
158 buildRules = do
159 Rules.BinaryDist.bindistRules
160 Rules.Configure.configureRules
161 Rules.Generate.copyRules
162 Rules.Generate.generateRules
163 Rules.Gmp.gmpRules
164 Rules.Libffi.libffiRules
165 Rules.Library.libraryRules
166 Rules.Rts.rtsRules
167 packageRules
168
169 oracleRules :: Rules ()
170 oracleRules = do
171 Hadrian.Oracles.ArgsHash.argsHashOracle trackArgument getArgs
172 Hadrian.Oracles.Cabal.Rules.cabalOracle
173 Hadrian.Oracles.DirectoryContents.directoryContentsOracle
174 Hadrian.Oracles.Path.pathOracle
175 Hadrian.Oracles.TextFile.textFileOracle
176 Oracles.ModuleFiles.moduleFilesOracle