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