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