Add Install Rules (#312)
[hadrian.git] / src / Rules / Install.hs
1 {-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
2 module Rules.Install (installRules) where
3
4 import Base
5 import Target
6 import Context
7 import Predicate hiding (builder)
8 import Settings
9 import Settings.Path
10 import Util
11 import GHC
12 import Rules
13 import Rules.Wrappers (WrappedBinary(..), installWrappers)
14 import Rules.Libffi
15 import Rules.Generate
16 import Settings.Packages.Rts
17 import Oracles.Config.Setting
18 import Oracles.PackageData
19 import Oracles.Path
20
21 import qualified System.Directory.Extra as IO
22
23 {- | Install the built binaries etc. to the @destDir ++ prefix@.
24
25 The installation prefix is usually like @/usr/local@ on Unix system.
26 The resulting tree structure is organized under @destDir ++ prefix@, like below
27
28 * @bin@: executable wrapper scripts, installed by 'installBins', e.g. @ghc@
29 * @lib/ghc-<version>/bin@: executable binaries/scripts,
30 installed by 'installLibExecs' and 'installLibExecScripts'
31 * @lib/ghc-<version>/include@: headers etc., installed by 'installIncludes'
32 * @lib/ghc-<version>/<pkg-name>@: built packages, installed by 'installPackages',
33 e.g. @base@
34 * @lib/ghc-<version>/settings@ etc.: other files in @lib@ path, installed by
35 'installCommonLibs'
36
37 XXX (izgzhen): Do we need @INSTALL_OPTS@ in the make scripts?
38 -}
39 installRules :: Rules ()
40 installRules = do
41 "install" ~> do
42 installPackageConf
43 installIncludes
44 installCommonLibs
45 installLibExecs
46 installLibExecScripts
47 installBins
48 installPackages
49
50 getLibExecDir :: Action FilePath
51 getLibExecDir = (-/- "bin") <$> installGhcLibDir
52
53 -- | Install executable scripts to @prefix/lib/bin@
54 -- ref: ghc.mk
55 installLibExecScripts :: Action ()
56 installLibExecScripts = do
57 need libExecScripts
58 libExecDir <- getLibExecDir
59 installDir (destDir ++ libExecDir)
60 forM_ libExecScripts $ \script -> do
61 installScript script (destDir ++ libExecDir)
62 where
63 libExecScripts :: [FilePath]
64 libExecScripts = [ ghcSplitPath ]
65
66
67 -- | Install executable binaries to @prefix/lib/bin@
68 -- ref: ghc.mk
69 installLibExecs :: Action ()
70 installLibExecs = do
71 libExecDir <- getLibExecDir
72 installDir (destDir ++ libExecDir)
73 forM_ installBinPkgs $ \pkg -> do
74 withLatestBuildStage pkg $ \stg -> do
75 let context = programContext stg pkg
76 let bin = inplaceLibBinPath -/- programName context <.> exe
77 need [bin]
78 installProgram bin (destDir ++ libExecDir)
79 when (pkg == ghc) $ do
80 moveFile (destDir ++ libExecDir -/- programName context <.> exe)
81 (destDir ++ libExecDir -/- "ghc" <.> exe)
82
83 -- | Binaries to install
84 -- TODO: Consider Stage1Only
85 installBinPkgs :: [Package]
86 installBinPkgs =
87 [ ghc, ghcPkg, ghcSplit, hp2ps
88 , hpc, hsc2hs, runGhc, unlit ]
89
90 -- | Install executable wrapper scripts to @prefix/bin@
91 -- ref: ghc.mk
92 installBins :: Action ()
93 installBins = do
94 binDir <- setting InstallBinDir
95 installDir (destDir ++ binDir)
96 forM_ installBinPkgs $ \pkg ->
97 withLatestBuildStage pkg $ \stg -> do
98 let context = programContext stg pkg
99 version <- setting ProjectVersion
100 -- binary's name
101 let binName = if pkg == ghc
102 then "ghc-" ++ version <.> exe
103 else programName context ++ "-" ++ version <.> exe
104 -- symbolic link's name
105 let symName = if pkg == ghc
106 then "ghc" <.> exe
107 else programName context <.> exe
108 case lookup context installWrappers of
109 Nothing -> return ()
110 Just wrapper -> do
111 libDir <- installGhcLibDir
112 contents <- interpretInContext context $
113 wrapper
114 (WrappedBinary (destDir ++ libDir) symName)
115 withTempDir $ \tmp -> do
116 let tmpfile = tmp -/- binName
117 writeFileChanged tmpfile contents
118 installProgram tmpfile (destDir ++ binDir)
119 unlessM windowsHost $
120 linkSymbolic (destDir ++ binDir -/- binName)
121 (destDir ++ binDir -/- symName)
122
123 withLatestBuildStage :: Package -> (Stage -> Action ()) -> Action ()
124 withLatestBuildStage pkg m = do
125 stg' <- latestBuildStage pkg
126 case stg' of
127 Nothing -> return ()
128 Just stg -> m stg
129
130 -- | Install @package.conf.install@ for each package
131 -- Note that each time it will be recreated
132 -- ref: rules/manual-package-conf.mk
133 installPackageConf :: Action ()
134 installPackageConf = do
135 let context = vanillaContext Stage0 rts
136 build $ Target context HsCpp [ pkgPath rts -/- "package.conf.in" ]
137 [ pkgConfInstallPath <.> "raw" ]
138 Stdout out <- cmd ("grep" :: String) [ "-v", "^#pragma GCC"
139 , pkgConfInstallPath <.> "raw" ]
140 withTempFile $ \tmp -> do
141 liftIO $ writeFile tmp out
142 Stdout out' <- cmd ("sed" :: String)
143 [ "-e", "s/\"\"//g", "-e", "s/:[ ]*,/: /g", tmp ]
144 liftIO $ writeFile pkgConfInstallPath out'
145
146 -- | Install packages to @prefix/lib@
147 -- ref: ghc.mk
148 installPackages :: Action ()
149 installPackages = do
150 need [ pkgConfInstallPath ]
151
152 ghcLibDir <- installGhcLibDir
153 binDir <- setting InstallBinDir
154
155 -- Install package.conf
156 let installedPackageConf = destDir ++ ghcLibDir -/- "package.conf.d"
157 installDir (destDir ++ ghcLibDir)
158 removeDirectory installedPackageConf
159 installDir installedPackageConf
160
161 -- Install RTS
162 let rtsDir = destDir ++ ghcLibDir -/- "rts"
163 installDir rtsDir
164 ways <- interpretInContext (vanillaContext Stage1 rts) getRtsWays
165 rtsLibs <- mapM pkgLibraryFile $ map (Context Stage1 rts) ways
166 ffiLibs <- sequence $ map rtsLibffiLibrary ways
167
168 -- TODO: Add dynamic ones
169 forM_ (rtsLibs ++ ffiLibs) $ \lib -> installData [lib] rtsDir
170
171 -- HACK (issue #327)
172 let ghcBootPlatformHeader =
173 buildPath (vanillaContext Stage1 compiler) -/-
174 "ghc_boot_platform.h"
175
176 copyFile ghcBootPlatformHeader (pkgPath compiler -/- "ghc_boot_platform.h")
177
178 -- TODO: Consider Stage1Only
179 -- TODO: Use automatic dependency analysis, rather than hardcoding
180 -- the ordering
181 let installLibPkgs = [ ghcPrim, integerSimple, base, filepath
182 , array, deepseq, bytestring, containers, time, unix
183 , directory, process, hpc, pretty, binary, cabal
184 , ghcBootTh, ghcBoot, templateHaskell
185 , transformers, terminfo, haskeline, ghci, compiler ]
186
187 forM_ installLibPkgs $ \pkg@Package{..} -> do
188 when (isLibrary pkg) $
189 withLatestBuildStage pkg $ \stg -> do
190 let context = vanillaContext stg pkg
191 top <- interpretInContext context getTopDirectory
192 let installDistDir = top -/- buildPath context
193 buildLib stg pkg
194 docDir <- installDocDir
195 ghclibDir <- installGhcLibDir
196 version <- interpretInContext context (getPkgData Version)
197 -- Copy over packages
198 let targetDest = destDir ++ ghclibDir -/-
199 pkgNameString pkg ++ "-" ++ version
200 strip <- stripCmdPath context
201 ways <- interpretInContext context getLibraryWays
202 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal" -- HACK?
203
204 -- HACK (#318): copy stuff back to the place favored by ghc-cabal
205 quietly $ copyDirectoryContents (Not excluded)
206 installDistDir (installDistDir -/- "build")
207 pref <- setting InstallPrefix
208 unit $ cmd ghcCabalInplace
209 [ "copy"
210 , pkgPath
211 , installDistDir
212 , strip
213 , destDir
214 , pref
215 , ghclibDir
216 , docDir -/- "html/libraries"
217 , intercalate " " (map show ways) ]
218
219 -- Register packages
220 let installedGhcPkgReal = destDir ++ binDir -/- "ghc-pkg" <.> exe
221 let installedGhcReal = destDir ++ binDir -/- "ghc" <.> exe
222 -- TODO: Extend GhcPkg builder args to support --global-package-db
223 unit $ cmd installedGhcPkgReal
224 [ "--force", "--global-package-db"
225 , installedPackageConf, "update"
226 , pkgConfInstallPath ]
227
228 forM_ installLibPkgs $ \pkg@Package{..} -> do
229 when (isLibrary pkg) $
230 withLatestBuildStage pkg $ \stg -> do
231 let context = vanillaContext stg pkg
232 top <- interpretInContext context getTopDirectory
233 let installDistDir = top -/- buildPath context
234 -- TODO: better reference to the built inplace binary path
235 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal"
236 pref <- setting InstallPrefix
237 docDir <- installDocDir
238 r <- relocatableBuild
239 unit $ cmd ghcCabalInplace
240 [ "register"
241 , pkgPath
242 , installDistDir
243 , installedGhcReal
244 , installedGhcPkgReal
245 , destDir ++ ghcLibDir
246 , destDir
247 , destDir ++ pref
248 , destDir ++ ghcLibDir
249 , destDir ++ docDir -/- "html/libraries"
250 , if r then "YES" else "NO" ]
251
252 confs <- getDirectoryContents installedPackageConf
253 forM_ confs (\f -> createData $ installedPackageConf -/- f)
254 unit $ cmd installedGhcPkgReal
255 [ "--force", "--global-package-db"
256 , installedPackageConf, "recache" ]
257 where
258 createData f = unit $ cmd ("chmod" :: String) [ "644", f ]
259 excluded = Or
260 [ Test "//haddock-prologue.txt"
261 , Test "//package-data.mk"
262 , Test "//setup-config"
263 , Test "//inplace-pkg-config"
264 , Test "//build" ]
265
266 -- | Install settings etc. files to @prefix/lib@
267 -- ref: ghc.mk
268 installCommonLibs :: Action ()
269 installCommonLibs = do
270 ghcLibDir <- installGhcLibDir
271 installLibsTo inplaceLibCopyTargets (destDir ++ ghcLibDir)
272
273 -- | Install library files to some path
274 -- ref: ghc.mk
275 installLibsTo :: [FilePath] -> FilePath -> Action ()
276 installLibsTo libs dir = do
277 installDir dir
278 forM_ libs $ \lib -> do
279 case takeExtension lib of
280 ".a" -> do
281 let out = dir -/- takeFileName lib
282 installData [out] dir
283 let context = vanillaContext Stage0 $ topLevel (PackageName "")
284 -- TODO: Get rid of meaningless context for certain builder like ranlib
285 build $ Target context Ranlib [out] [out]
286 _ -> installData [lib] dir
287
288 -- | All header files are in includes/{one of these subdirectories}
289 -- ref: includes/ghc.mk
290 includeHSubdirs :: [FilePath]
291 includeHSubdirs = [ ".", "rts", "rts/prof", "rts/storage", "stg" ]
292
293 -- | Install header files to @prefix/lib/ghc-<version>/include@
294 -- ref: includes/ghc.mk
295 installIncludes ::Action ()
296 installIncludes = do
297 ghclibDir <- installGhcLibDir
298 let ghcheaderDir = ghclibDir -/- "include"
299 installDir (destDir ++ ghcheaderDir)
300 forM_ includeHSubdirs $ \d -> do
301 installDir (destDir ++ ghcheaderDir -/- d)
302 headers <- getDirectoryFiles ("includes" -/- d) ["*.h"]
303 installHeader (map (("includes" -/- d) -/-) headers)
304 (destDir ++ ghcheaderDir -/- d ++ "/")
305 installHeader (includesDependencies ++
306 [generatedPath -/- "DerivedConstants.h"] ++
307 libffiDependencies)
308 (destDir ++ ghcheaderDir ++ "/")
309 where
310 installHeader = installData -- they share same arguments