Better tracking of dependence in installation (#353)
[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.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 installIncludes
43 installPackageConf
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 libExecDir <- getLibExecDir
58 installDir (destDir ++ libExecDir)
59 forM_ libExecScripts $ \script -> do
60 installScript script (destDir ++ libExecDir)
61 where
62 libExecScripts :: [FilePath]
63 libExecScripts = [ ghcSplitPath ]
64
65
66 -- | Install executable binaries to @prefix/lib/bin@
67 -- ref: ghc.mk
68 installLibExecs :: Action ()
69 installLibExecs = do
70 libExecDir <- getLibExecDir
71 installDir (destDir ++ libExecDir)
72 forM_ installBinPkgs $ \pkg -> do
73 withLatestBuildStage pkg $ \stg -> do
74 let context = programContext stg pkg
75 let bin = inplaceLibBinPath -/- programName context <.> exe
76 installProgram bin (destDir ++ libExecDir)
77 when (pkg == ghc) $ do
78 moveFile (destDir ++ libExecDir -/- programName context <.> exe)
79 (destDir ++ libExecDir -/- "ghc" <.> exe)
80
81 -- | Binaries to install
82 installBinPkgs :: [Package]
83 installBinPkgs =
84 [ ghc, ghcPkg, ghcSplit, hp2ps
85 , hpc, hsc2hs, runGhc, unlit ]
86
87 -- | Install executable wrapper scripts to @prefix/bin@
88 -- ref: ghc.mk
89 installBins :: Action ()
90 installBins = do
91 binDir <- setting InstallBinDir
92 installDir (destDir ++ binDir)
93 forM_ installBinPkgs $ \pkg ->
94 withLatestBuildStage pkg $ \stg -> do
95 let context = programContext stg pkg
96 version <- setting ProjectVersion
97 -- binary's name
98 let binName = if pkg == ghc
99 then "ghc-" ++ version <.> exe
100 else programName context ++ "-" ++ version <.> exe
101 -- symbolic link's name
102 let symName = if pkg == ghc
103 then "ghc" <.> exe
104 else programName context <.> exe
105 case lookup context installWrappers of
106 Nothing -> return ()
107 Just wrapper -> do
108 libDir <- installGhcLibDir
109 contents <- interpretInContext context $
110 wrapper
111 (WrappedBinary (destDir ++ libDir) symName)
112 let wrapperPath = destDir ++ binDir -/- binName
113 writeFileChanged wrapperPath contents
114 makeExecutable wrapperPath
115 unlessM windowsHost $
116 linkSymbolic (destDir ++ binDir -/- binName)
117 (destDir ++ binDir -/- symName)
118
119 withLatestBuildStage :: Package -> (Stage -> Action ()) -> Action ()
120 withLatestBuildStage pkg m = do
121 stg' <- latestBuildStage pkg
122 case stg' of
123 Nothing -> return ()
124 Just stg -> m stg
125
126 -- | Install @package.conf.install@ for each package
127 -- Note that each time it will be recreated
128 -- ref: rules/manual-package-conf.mk
129 installPackageConf :: Action ()
130 installPackageConf = do
131 let context = vanillaContext Stage0 rts
132 liftIO $ IO.createDirectoryIfMissing True (takeDirectory pkgConfInstallPath)
133 build $ Target context HsCpp [ pkgPath rts -/- "package.conf.in" ]
134 [ pkgConfInstallPath <.> "raw" ]
135 Stdout content <- cmd "grep" [ "-v", "^#pragma GCC"
136 , pkgConfInstallPath <.> "raw" ]
137 withTempFile $ \tmp -> do
138 liftIO $ writeFile tmp content
139 Stdout content' <- cmd "sed" [ "-e", "s/\"\"//g", "-e", "s/:[ ]*,/: /g", tmp ]
140 liftIO $ writeFile pkgConfInstallPath content'
141
142 -- | Install packages to @prefix/lib@
143 -- ref: ghc.mk
144 installPackages :: Action ()
145 installPackages = do
146 need [ pkgConfInstallPath ]
147
148 ghcLibDir <- installGhcLibDir
149 binDir <- setting InstallBinDir
150
151 -- Install package.conf
152 let installedPackageConf = destDir ++ ghcLibDir -/- "package.conf.d"
153 installDir (destDir ++ ghcLibDir)
154 removeDirectory installedPackageConf
155 installDir installedPackageConf
156
157 -- Install RTS
158 let rtsDir = destDir ++ ghcLibDir -/- "rts"
159 installDir rtsDir
160 ways <- interpretInContext (vanillaContext Stage1 rts) getRtsWays
161 rtsLibs <- mapM pkgLibraryFile $ map (Context Stage1 rts) ways
162 ffiLibs <- sequence $ map rtsLibffiLibrary ways
163
164 -- TODO: Add dynamic ones
165 forM_ (rtsLibs ++ ffiLibs) $ \lib -> installData [lib] rtsDir
166
167 -- HACK (issue #327)
168 let ghcBootPlatformHeader =
169 buildPath (vanillaContext Stage1 compiler) -/-
170 "ghc_boot_platform.h"
171
172 copyFile ghcBootPlatformHeader (pkgPath compiler -/- "ghc_boot_platform.h")
173
174 activePackages <- filterM ((isJust <$>) . latestBuildStage)
175 (knownPackages \\ [rts, libffi])
176
177 installLibPkgs <- sortPkgsByDep (filter isLibrary activePackages)
178
179 forM_ installLibPkgs $ \pkg@Package{..} -> do
180 when (isLibrary pkg) $
181 withLatestBuildStage pkg $ \stg -> do
182 let context = vanillaContext stg pkg
183 top <- interpretInContext context getTopDirectory
184 let installDistDir = top -/- buildPath context
185 buildPackage stg pkg
186 docDir <- installDocDir
187 ghclibDir <- installGhcLibDir
188
189 -- Copy over packages
190
191 strip <- stripCmdPath context
192 ways <- interpretInContext context getLibraryWays
193 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal" -- HACK?
194 need [ ghcCabalInplace ]
195
196 -- HACK (#318): copy stuff back to the place favored by ghc-cabal
197 quietly $ copyDirectoryContents (Not excluded)
198 installDistDir (installDistDir -/- "build")
199 pref <- setting InstallPrefix
200 unit $ cmd ghcCabalInplace
201 [ "copy"
202 , pkgPath
203 , installDistDir
204 , strip
205 , destDir
206 , pref
207 , ghclibDir
208 , docDir -/- "html/libraries"
209 , intercalate " " (map show ways) ]
210
211 -- Register packages
212 let installedGhcPkgReal = destDir ++ binDir -/- "ghc-pkg" <.> exe
213 let installedGhcReal = destDir ++ binDir -/- "ghc" <.> exe
214 -- TODO: Extend GhcPkg builder args to support --global-package-db
215 unit $ cmd installedGhcPkgReal
216 [ "--force", "--global-package-db"
217 , installedPackageConf, "update"
218 , pkgConfInstallPath ]
219
220 forM_ installLibPkgs $ \pkg@Package{..} -> do
221 when (isLibrary pkg) $
222 withLatestBuildStage pkg $ \stg -> do
223 let context = vanillaContext stg pkg
224 top <- interpretInContext context getTopDirectory
225 let installDistDir = top -/- buildPath context
226 -- TODO: better reference to the built inplace binary path
227 let ghcCabalInplace = inplaceBinPath -/- "ghc-cabal"
228 pref <- setting InstallPrefix
229 docDir <- installDocDir
230 r <- relocatableBuild
231 unit $ cmd ghcCabalInplace
232 [ "register"
233 , pkgPath
234 , installDistDir
235 , installedGhcReal
236 , installedGhcPkgReal
237 , destDir ++ ghcLibDir
238 , destDir
239 , destDir ++ pref
240 , destDir ++ ghcLibDir
241 , destDir ++ docDir -/- "html/libraries"
242 , if r then "YES" else "NO" ]
243
244 confs <- getDirectoryContents installedPackageConf
245 forM_ confs (\f -> createData $ installedPackageConf -/- f)
246 unit $ cmd installedGhcPkgReal
247 [ "--force", "--global-package-db"
248 , installedPackageConf, "recache" ]
249 where
250 createData f = unit $ cmd "chmod" [ "644", f ]
251 excluded = Or
252 [ Test "//haddock-prologue.txt"
253 , Test "//package-data.mk"
254 , Test "//setup-config"
255 , Test "//inplace-pkg-config"
256 , Test "//build" ]
257
258 -- | Install settings etc. files to @prefix/lib@
259 -- ref: ghc.mk
260 installCommonLibs :: Action ()
261 installCommonLibs = do
262 ghcLibDir <- installGhcLibDir
263 installLibsTo inplaceLibCopyTargets (destDir ++ ghcLibDir)
264
265 -- | Install library files to some path
266 -- ref: ghc.mk
267 installLibsTo :: [FilePath] -> FilePath -> Action ()
268 installLibsTo libs dir = do
269 installDir dir
270 forM_ libs $ \lib -> do
271 case takeExtension lib of
272 ".a" -> do
273 let out = dir -/- takeFileName lib
274 installData [out] dir
275 let context = vanillaContext Stage0 $ topLevel (PackageName "")
276 -- TODO: Get rid of meaningless context for certain builder like ranlib
277 build $ Target context Ranlib [out] [out]
278 _ -> installData [lib] dir
279
280 -- | All header files are in includes/{one of these subdirectories}
281 -- ref: includes/ghc.mk
282 includeHSubdirs :: [FilePath]
283 includeHSubdirs = [ ".", "rts", "rts/prof", "rts/storage", "stg" ]
284
285 -- | Install header files to @prefix/lib/ghc-<version>/include@
286 -- ref: includes/ghc.mk
287 installIncludes ::Action ()
288 installIncludes = do
289 ghclibDir <- installGhcLibDir
290 let ghcheaderDir = ghclibDir -/- "include"
291 installDir (destDir ++ ghcheaderDir)
292 forM_ includeHSubdirs $ \d -> do
293 installDir (destDir ++ ghcheaderDir -/- d)
294 headers <- getDirectoryFiles ("includes" -/- d) ["*.h"]
295 installHeader (map (("includes" -/- d) -/-) headers)
296 (destDir ++ ghcheaderDir -/- d ++ "/")
297 installHeader (includesDependencies ++
298 [generatedPath -/- "DerivedConstants.h"] ++
299 libffiDependencies)
300 (destDir ++ ghcheaderDir ++ "/")
301 where
302 installHeader = installData -- they share same arguments