Use Cabal directly in place of ghc-cabal + make build root configurable (#531)
[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.Compile
12 import qualified Rules.PackageData
13 import qualified Rules.Dependencies
14 import qualified Rules.Documentation
15 import qualified Rules.Generate
16 import qualified Rules.Configure
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
45 targets <- mapM (f Stage1) =<< stagePackages Stage1
46 need targets
47
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 f :: Stage -> Package -> Action FilePath
54 f stage pkg | isLibrary pkg = pkgConfFile (Context stage pkg (read "v"))
55 | otherwise = programPath =<< programContext stage pkg
56 g :: Stage -> Package -> Action String
57 g stage pkg | isLibrary pkg = return $ pkgName pkg
58 | otherwise = programName (Context stage pkg (read "v"))
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 running @ghc-cabal@ to determine whether
64 -- GHCi library needs to be built for this package. 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 we need to run @ghc-cabal@ in the order respecting package 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 | not (nonCabalContext context) ] ++ 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 let contexts = liftM3 Context allStages knownPackages allWays
98 vanillaContexts = liftM2 vanillaContext allStages knownPackages
99
100 forM_ contexts $ mconcat
101 [ Rules.Compile.compilePackage readPackageDb
102 , Rules.Library.buildPackageLibrary ]
103
104 let dynamicContexts = liftM3 Context [Stage1 ..] knownPackages [dynamic]
105 forM_ dynamicContexts Rules.Library.buildDynamicLib
106
107 Rules.Program.buildProgram readPackageDb
108
109 forM_ [Stage0 .. ] $ \stage -> do
110 -- we create a dummy context, that has the correct state, but contains
111 -- @dummyPackage@ as a... dummy package. The package isn't accessed but the record
112 -- need to be set properly. @undefined@ is not an option as it ends up
113 -- being forced.
114 Rules.Register.registerPackages writePackageDb (Context stage dummyPackage vanilla)
115
116 forM_ vanillaContexts $ mconcat
117 [ Rules.PackageData.buildPackageData
118 , Rules.Dependencies.buildPackageDependencies readPackageDb
119 , Rules.Documentation.buildPackageDocumentation
120 , Rules.Library.buildPackageGhciLibrary
121 , Rules.Generate.generatePackageCode ]
122
123 buildRules :: Rules ()
124 buildRules = do
125 Rules.Configure.configureRules
126 Rules.Generate.copyRules
127 Rules.Generate.generateRules
128 Rules.Gmp.gmpRules
129 Rules.Libffi.libffiRules
130 packageRules
131
132 oracleRules :: Rules ()
133 oracleRules = do
134 Hadrian.Oracles.ArgsHash.argsHashOracle trackArgument getArgs
135 Hadrian.Oracles.DirectoryContents.directoryContentsOracle
136 Hadrian.Oracles.Path.pathOracle
137 Hadrian.Oracles.TextFile.textFileOracle
138 Oracles.ModuleFiles.moduleFilesOracle