Minor revision
[hadrian.git] / src / Rules / Install.hs
1 {-# LANGUAGE 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.Dependencies (sortPkgsByDep)
19 import Oracles.DirectoryContents
20 import Oracles.Path
21
22 import qualified System.Directory as IO
23
24 {- | Install the built binaries etc. to the @destDir ++ prefix@.
25
26 The installation prefix is usually @/usr/local@ on a Unix system.
27 The resulting tree structure is organized under @destDir ++ prefix@ as follows:
28
29 * @bin@: executable wrapper scripts, installed by 'installBins', e.g. @ghc@.
30
31 * @lib/ghc-<version>/bin@: executable binaries/scripts,
32 installed by 'installLibExecs' and 'installLibExecScripts'.
33
34 * @lib/ghc-<version>/include@: headers etc., installed by 'installIncludes'.
35
36 * @lib/ghc-<version>/<pkg-name>@: built packages, e.g. @base@, installed
37 by 'installPackages'.
38
39 * @lib/ghc-<version>/settings@ etc.: other files in @lib@ directory,
40 installed by 'installCommonLibs'.
41
42 XXX (izgzhen): Do we need @INSTALL_OPTS@ in the make scripts?
43 -}
44 installRules :: Rules ()
45 installRules = do
46 "install" ~> do
47 installIncludes
48 installPackageConf
49 installCommonLibs
50 installLibExecs
51 installLibExecScripts
52 installBins
53 installPackages
54
55 -- | Binaries to install.
56 installBinPkgs :: [Package]
57 installBinPkgs = [ghc, ghcPkg, ghcSplit, hp2ps, hpc, hsc2hs, runGhc, unlit]
58
59 getLibExecDir :: Action FilePath
60 getLibExecDir = (-/- "bin") <$> installGhcLibDir
61
62 -- ref: ghc.mk
63 -- | Install executable scripts to @prefix/lib/bin@.
64 installLibExecScripts :: Action ()
65 installLibExecScripts = do
66 libExecDir <- getLibExecDir
67 installDirectory (destDir ++ libExecDir)
68 forM_ libExecScripts $ \script -> do
69 installScript script (destDir ++ libExecDir)
70 where
71 libExecScripts :: [FilePath]
72 libExecScripts = [ghcSplitPath]
73
74 -- ref: ghc.mk
75 -- | Install executable binaries to @prefix/lib/bin@.
76 installLibExecs :: Action ()
77 installLibExecs = do
78 libExecDir <- getLibExecDir
79 installDirectory (destDir ++ libExecDir)
80 forM_ installBinPkgs $ \pkg -> do
81 withLatestBuildStage pkg $ \stage -> do
82 let context = programContext stage pkg
83 bin = inplaceLibBinPath -/- programName context <.> exe
84 installProgram bin (destDir ++ libExecDir)
85 when (pkg == ghc) $ do
86 moveFile (destDir ++ libExecDir -/- programName context <.> exe)
87 (destDir ++ libExecDir -/- "ghc" <.> exe)
88
89 -- ref: ghc.mk
90 -- | Install executable wrapper scripts to @prefix/bin@.
91 installBins :: Action ()
92 installBins = do
93 binDir <- setting InstallBinDir
94 libDir <- installGhcLibDir
95 installDirectory (destDir ++ binDir)
96 win <- windowsHost
97 when win $
98 copyDirectoryContents matchAll (destDir ++ libDir -/- "bin") (destDir ++ binDir)
99 unless win $ forM_ installBinPkgs $ \pkg ->
100 withLatestBuildStage pkg $ \stage -> do
101 let context = programContext stage pkg
102 version <- setting ProjectVersion
103 -- Name of the binary file
104 let binName = if pkg == ghc
105 then "ghc-" ++ version <.> exe
106 else programName context ++ "-" ++ version <.> exe
107 -- Name of the symbolic link
108 let symName = if pkg == ghc
109 then "ghc" <.> exe
110 else programName context <.> exe
111 case lookup context installWrappers of
112 Nothing -> return ()
113 Just wrapper -> do
114 contents <- interpretInContext context $
115 wrapper (WrappedBinary (destDir ++ libDir) symName)
116 let wrapperPath = destDir ++ binDir -/- binName
117 writeFileChanged wrapperPath contents
118 makeExecutable wrapperPath
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 maybeStage <- latestBuildStage pkg
126 case maybeStage of
127 Just stage -> m stage
128 Nothing -> return ()
129
130 -- ref: rules/manual-package-conf.mk
131 -- TODO: Should we use a temporary file instead of pkgConfInstallPath?
132 -- | Install @package.conf.install@ for each package. Note that it will be
133 -- recreated each time.
134 installPackageConf :: Action ()
135 installPackageConf = do
136 let context = vanillaContext Stage0 rts
137 liftIO $ IO.createDirectoryIfMissing True (takeDirectory pkgConfInstallPath)
138 build $ Target context HsCpp [ pkgPath rts -/- "package.conf.in" ]
139 [ pkgConfInstallPath <.> "raw" ]
140 Stdout content <- cmd "grep" [ "-v", "^#pragma GCC"
141 , pkgConfInstallPath <.> "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 pkgConfInstallPath result
146
147 -- ref: ghc.mk
148 -- | Install packages to @prefix/lib@.
149 installPackages :: Action ()
150 installPackages = do
151 need [pkgConfInstallPath]
152
153 ghcLibDir <- installGhcLibDir
154 binDir <- setting InstallBinDir
155
156 -- Install package.conf
157 let installedPackageConf = destDir ++ ghcLibDir -/- "package.conf.d"
158 installDirectory (destDir ++ ghcLibDir)
159 removeDirectory installedPackageConf
160 installDirectory installedPackageConf
161
162 -- Install RTS
163 let rtsDir = destDir ++ ghcLibDir -/- "rts"
164 installDirectory rtsDir
165 ways <- interpretInContext (vanillaContext Stage1 rts) getRtsWays
166 rtsLibs <- mapM pkgLibraryFile $ map (Context Stage1 rts) ways
167 ffiLibs <- sequence $ map rtsLibffiLibrary ways
168
169 -- TODO: Add dynamic ones
170 forM_ (rtsLibs ++ ffiLibs) $ \lib -> installData [lib] rtsDir
171
172 -- HACK (issue #327)
173 let ghcBootPlatformHeader =
174 buildPath (vanillaContext Stage1 compiler) -/- "ghc_boot_platform.h"
175
176 copyFile ghcBootPlatformHeader (pkgPath compiler -/- "ghc_boot_platform.h")
177
178 activePackages <- filterM ((isJust <$>) . latestBuildStage)
179 (knownPackages \\ [rts, libffi])
180
181 installLibPkgs <- sortPkgsByDep (filter isLibrary activePackages)
182
183 forM_ installLibPkgs $ \pkg@Package{..} -> do
184 when (isLibrary pkg) $
185 withLatestBuildStage pkg $ \stage -> do
186 let context = vanillaContext stage pkg
187 top <- topDirectory
188 let installDistDir = top -/- buildPath context
189 buildPackage stage pkg
190 docDir <- installDocDir
191 ghclibDir <- installGhcLibDir
192
193 -- Copy over packages
194 strip <- stripCmdPath
195 ways <- interpretInContext context getLibraryWays
196 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal" <.> exe -- HACK?
197 need [ghcCabalInplace]
198
199 let cabalFile = pkgCabalFile pkg
200
201 pkgConf <- pkgConfFile context
202 need [cabalFile, pkgConf] -- TODO: check if need pkgConf
203
204 -- HACK (#318): copy stuff back to the place favored by ghc-cabal
205 quietly $ copyDirectoryContents (Not excluded)
206 installDistDir (installDistDir -/- "build")
207
208 whenM (isSpecified HsColour) $
209 build $ Target context GhcCabalHsColour [cabalFile] []
210
211 pref <- setting InstallPrefix
212 unit $ cmd ghcCabalInplace [ "copy"
213 , pkgPath
214 , installDistDir
215 , strip
216 , destDir
217 , pref
218 , ghclibDir
219 , docDir -/- "html/libraries"
220 , intercalate " " (map show ways) ]
221
222 -- Register packages
223 let installedGhcPkgReal = destDir ++ binDir -/- "ghc-pkg" <.> exe
224 installedGhcReal = destDir ++ binDir -/- "ghc" <.> exe
225 -- TODO: Extend GhcPkg builder args to support --global-package-db
226 unit $ cmd installedGhcPkgReal [ "--force", "--global-package-db"
227 , installedPackageConf, "update"
228 , pkgConfInstallPath ]
229
230 forM_ installLibPkgs $ \pkg@Package{..} -> do
231 when (isLibrary pkg) $
232 withLatestBuildStage pkg $ \stage -> do
233 let context = vanillaContext stage pkg
234 top <- topDirectory
235 let installDistDir = top -/- buildPath context
236 -- TODO: better reference to the built inplace binary path
237 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal"
238 pref <- setting InstallPrefix
239 docDir <- installDocDir
240 r <- relocatableBuild
241 unit $ cmd ghcCabalInplace
242 [ "register"
243 , pkgPath
244 , installDistDir
245 , installedGhcReal
246 , installedGhcPkgReal
247 , destDir ++ ghcLibDir
248 , destDir
249 , destDir ++ pref
250 , destDir ++ ghcLibDir
251 , destDir ++ docDir -/- "html/libraries"
252 , if r then "YES" else "NO" ]
253
254 confs <- getDirectoryContents installedPackageConf
255 forM_ confs (\f -> createData $ installedPackageConf -/- f)
256 unit $ cmd installedGhcPkgReal [ "--force", "--global-package-db"
257 , installedPackageConf, "recache" ]
258 where
259 createData f = unit $ cmd "chmod" [ "644", f ]
260 excluded = Or [ Test "//haddock-prologue.txt"
261 , Test "//package-data.mk"
262 , Test "//setup-config"
263 , Test "//inplace-pkg-config"
264 , Test "//build" ]
265
266 -- ref: ghc.mk
267 -- | Install settings etc. files to @prefix/lib@.
268 installCommonLibs :: Action ()
269 installCommonLibs = do
270 ghcLibDir <- installGhcLibDir
271 installLibsTo inplaceLibCopyTargets (destDir ++ ghcLibDir)
272
273 -- ref: ghc.mk
274 -- | Install library files to some path.
275 installLibsTo :: [FilePath] -> FilePath -> Action ()
276 installLibsTo libs dir = do
277 installDirectory 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 -- ref: includes/ghc.mk
289 -- | All header files are in includes/{one of these subdirectories}.
290 includeHSubdirs :: [FilePath]
291 includeHSubdirs = [".", "rts", "rts/prof", "rts/storage", "stg"]
292
293 -- ref: includes/ghc.mk
294 -- | Install header files to @prefix/lib/ghc-<version>/include@.
295 installIncludes ::Action ()
296 installIncludes = do
297 ghclibDir <- installGhcLibDir
298 let ghcheaderDir = ghclibDir -/- "include"
299 installDirectory (destDir ++ ghcheaderDir)
300 forM_ includeHSubdirs $ \dir -> do
301 installDirectory (destDir ++ ghcheaderDir -/- dir)
302 headers <- getDirectoryFiles ("includes" -/- dir) ["*.h"]
303 installHeader (map (("includes" -/- dir) -/-) headers)
304 (destDir ++ ghcheaderDir -/- dir ++ "/")
305 installHeader (includesDependencies ++
306 [generatedPath -/- "DerivedConstants.h"] ++
307 libffiDependencies)
308 (destDir ++ ghcheaderDir ++ "/")
309 where
310 installHeader = installData -- they share same arguments