f1a7454fbbfa99b1c9340512e74fa3f04b8c2b8d
[ghc.git] / hadrian / src / Rules / Documentation.hs
1 module Rules.Documentation (
2 -- * Rules
3 buildPackageDocumentation, documentationRules,
4
5 -- * Utilities
6 haddockDependencies
7 ) where
8
9 import Hadrian.BuildPath
10 import Hadrian.Haskell.Cabal
11 import Hadrian.Haskell.Cabal.Type
12
13 import Rules.Generate (ghcPrimDependencies)
14 import Base
15 import Context
16 import Expression (getContextData, interpretInContext, (?), package)
17 import Flavour
18 import Oracles.ModuleFiles
19 import Packages
20 import Settings
21 import Target
22 import Utilities
23
24 import Data.List (union)
25 import qualified Text.Parsec as Parsec
26
27 docRoot :: FilePath
28 docRoot = "docs"
29
30 htmlRoot :: FilePath
31 htmlRoot = docRoot -/- "html"
32
33 pdfRoot :: FilePath
34 pdfRoot = docRoot -/- "pdfs"
35
36 archiveRoot :: FilePath
37 archiveRoot = docRoot -/- "archives"
38
39 haddockHtmlLib :: FilePath
40 haddockHtmlLib = htmlRoot -/- "haddock-bundle.min.js"
41
42 manPageBuildPath :: FilePath
43 manPageBuildPath = "docs/users_guide/build-man/ghc.1"
44
45 -- TODO: Get rid of this hack.
46 docContext :: Context
47 docContext = vanillaContext Stage2 (library "Documentation" "docs")
48
49 docPaths :: [FilePath]
50 docPaths = ["libraries", "users_guide", "Haddock"]
51
52 pathPdf :: FilePath -> FilePath
53 pathPdf path = pdfRoot -/- path <.> ".pdf"
54
55 pathIndex :: FilePath -> FilePath
56 pathIndex path = htmlRoot -/- path -/- "index.html"
57
58 pathArchive :: FilePath -> FilePath
59 pathArchive path = archiveRoot -/- path <.> "html.tar.xz"
60
61 -- TODO: Get rid of this hack.
62 pathPath :: FilePath -> FilePath
63 pathPath "users_guide" = "docs/users_guide"
64 pathPath "Haddock" = "utils/haddock/doc"
65 pathPath _ = ""
66
67 -- | Build all documentation
68 documentationRules :: Rules ()
69 documentationRules = do
70 buildDocumentationArchives
71 buildHtmlDocumentation
72 buildManPage
73 buildPdfDocumentation
74
75 -- a phony rule that runs Haddock for "Haskell Hierarchical Libraries" and
76 -- the "GHC-API"
77 "docs-haddock" ~> do
78 root <- buildRoot
79 need [ root -/- pathIndex "libraries" ]
80
81 -- a phony rule that runs Haddock, builds the User's guide, builds
82 -- Haddock's manual, and builds man pages
83 "docs" ~> do
84 root <- buildRoot
85 let html = htmlRoot -/- "index.html" -- also implies "docs-haddock"
86 archives = map pathArchive docPaths
87 pdfs = map pathPdf $ docPaths \\ ["libraries"]
88 need $ map (root -/-) $ [html] ++ archives ++ pdfs ++ [manPageBuildPath]
89
90 ------------------------------------- HTML -------------------------------------
91
92 -- | Build rules for HTML documentation.
93 buildHtmlDocumentation :: Rules ()
94 buildHtmlDocumentation = do
95 mapM_ buildSphinxHtml $ docPaths \\ ["libraries"]
96 buildLibraryDocumentation
97 root <- buildRootRules
98
99 root -/- htmlRoot -/- "index.html" %> \file -> do
100 need [root -/- haddockHtmlLib]
101 need $ map ((root -/-) . pathIndex) docPaths
102 copyFileUntracked "docs/index.html" file
103
104 -- | Compile a Sphinx ReStructured Text package to HTML.
105 buildSphinxHtml :: FilePath -> Rules ()
106 buildSphinxHtml path = do
107 root <- buildRootRules
108 root -/- htmlRoot -/- path -/- "index.html" %> \file -> do
109 need [root -/- haddockHtmlLib]
110 let dest = takeDirectory file
111 build $ target docContext (Sphinx Html) [pathPath path] [dest]
112
113 ------------------------------------ Haddock -----------------------------------
114
115 -- | Build the haddocks for GHC's libraries.
116 buildLibraryDocumentation :: Rules ()
117 buildLibraryDocumentation = do
118 root <- buildRootRules
119
120 -- Js and Css files for haddock output
121 root -/- haddockHtmlLib %> \_ ->
122 copyDirectory "utils/haddock/haddock-api/resources/html" (root -/- docRoot)
123
124 -- Building the "Haskell Hierarchical Libraries" index
125 root -/- htmlRoot -/- "libraries/index.html" %> \file -> do
126 need [ root -/- haddockHtmlLib
127 , "libraries/prologue.txt" ]
128
129 -- We want Haddocks for everything except `rts` to be built, but we
130 -- don't want the index to be polluted by stuff from `ghc`-the-library
131 -- (there will be a seperate top-level link to those Haddocks).
132 haddocks <- allHaddocks
133 let neededDocs = filter (\x -> takeFileName x /= "rts.haddock") haddocks
134 libDocs = filter (\x -> takeFileName x /= "ghc.haddock") neededDocs
135
136 need neededDocs
137 build $ target docContext (Haddock BuildIndex) libDocs [file]
138
139 allHaddocks :: Action [FilePath]
140 allHaddocks = do
141 pkgs <- stagePackages Stage1
142 sequence [ pkgHaddockFile $ vanillaContext Stage1 pkg
143 | pkg <- pkgs, isLibrary pkg, pkgName pkg /= "rts" ]
144
145 -- Note: this build rule creates plenty of files, not just the .haddock one.
146 -- All of them go into the 'docRoot' subdirectory. Pedantically tracking all
147 -- built files in the Shake database seems fragile and unnecessary.
148 buildPackageDocumentation :: Rules ()
149 buildPackageDocumentation = do
150 root <- buildRootRules
151
152 -- Per-package haddocks
153 root -/- htmlRoot -/- "libraries/*/haddock-prologue.txt" %> \file -> do
154 ctx <- getPkgDocTarget root file >>= pkgDocContext
155 need [root -/- haddockHtmlLib]
156 -- This is how @ghc-cabal@ used to produces "haddock-prologue.txt" files.
157 syn <- pkgSynopsis (Context.package ctx)
158 desc <- pkgDescription (Context.package ctx)
159 let prologue = if null desc then syn else desc
160 liftIO $ writeFile file prologue
161
162 root -/- htmlRoot -/- "libraries/*/*.haddock" %> \file -> do
163 context <- getPkgDocTarget root file >>= pkgDocContext
164 need [ takeDirectory file -/- "haddock-prologue.txt"]
165 haddocks <- haddockDependencies context
166
167 -- `ghc-prim` has a source file for 'GHC.Prim' which is generated just
168 -- for Haddock. We need to 'union' (instead of '++') to avoid passing
169 -- 'GHC.PrimopWrappers' (which unfortunately shows up in both
170 -- `generatedSrcs` and `vanillaSrcs`) to Haddock twice.
171 generatedSrcs <- interpretInContext context (Expression.package ghcPrim ? ghcPrimDependencies)
172 vanillaSrcs <- hsSources context
173 let srcs = vanillaSrcs `union` generatedSrcs
174
175 need $ srcs ++ haddocks ++ [root -/- haddockHtmlLib]
176
177 -- Build Haddock documentation
178 -- TODO: Pass the correct way from Rules via Context.
179 dynamicPrograms <- dynamicGhcPrograms =<< flavour
180 let haddockWay = if dynamicPrograms then dynamic else vanilla
181 build $ target (context {way = haddockWay}) (Haddock BuildPackage) srcs [file]
182
183 data PkgDocTarget = DotHaddock PackageName | HaddockPrologue PackageName
184 deriving (Eq, Show)
185
186 pkgDocContext :: PkgDocTarget -> Action Context
187 pkgDocContext target = case findPackageByName pkgname of
188 Nothing -> error $ "pkgDocContext: couldn't find package " ++ pkgname
189 Just p -> return (Context Stage1 p vanilla)
190
191 where pkgname = case target of
192 DotHaddock n -> n
193 HaddockPrologue n -> n
194
195 parsePkgDocTarget :: FilePath -> Parsec.Parsec String () PkgDocTarget
196 parsePkgDocTarget root = do
197 _ <- Parsec.string root *> Parsec.optional (Parsec.char '/')
198 _ <- Parsec.string (htmlRoot ++ "/")
199 _ <- Parsec.string "libraries/"
200 pkgname <- Parsec.manyTill Parsec.anyChar (Parsec.char '/')
201 Parsec.choice
202 [ Parsec.try (Parsec.string "haddock-prologue.txt")
203 *> pure (HaddockPrologue pkgname)
204 , Parsec.string (pkgname <.> "haddock")
205 *> pure (DotHaddock pkgname)
206 ]
207
208 getPkgDocTarget :: FilePath -> FilePath -> Action PkgDocTarget
209 getPkgDocTarget root path =
210 parsePath (parsePkgDocTarget root) "<doc target>" path
211
212 -------------------------------------- PDF -------------------------------------
213
214 -- | Build all PDF documentation
215 buildPdfDocumentation :: Rules ()
216 buildPdfDocumentation = mapM_ buildSphinxPdf docPaths
217
218 -- | Compile a Sphinx ReStructured Text package to LaTeX
219 buildSphinxPdf :: FilePath -> Rules ()
220 buildSphinxPdf path = do
221 root <- buildRootRules
222 root -/- pdfRoot -/- path <.> "pdf" %> \file -> do
223 need [root -/- haddockHtmlLib]
224 withTempDir $ \dir -> do
225 build $ target docContext (Sphinx Latex) [pathPath path] [dir]
226 build $ target docContext Xelatex [path <.> "tex"] [dir]
227 copyFileUntracked (dir -/- path <.> "pdf") file
228
229 ------------------------------------ Archive -----------------------------------
230
231 -- | Build documentation archives.
232 buildDocumentationArchives :: Rules ()
233 buildDocumentationArchives = mapM_ buildArchive docPaths
234
235 buildArchive :: FilePath -> Rules ()
236 buildArchive path = do
237 root <- buildRootRules
238 root -/- pathArchive path %> \file -> do
239 need [root -/- haddockHtmlLib]
240 root <- buildRoot
241 let src = root -/- pathIndex path
242 need [src]
243 build $ target docContext (Tar Create) [takeDirectory src] [file]
244
245 -- | Build the man page.
246 buildManPage :: Rules ()
247 buildManPage = do
248 root <- buildRootRules
249 root -/- manPageBuildPath %> \file -> do
250 need [root -/- haddockHtmlLib, "docs/users_guide/ghc.rst"]
251 withTempDir $ \dir -> do
252 build $ target docContext (Sphinx Man) ["docs/users_guide"] [dir]
253 copyFileUntracked (dir -/- "ghc.1") file
254
255 -- | Find the Haddock files for the dependencies of the current library.
256 haddockDependencies :: Context -> Action [FilePath]
257 haddockDependencies context = do
258 depNames <- interpretInContext context (getContextData depNames)
259 sequence [ pkgHaddockFile $ vanillaContext Stage1 depPkg
260 | Just depPkg <- map findPackageByName depNames, depPkg /= rts ]