8530f50380e6d09851222d25ea4221acb258756d
[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.Dependencies (sortPkgsByDep)
19 import Oracles.Path
20
21 import qualified System.Directory 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 installBinPkgs :: [Package]
85 installBinPkgs =
86 [ ghc, ghcPkg, ghcSplit, hp2ps
87 , hpc, hsc2hs, runGhc, unlit ]
88
89 -- | Install executable wrapper scripts to @prefix/bin@
90 -- ref: ghc.mk
91 installBins :: Action ()
92 installBins = do
93 binDir <- setting InstallBinDir
94 installDir (destDir ++ binDir)
95 forM_ installBinPkgs $ \pkg ->
96 withLatestBuildStage pkg $ \stg -> do
97 let context = programContext stg pkg
98 version <- setting ProjectVersion
99 -- binary's name
100 let binName = if pkg == ghc
101 then "ghc-" ++ version <.> exe
102 else programName context ++ "-" ++ version <.> exe
103 -- symbolic link's name
104 let symName = if pkg == ghc
105 then "ghc" <.> exe
106 else programName context <.> exe
107 case lookup context installWrappers of
108 Nothing -> return ()
109 Just wrapper -> do
110 libDir <- installGhcLibDir
111 contents <- interpretInContext context $
112 wrapper
113 (WrappedBinary (destDir ++ libDir) symName)
114 withTempDir $ \tmp -> do
115 let tmpfile = tmp -/- binName
116 writeFileChanged tmpfile contents
117 installProgram tmpfile (destDir ++ binDir)
118 unlessM windowsHost $
119 linkSymbolic (destDir ++ binDir -/- binName)
120 (destDir ++ binDir -/- symName)
121
122 withLatestBuildStage :: Package -> (Stage -> Action ()) -> Action ()
123 withLatestBuildStage pkg m = do
124 stg' <- latestBuildStage pkg
125 case stg' of
126 Nothing -> return ()
127 Just stg -> m stg
128
129 -- | Install @package.conf.install@ for each package
130 -- Note that each time it will be recreated
131 -- ref: rules/manual-package-conf.mk
132 installPackageConf :: Action ()
133 installPackageConf = do
134 let context = vanillaContext Stage0 rts
135 liftIO $ IO.createDirectoryIfMissing True (takeDirectory pkgConfInstallPath)
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 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 $ \stg -> do
186 let context = vanillaContext stg pkg
187 top <- interpretInContext context getTopDirectory
188 let installDistDir = top -/- buildPath context
189 buildPackage stg pkg
190 docDir <- installDocDir
191 ghclibDir <- installGhcLibDir
192
193 -- Copy over packages
194
195 strip <- stripCmdPath context
196 ways <- interpretInContext context getLibraryWays
197 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal" -- HACK?
198
199 -- HACK (#318): copy stuff back to the place favored by ghc-cabal
200 quietly $ copyDirectoryContents (Not excluded)
201 installDistDir (installDistDir -/- "build")
202 pref <- setting InstallPrefix
203 unit $ cmd ghcCabalInplace
204 [ "copy"
205 , pkgPath
206 , installDistDir
207 , strip
208 , destDir
209 , pref
210 , ghclibDir
211 , docDir -/- "html/libraries"
212 , intercalate " " (map show ways) ]
213
214 -- Register packages
215 let installedGhcPkgReal = destDir ++ binDir -/- "ghc-pkg" <.> exe
216 let installedGhcReal = destDir ++ binDir -/- "ghc" <.> exe
217 -- TODO: Extend GhcPkg builder args to support --global-package-db
218 unit $ cmd installedGhcPkgReal
219 [ "--force", "--global-package-db"
220 , installedPackageConf, "update"
221 , pkgConfInstallPath ]
222
223 forM_ installLibPkgs $ \pkg@Package{..} -> do
224 when (isLibrary pkg) $
225 withLatestBuildStage pkg $ \stg -> do
226 let context = vanillaContext stg pkg
227 top <- interpretInContext context getTopDirectory
228 let installDistDir = top -/- buildPath context
229 -- TODO: better reference to the built inplace binary path
230 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal"
231 pref <- setting InstallPrefix
232 docDir <- installDocDir
233 r <- relocatableBuild
234 unit $ cmd ghcCabalInplace
235 [ "register"
236 , pkgPath
237 , installDistDir
238 , installedGhcReal
239 , installedGhcPkgReal
240 , destDir ++ ghcLibDir
241 , destDir
242 , destDir ++ pref
243 , destDir ++ ghcLibDir
244 , destDir ++ docDir -/- "html/libraries"
245 , if r then "YES" else "NO" ]
246
247 confs <- getDirectoryContents installedPackageConf
248 forM_ confs (\f -> createData $ installedPackageConf -/- f)
249 unit $ cmd installedGhcPkgReal
250 [ "--force", "--global-package-db"
251 , installedPackageConf, "recache" ]
252 where
253 createData f = unit $ cmd ("chmod" :: String) [ "644", f ]
254 excluded = Or
255 [ Test "//haddock-prologue.txt"
256 , Test "//package-data.mk"
257 , Test "//setup-config"
258 , Test "//inplace-pkg-config"
259 , Test "//build" ]
260
261 -- | Install settings etc. files to @prefix/lib@
262 -- ref: ghc.mk
263 installCommonLibs :: Action ()
264 installCommonLibs = do
265 ghcLibDir <- installGhcLibDir
266 installLibsTo inplaceLibCopyTargets (destDir ++ ghcLibDir)
267
268 -- | Install library files to some path
269 -- ref: ghc.mk
270 installLibsTo :: [FilePath] -> FilePath -> Action ()
271 installLibsTo libs dir = do
272 installDir dir
273 forM_ libs $ \lib -> do
274 case takeExtension lib of
275 ".a" -> do
276 let out = dir -/- takeFileName lib
277 installData [out] dir
278 let context = vanillaContext Stage0 $ topLevel (PackageName "")
279 -- TODO: Get rid of meaningless context for certain builder like ranlib
280 build $ Target context Ranlib [out] [out]
281 _ -> installData [lib] dir
282
283 -- | All header files are in includes/{one of these subdirectories}
284 -- ref: includes/ghc.mk
285 includeHSubdirs :: [FilePath]
286 includeHSubdirs = [ ".", "rts", "rts/prof", "rts/storage", "stg" ]
287
288 -- | Install header files to @prefix/lib/ghc-<version>/include@
289 -- ref: includes/ghc.mk
290 installIncludes ::Action ()
291 installIncludes = do
292 ghclibDir <- installGhcLibDir
293 let ghcheaderDir = ghclibDir -/- "include"
294 installDir (destDir ++ ghcheaderDir)
295 forM_ includeHSubdirs $ \d -> do
296 installDir (destDir ++ ghcheaderDir -/- d)
297 headers <- getDirectoryFiles ("includes" -/- d) ["*.h"]
298 installHeader (map (("includes" -/- d) -/-) headers)
299 (destDir ++ ghcheaderDir -/- d ++ "/")
300 installHeader (includesDependencies ++
301 [generatedPath -/- "DerivedConstants.h"] ++
302 libffiDependencies)
303 (destDir ++ ghcheaderDir ++ "/")
304 where
305 installHeader = installData -- they share same arguments