Use Cabal directly in place of ghc-cabal + make build root configurable (#531)
[hadrian.git] / src / Rules / Documentation.hs
1 module Rules.Documentation (
2 -- * Rules
3 buildPackageDocumentation, documentationRules,
4
5 -- * Utilities
6 haddockDependencies
7 ) where
8
9 import Base
10 import Context
11 import Expression (getPackageData, interpretInContext)
12 import Flavour
13 import GHC
14 import Oracles.ModuleFiles
15 import Settings
16 import Target
17 import Utilities
18
19 import qualified Hadrian.Haskell.Cabal.PackageData as PD
20
21 -- | Build all documentation
22 documentationRules :: Rules ()
23 documentationRules = do
24 root <- buildRootRules
25 buildHtmlDocumentation
26 buildPdfDocumentation
27 buildDocumentationArchives
28 buildManPage
29 root -/- htmlRoot -/- "libraries/gen_contents_index" %> copyFile "libraries/gen_contents_index"
30 root -/- htmlRoot -/- "libraries/prologue.txt" %> copyFile "libraries/prologue.txt"
31 "docs" ~> do
32 root <- buildRoot
33 let html = htmlRoot -/- "index.html"
34 archives = map pathArchive docPaths
35 pdfs = map pathPdf $ docPaths \\ [ "libraries" ]
36 need $ map (root -/-) $ [html] ++ archives ++ pdfs
37 need [ root -/- htmlRoot -/- "libraries" -/- "gen_contents_index"
38 , root -/- htmlRoot -/- "libraries" -/- "prologue.txt"
39 , root -/- manPageBuildPath
40 ]
41
42 manPageBuildPath :: FilePath
43 manPageBuildPath = "docs/users_guide/build-man/ghc.1"
44
45 -- TODO: Add support for Documentation Packages so we can
46 -- run the builders without this hack.
47 docPackage :: Package
48 docPackage = hsLibrary "Documentation" "docs"
49
50 docPaths :: [FilePath]
51 docPaths = [ "libraries", "users_guide", "Haddock" ]
52
53 docRoot :: FilePath
54 docRoot = "docs"
55
56 htmlRoot :: FilePath
57 htmlRoot = docRoot -/- "html"
58
59 pdfRoot :: FilePath
60 pdfRoot = docRoot -/- "pdfs"
61
62 archiveRoot :: FilePath
63 archiveRoot = docRoot -/- "archives"
64
65 pathPdf :: FilePath -> FilePath
66 pathPdf path = pdfRoot -/- path <.> ".pdf"
67
68 pathIndex :: FilePath -> FilePath
69 pathIndex path = htmlRoot -/- path -/- "index.html"
70
71 pathArchive :: FilePath -> FilePath
72 pathArchive path = archiveRoot -/- path <.> "html.tar.xz"
73
74 -- TODO: Replace this with pkgPath when support is added
75 -- for Documentation Packages.
76 pathPath :: FilePath -> FilePath
77 pathPath "users_guide" = "docs/users_guide"
78 pathPath "Haddock" = "utils/haddock/doc"
79 pathPath _ = ""
80
81 ----------------------------------------------------------------------
82 -- HTML
83
84 -- | Build all HTML documentation
85 buildHtmlDocumentation :: Rules ()
86 buildHtmlDocumentation = do
87 mapM_ buildSphinxHtml $ docPaths \\ [ "libraries" ]
88 buildLibraryDocumentation
89 root <- buildRootRules
90 root -/- htmlRoot -/- "index.html" %> \file -> do
91 root <- buildRoot
92 need $ map ((root -/-) . pathIndex) docPaths
93 copyFileUntracked "docs/index.html" file
94
95 -----------------------------
96 -- Sphinx
97
98 -- | Compile a Sphinx ReStructured Text package to HTML
99 buildSphinxHtml :: FilePath -> Rules ()
100 buildSphinxHtml path = do
101 root <- buildRootRules
102 root -/- htmlRoot -/- path -/- "index.html" %> \file -> do
103 let dest = takeDirectory file
104 context = vanillaContext Stage1 docPackage
105 build $ target context (Sphinx Html) [pathPath path] [dest]
106
107 -----------------------------
108 -- Haddock
109
110 -- | Build the haddocks for GHC's libraries
111 buildLibraryDocumentation :: Rules ()
112 buildLibraryDocumentation = do
113 root <- buildRootRules
114
115 -- Js and Css files for haddock output
116 root -/- haddockHtmlLib %> \d -> do
117 let dir = takeDirectory d
118 liftIO $ removeFiles dir ["//*"]
119 copyDirectory "utils/haddock/haddock-api/resources/html" dir
120
121 root -/- htmlRoot -/- "libraries/index.html" %> \file -> do
122 haddocks <- allHaddocks
123 let libDocs = filter
124 (\x -> takeFileName x `notElem` ["ghc.haddock", "rts.haddock"])
125 haddocks
126 context = vanillaContext Stage1 docPackage
127 need (root -/- haddockHtmlLib : libDocs)
128 build $ target context (Haddock BuildIndex) libDocs [file]
129
130 allHaddocks :: Action [FilePath]
131 allHaddocks = do
132 pkgs <- stagePackages Stage1
133 sequence [ pkgHaddockFile $ vanillaContext Stage1 pkg
134 | pkg <- pkgs, isLibrary pkg, isHsPackage pkg ]
135
136 haddockHtmlLib ::FilePath
137 haddockHtmlLib = "docs/html/haddock-bundle.min.js"
138
139 -- | Find the haddock files for the dependencies of the current library
140 haddockDependencies :: Context -> Action [FilePath]
141 haddockDependencies context = do
142 depNames <- interpretInContext context (getPackageData PD.depNames)
143 sequence [ pkgHaddockFile $ vanillaContext Stage1 depPkg
144 | Just depPkg <- map findPackageByName depNames, depPkg /= rts ]
145
146 -- Note: this build rule creates plenty of files, not just the .haddock one.
147 -- All of them go into the 'doc' subdirectory. Pedantically tracking all built
148 -- files in the Shake database seems fragile and unnecessary.
149 buildPackageDocumentation :: Context -> Rules ()
150 buildPackageDocumentation context@Context {..} = when (stage == Stage1 && package /= rts) $ do
151 root <- buildRootRules
152
153 -- Per-package haddocks
154 root -/- htmlRoot -/- "libraries" -/- pkgName package -/- "haddock-prologue.txt" %> \file -> do
155 -- this is how ghc-cabal produces "haddock-prologue.txt" files
156 (syn, desc) <- interpretInContext context . getPackageData $ \p ->
157 (PD.synopsis p, PD.description p)
158 let prologue = if null desc
159 then syn
160 else desc
161 liftIO (writeFile file prologue)
162
163 root -/- htmlRoot -/- "libraries" -/- pkgName package -/- pkgName package <.> "haddock" %> \file -> do
164 need [ root -/- htmlRoot -/- "libraries" -/- pkgName package -/- "haddock-prologue.txt" ]
165 haddocks <- haddockDependencies context
166 srcs <- hsSources context
167 need $ srcs ++ haddocks ++ [root -/- haddockHtmlLib]
168
169 -- Build Haddock documentation
170 -- TODO: pass the correct way from Rules via Context
171 dynamicPrograms <- dynamicGhcPrograms <$> flavour
172 let haddockWay = if dynamicPrograms then dynamic else vanilla
173 build $ target (context {way = haddockWay}) (Haddock BuildPackage)
174 srcs [file]
175
176 ----------------------------------------------------------------------
177 -- PDF
178
179 -- | Build all PDF documentation
180 buildPdfDocumentation :: Rules ()
181 buildPdfDocumentation = mapM_ buildSphinxPdf docPaths
182
183 -- | Compile a Sphinx ReStructured Text package to LaTeX
184 buildSphinxPdf :: FilePath -> Rules ()
185 buildSphinxPdf path = do
186 root <- buildRootRules
187 root -/- pdfRoot -/- path <.> "pdf" %> \file -> do
188 let context = vanillaContext Stage1 docPackage
189 withTempDir $ \dir -> do
190 build $ target context (Sphinx Latex) [pathPath path] [dir]
191 build $ target context Xelatex [path <.> "tex"] [dir]
192 copyFileUntracked (dir -/- path <.> "pdf") file
193
194 ----------------------------------------------------------------------
195 -- Archive
196
197 -- | Build archives of documentation
198 buildDocumentationArchives :: Rules ()
199 buildDocumentationArchives = mapM_ buildArchive docPaths
200
201 buildArchive :: FilePath -> Rules ()
202 buildArchive path = do
203 root <- buildRootRules
204 root -/- pathArchive path %> \file -> do
205 root <- buildRoot
206 let context = vanillaContext Stage1 docPackage
207 src = root -/- pathIndex path
208 need [src]
209 build $ target context (Tar Create) [takeDirectory src] [file]
210
211 -- | build man page
212 buildManPage :: Rules ()
213 buildManPage = do
214 root <- buildRootRules
215 root -/- manPageBuildPath %> \file -> do
216 need ["docs/users_guide/ghc.rst"]
217 let context = vanillaContext Stage1 docPackage
218 withTempDir $ \dir -> do
219 build $ target context (Sphinx Man) ["docs/users_guide"] [dir]
220 copyFileUntracked (dir -/- "ghc.1") file