Minor clean up, taking hlint suggestions
[ghc.git] / src / Rules / Install.hs
1 module Rules.Install (installRules) where
2
3 import Hadrian.Oracles.DirectoryContents
4 import qualified System.Directory as IO
5
6 import Base
7 import Expression
8 import Oracles.Setting
9 import Rules
10 import Rules.Generate
11 import Rules.Libffi
12 import Rules.Wrappers
13 import Settings
14 import Settings.Packages.Rts
15 import Target
16 import Utilities
17
18 {- | Install the built binaries etc. to the @destDir ++ prefix@.
19
20 The installation prefix is usually @/usr/local@ on a Unix system.
21 The resulting tree structure is organized under @destDir ++ prefix@ as follows:
22
23 * @bin@: executable wrapper scripts, installed by 'installBins', e.g. @ghc@.
24
25 * @lib/ghc-<version>/bin@: executable binaries/scripts,
26 installed by 'installLibExecs' and 'installLibExecScripts'.
27
28 * @lib/ghc-<version>/include@: headers etc., installed by 'installIncludes'.
29
30 * @lib/ghc-<version>/<pkg-name>@: built packages, e.g. @base@, installed
31 by 'installPackages'.
32
33 * @lib/ghc-<version>/settings@ etc.: other files in @lib@ directory,
34 installed by 'installCommonLibs'.
35
36 XXX (izgzhen): Do we need @INSTALL_OPTS@ in the make scripts?
37 -}
38 installRules :: Rules ()
39 installRules =
40 "install" ~> do
41 installIncludes
42 installPackageConf
43 installCommonLibs
44 installLibExecs
45 installLibExecScripts
46 installBins
47 installPackages
48 installDocs
49
50 -- TODO: Get rid of hard-coded list.
51 -- | Binaries to install.
52 installBinPkgs :: [Package]
53 installBinPkgs = [ghc, ghcPkg, ghcSplit, hp2ps, hpc, hsc2hs, runGhc, unlit]
54
55 getLibExecDir :: Action FilePath
56 getLibExecDir = (-/- "bin") <$> installGhcLibDir
57
58 -- ref: ghc.mk
59 -- | Install executable scripts to @prefix/lib/bin@.
60 installLibExecScripts :: Action ()
61 installLibExecScripts = do
62 libExecDir <- getLibExecDir
63 destDir <- getDestDir
64 installDirectory (destDir ++ libExecDir)
65 forM_ libExecScripts $ \script -> installScript script (destDir ++ libExecDir)
66 where
67 libExecScripts :: [FilePath]
68 libExecScripts = [ghcSplitPath]
69
70 -- ref: ghc.mk
71 -- | Install executable binaries to @prefix/lib/bin@.
72 installLibExecs :: Action ()
73 installLibExecs = do
74 libExecDir <- getLibExecDir
75 destDir <- getDestDir
76 installDirectory (destDir ++ libExecDir)
77 forM_ installBinPkgs $ \pkg ->
78 withInstallStage pkg $ \stage -> do
79 context <- programContext stage pkg
80 let bin = inplaceLibBinPath -/- programName context <.> exe
81 installProgram bin (destDir ++ libExecDir)
82 when (pkg == ghc) $
83 moveFile (destDir ++ libExecDir -/- programName context <.> exe)
84 (destDir ++ libExecDir -/- "ghc" <.> exe)
85
86 -- ref: ghc.mk
87 -- | Install executable wrapper scripts to @prefix/bin@.
88 installBins :: Action ()
89 installBins = do
90 binDir <- setting InstallBinDir
91 libDir <- installGhcLibDir
92 destDir <- getDestDir
93 installDirectory (destDir ++ binDir)
94 win <- windowsHost
95 when win $
96 copyDirectoryContents matchAll (destDir ++ libDir -/- "bin") (destDir ++ binDir)
97 unless win $ forM_ installBinPkgs $ \pkg ->
98 withInstallStage pkg $ \stage -> do
99 context <- programContext stage pkg
100 version <- setting ProjectVersion
101 -- Name of the binary file
102 let binName | pkg == ghc = "ghc-" ++ version <.> exe
103 | otherwise = programName context ++ "-" ++ version <.> exe
104 -- Name of the symbolic link
105 let symName | pkg == ghc = "ghc" <.> exe
106 | otherwise = programName context <.> exe
107 case lookup context installWrappers of
108 Nothing -> return ()
109 Just wrapper -> do
110 contents <- interpretInContext context $
111 wrapper (WrappedBinary (destDir ++ libDir) symName)
112 let wrapperPath = destDir ++ binDir -/- binName
113 writeFileChanged wrapperPath contents
114 makeExecutable wrapperPath
115 unlessM windowsHost $
116 linkSymbolic (destDir ++ binDir -/- binName)
117 (destDir ++ binDir -/- symName)
118
119 -- | Perform an action depending on the install stage or do nothing if the
120 -- package is not installed.
121 withInstallStage :: Package -> (Stage -> Action ()) -> Action ()
122 withInstallStage pkg m = do
123 maybeStage <- installStage pkg
124 case maybeStage of { Just stage -> m stage; Nothing -> return () }
125
126 pkgConfInstallPath :: Action FilePath
127 pkgConfInstallPath = buildPath (vanillaContext Stage0 rts) <&> (-/- "package.conf.install")
128
129 -- ref: rules/manual-package-conf.mk
130 -- TODO: Should we use a temporary file instead of pkgConfInstallPath?
131 -- | Install @package.conf.install@ for each package. Note that it will be
132 -- recreated each time.
133 installPackageConf :: Action ()
134 installPackageConf = do
135 let context = vanillaContext Stage0 rts
136 confPath <- pkgConfInstallPath
137 liftIO $ IO.createDirectoryIfMissing True (takeDirectory confPath)
138 build $ target context HsCpp [ pkgPath rts -/- "package.conf.in" ]
139 [ confPath <.> "raw" ]
140 Stdout content <- cmd "grep" [ "-v", "^#pragma GCC"
141 , confPath <.> "raw" ]
142 withTempFile $ \tmp -> do
143 liftIO $ writeFile tmp content
144 Stdout result <- cmd "sed" [ "-e", "s/\"\"//g", "-e", "s/:[ ]*,/: /g", tmp ]
145 liftIO $ writeFile confPath result
146
147 -- ref: ghc.mk
148 -- | Install packages to @prefix/lib@.
149 installPackages :: Action ()
150 installPackages = do
151 confPath <- pkgConfInstallPath
152 need [confPath]
153
154 ghcLibDir <- installGhcLibDir
155 binDir <- setting InstallBinDir
156 destDir <- getDestDir
157
158 -- Install package.conf
159 let installedPackageConf = destDir ++ ghcLibDir -/- "package.conf.d"
160 installDirectory (destDir ++ ghcLibDir)
161 removeDirectory installedPackageConf
162 installDirectory installedPackageConf
163
164 -- Install RTS
165 let rtsDir = destDir ++ ghcLibDir -/- "rts"
166 installDirectory rtsDir
167 ways <- interpretInContext (vanillaContext Stage1 rts) getRtsWays
168 rtsLibs <- mapM (pkgLibraryFile . Context Stage1 rts) ways
169 ffiLibs <- mapM rtsLibffiLibrary ways
170
171 -- TODO: Add dynamic libraries.
172 forM_ (rtsLibs ++ ffiLibs) $ \lib -> installData [lib] rtsDir
173
174 -- TODO: Remove this hack required for @ghc-cabal copy@.
175 -- See https://github.com/snowleopard/hadrian/issues/327.
176 ghcBootPlatformHeader <-
177 buildPath (vanillaContext Stage1 compiler) <&> (-/- "ghc_boot_platform.h")
178 copyFile ghcBootPlatformHeader (pkgPath compiler -/- "ghc_boot_platform.h")
179
180 installPackages <- filterM ((isJust <$>) . installStage)
181 (knownPackages \\ [rts, libffi])
182
183 installLibPkgs <- topsortPackages (filter isLibrary installPackages)
184
185 -- TODO: Figure out what is the root cause of the missing ghc-gmp.h error.
186 copyFile (pkgPath integerGmp -/- "gmp/ghc-gmp.h") (pkgPath integerGmp -/- "ghc-gmp.h")
187
188 forM_ installLibPkgs $ \pkg ->
189 case pkgCabalFile pkg of
190 Nothing -> error $ "Non-Haskell project in installLibPkgs" ++ show pkg
191 Just cabalFile -> withInstallStage pkg $ \stage -> do
192 let context = vanillaContext stage pkg
193 top <- topDirectory
194 installDistDir <- buildPath context
195 let absInstallDistDir = top -/- installDistDir
196
197 need =<< packageTargets True stage pkg
198 docDir <- installDocDir
199 ghclibDir <- installGhcLibDir
200
201 -- Copy over packages
202 strip <- stripCmdPath
203 ways <- interpretInContext context getLibraryWays
204 -- TODO: Remove hard-coded @ghc-cabal@ path.
205 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal" <.> exe
206 need [ghcCabalInplace]
207
208 pkgConf <- pkgConfFile context
209 need [cabalFile, pkgConf] -- TODO: Check if we need 'pkgConf'.
210
211 -- TODO: Drop redundant copies required by @ghc-cabal@.
212 -- See https://github.com/snowleopard/hadrian/issues/318.
213 quietly $ copyDirectoryContentsUntracked (Not excluded)
214 installDistDir (installDistDir -/- "build")
215
216 pref <- setting InstallPrefix
217 unit $ cmd ghcCabalInplace [ "copy"
218 , pkgPath pkg
219 , absInstallDistDir
220 , strip
221 , destDir
222 , pref
223 , ghclibDir
224 , docDir -/- "html/libraries"
225 , unwords (map show ways) ]
226
227 -- Register packages
228 let installedGhcPkgReal = destDir ++ binDir -/- "ghc-pkg" <.> exe
229 installedGhcReal = destDir ++ binDir -/- "ghc" <.> exe
230 -- TODO: Extend GhcPkg builder args to support --global-package-db
231 unit $ cmd installedGhcPkgReal [ "--force", "--global-package-db"
232 , installedPackageConf, "update"
233 , confPath ]
234
235 forM_ installLibPkgs $ \pkg ->
236 withInstallStage pkg $ \stage -> do
237 let context = vanillaContext stage pkg
238 top <- topDirectory
239 installDistDir <- (top -/-) <$> buildPath context
240 -- TODO: better reference to the built inplace binary path
241 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal"
242 pref <- setting InstallPrefix
243 docDir <- installDocDir
244 r <- relocatableBuild
245 unit $ cmd ghcCabalInplace
246 [ "register"
247 , pkgPath pkg
248 , installDistDir
249 , installedGhcReal
250 , installedGhcPkgReal
251 , destDir ++ ghcLibDir
252 , destDir
253 , destDir ++ pref
254 , destDir ++ ghcLibDir
255 , destDir ++ docDir -/- "html/libraries"
256 , if r then "YES" else "NO" ]
257
258 confs <- getDirectoryContents installedPackageConf
259 forM_ confs (\f -> createData $ installedPackageConf -/- f)
260 unit $ cmd installedGhcPkgReal [ "--force", "--global-package-db"
261 , installedPackageConf, "recache" ]
262 where
263 createData f = unit $ cmd "chmod" [ "644", f ]
264 excluded = Or [ Test "//haddock-prologue.txt"
265 , Test "//package-data.mk"
266 , Test "//setup-config"
267 , Test "//inplace-pkg-config"
268 , Test "//build" ]
269
270 -- ref: ghc.mk
271 -- | Install settings etc. files to @prefix/lib@.
272 installCommonLibs :: Action ()
273 installCommonLibs = do
274 ghcLibDir <- installGhcLibDir
275 destDir <- getDestDir
276 installLibsTo inplaceLibCopyTargets (destDir ++ ghcLibDir)
277
278 -- ref: ghc.mk
279 -- | Install library files to some path.
280 installLibsTo :: [FilePath] -> FilePath -> Action ()
281 installLibsTo libs dir = do
282 installDirectory dir
283 forM_ libs $ \lib -> case takeExtension lib of
284 ".a" -> do
285 let out = dir -/- takeFileName lib
286 installData [out] dir
287 runBuilder Ranlib [out] [out] [out]
288 _ -> installData [lib] dir
289
290 -- ref: includes/ghc.mk
291 -- | All header files are in includes/{one of these subdirectories}.
292 includeHSubdirs :: [FilePath]
293 includeHSubdirs = [".", "rts", "rts/prof", "rts/storage", "stg"]
294
295 -- ref: includes/ghc.mk
296 -- | Install header files to @prefix/lib/ghc-<version>/include@.
297 installIncludes :: Action ()
298 installIncludes = do
299 ghclibDir <- installGhcLibDir
300 destDir <- getDestDir
301 let ghcheaderDir = ghclibDir -/- "include"
302 installDirectory (destDir ++ ghcheaderDir)
303 forM_ includeHSubdirs $ \dir -> do
304 installDirectory (destDir ++ ghcheaderDir -/- dir)
305 headers <- getDirectoryFiles ("includes" -/- dir) ["*.h"]
306 installHeader (map (("includes" -/- dir) -/-) headers)
307 (destDir ++ ghcheaderDir -/- dir ++ "/")
308 root <- buildRoot
309 rtsPath <- rtsBuildPath
310 installHeader (fmap (root -/-) includesDependencies ++
311 [root -/- generatedDir -/- "DerivedConstants.h"] ++
312 fmap (rtsPath -/-) libffiDependencies)
313 (destDir ++ ghcheaderDir ++ "/")
314 where
315 installHeader = installData -- they share same arguments
316
317 -- ref: ghc.mk
318 -- | Install documentation to @prefix/share/doc/ghc-<version>@.
319 installDocs :: Action ()
320 installDocs = do
321 destDir <- getDestDir
322 docDir <- installDocDir
323 root <- buildRoot
324 installDirectory (destDir ++ docDir)
325
326 let usersGuide = root -/- "docs/pdfs/users_guide.pdf"
327 whenM (doesFileExist usersGuide) $
328 installData [usersGuide] (destDir ++ docDir)
329
330 let htmlDocDir = destDir ++ docDir -/- "html"
331 installDirectory htmlDocDir
332 installData ["docs/index.html"] htmlDocDir
333
334 forM_ ["Haddock", "libraries", "users_guide"] $ \dirname -> do
335 let dir = root -/- "docs/html" -/- dirname
336 whenM (doesDirectoryExist dir) $ copyDirectory dir htmlDocDir