525746b6103edac53bccf679a0755df2a574c64f
[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 -- | 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 liftIO $ IO.createDirectoryIfMissing True (takeDirectory pkgConfInstallPath)
137 build $ Target context HsCpp [ pkgPath rts -/- "package.conf.in" ]
138 [ pkgConfInstallPath <.> "raw" ]
139 Stdout content <- cmd "grep" [ "-v", "^#pragma GCC"
140 , pkgConfInstallPath <.> "raw" ]
141 withTempFile $ \tmp -> do
142 liftIO $ writeFile tmp content
143 Stdout result <- cmd "sed" [ "-e", "s/\"\"//g", "-e", "s/:[ ]*,/: /g", tmp ]
144 liftIO $ writeFile pkgConfInstallPath result
145
146 -- ref: ghc.mk
147 -- | Install packages to @prefix/lib@.
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 installDirectory (destDir ++ ghcLibDir)
158 removeDirectory installedPackageConf
159 installDirectory installedPackageConf
160
161 -- Install RTS
162 let rtsDir = destDir ++ ghcLibDir -/- "rts"
163 installDirectory 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) -/- "ghc_boot_platform.h"
174
175 copyFile ghcBootPlatformHeader (pkgPath compiler -/- "ghc_boot_platform.h")
176
177 activePackages <- filterM ((isJust <$>) . latestBuildStage)
178 (knownPackages \\ [rts, libffi])
179
180 installLibPkgs <- sortPkgsByDep (filter isLibrary activePackages)
181
182 forM_ installLibPkgs $ \pkg@Package{..} -> do
183 when (isLibrary pkg) $
184 withLatestBuildStage pkg $ \stage -> do
185 let context = vanillaContext stage pkg
186 top <- interpretInContext context getTopDirectory
187 let installDistDir = top -/- buildPath context
188 buildPackage stage pkg
189 docDir <- installDocDir
190 ghclibDir <- installGhcLibDir
191
192 -- Copy over packages
193 strip <- stripCmdPath context
194 ways <- interpretInContext context getLibraryWays
195 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal" <.> exe -- HACK?
196 need [ghcCabalInplace]
197
198 let cabalFile = pkgCabalFile pkg
199
200 pkgConf <- pkgConfFile context
201 need [cabalFile, pkgConf] -- TODO: check if need pkgConf
202
203 -- HACK (#318): copy stuff back to the place favored by ghc-cabal
204 quietly $ copyDirectoryContents (Not excluded)
205 installDistDir (installDistDir -/- "build")
206
207 whenM (isSpecified HsColour) $
208 build $ Target context GhcCabalHsColour [cabalFile] []
209
210 pref <- setting InstallPrefix
211 unit $ cmd ghcCabalInplace [ "copy"
212 , pkgPath
213 , installDistDir
214 , strip
215 , destDir
216 , pref
217 , ghclibDir
218 , docDir -/- "html/libraries"
219 , intercalate " " (map show ways) ]
220
221 -- Register packages
222 let installedGhcPkgReal = destDir ++ binDir -/- "ghc-pkg" <.> exe
223 installedGhcReal = destDir ++ binDir -/- "ghc" <.> exe
224 -- TODO: Extend GhcPkg builder args to support --global-package-db
225 unit $ cmd installedGhcPkgReal [ "--force", "--global-package-db"
226 , installedPackageConf, "update"
227 , pkgConfInstallPath ]
228
229 forM_ installLibPkgs $ \pkg@Package{..} -> do
230 when (isLibrary pkg) $
231 withLatestBuildStage pkg $ \stage -> do
232 let context = vanillaContext stage pkg
233 top <- interpretInContext context getTopDirectory
234 let installDistDir = top -/- buildPath context
235 -- TODO: better reference to the built inplace binary path
236 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal"
237 pref <- setting InstallPrefix
238 docDir <- installDocDir
239 r <- relocatableBuild
240 unit $ cmd ghcCabalInplace
241 [ "register"
242 , pkgPath
243 , installDistDir
244 , installedGhcReal
245 , installedGhcPkgReal
246 , destDir ++ ghcLibDir
247 , destDir
248 , destDir ++ pref
249 , destDir ++ ghcLibDir
250 , destDir ++ docDir -/- "html/libraries"
251 , if r then "YES" else "NO" ]
252
253 confs <- getDirectoryContents installedPackageConf
254 forM_ confs (\f -> createData $ installedPackageConf -/- f)
255 unit $ cmd installedGhcPkgReal [ "--force", "--global-package-db"
256 , installedPackageConf, "recache" ]
257 where
258 createData f = unit $ cmd "chmod" [ "644", f ]
259 excluded = Or [ Test "//haddock-prologue.txt"
260 , Test "//package-data.mk"
261 , Test "//setup-config"
262 , Test "//inplace-pkg-config"
263 , Test "//build" ]
264
265 -- ref: ghc.mk
266 -- | Install settings etc. files to @prefix/lib@.
267 installCommonLibs :: Action ()
268 installCommonLibs = do
269 ghcLibDir <- installGhcLibDir
270 installLibsTo inplaceLibCopyTargets (destDir ++ ghcLibDir)
271
272 -- ref: ghc.mk
273 -- | Install library files to some path.
274 installLibsTo :: [FilePath] -> FilePath -> Action ()
275 installLibsTo libs dir = do
276 installDirectory dir
277 forM_ libs $ \lib -> do
278 case takeExtension lib of
279 ".a" -> do
280 let out = dir -/- takeFileName lib
281 installData [out] dir
282 let context = vanillaContext Stage0 $ topLevel (PackageName "")
283 -- TODO: Get rid of meaningless context for certain builder like ranlib
284 build $ Target context Ranlib [out] [out]
285 _ -> installData [lib] dir
286
287 -- ref: includes/ghc.mk
288 -- | All header files are in includes/{one of these subdirectories}.
289 includeHSubdirs :: [FilePath]
290 includeHSubdirs = [".", "rts", "rts/prof", "rts/storage", "stg"]
291
292 -- ref: includes/ghc.mk
293 -- | Install header files to @prefix/lib/ghc-<version>/include@.
294 installIncludes ::Action ()
295 installIncludes = do
296 ghclibDir <- installGhcLibDir
297 let ghcheaderDir = ghclibDir -/- "include"
298 installDirectory (destDir ++ ghcheaderDir)
299 forM_ includeHSubdirs $ \dir -> do
300 installDirectory (destDir ++ ghcheaderDir -/- dir)
301 headers <- getDirectoryFiles ("includes" -/- dir) ["*.h"]
302 installHeader (map (("includes" -/- dir) -/-) headers)
303 (destDir ++ ghcheaderDir -/- dir ++ "/")
304 installHeader (includesDependencies ++
305 [generatedPath -/- "DerivedConstants.h"] ++
306 libffiDependencies)
307 (destDir ++ ghcheaderDir ++ "/")
308 where
309 installHeader = installData -- they share same arguments