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