1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
module Rules.CabalReinstall where
import Context
import Expression
import Oracles.Flag
import Packages
import Settings
import Target
import Utilities
import qualified System.Directory.Extra as IO
import Data.Either
import Rules.BinaryDist
import Hadrian.Haskell.Cabal (pkgUnitId)
import Oracles.Setting
{-
Note [Testing reinstallable GHC]
~~~~~~~~~~~~~~~~~~~~~~~~~~~
To test the reinstallable GHC configuration, we install a GHC to <build root>/stage-cabal/bin
along with appropriate wrapper scripts.
The libdir of the reinstalled GHC points to the libdir of the stage 2 compiler (in <build root>/stage1)
-}
-- | We don't support reinstalling these
cabalExcludedPackages :: [Package]
cabalExcludedPackages = [array, base, deepseq, filepath, ghcBignum, ghcBootTh, ghcPrim, integerGmp, integerSimple, pretty, templateHaskell]
cabalBuildRules :: Rules ()
cabalBuildRules = do
root <- buildRootRules
root -/- "stage-cabal" -/- "cabal-packages" %> \outpath -> do
-- Always rerun to pass onto cabal's own recompilation logic
alwaysRerun
all_pkgs <- stagePackages Stage1
forM_ (filter (not . (`elem` cabalExcludedPackages)) all_pkgs) $ \pkg -> do
withVerbosity Diagnostic $
buildWithCmdOptions [] $
target (vanillaContext Stage2 pkg) (Cabal Install Stage2) [] []
liftIO $ writeFile outpath "done"
phony "build-cabal" $ need [root -/- "stage-cabal" -/- "bin" -/- ".stamp"]
root -/- "stage-cabal" -/- "bin" -/- "*" %> \_ -> need [root -/- "stage-cabal" -/- "bin" -/- ".stamp"]
priority 2.0 $ root -/- "stage-cabal" -/- "bin" -/- ".stamp" %> \stamp -> do
-- We 'need' all binaries and libraries
all_pkgs <- stagePackages Stage1
(lib_targets, bin_targets) <- partitionEithers <$> mapM pkgTarget all_pkgs
cross <- flag CrossCompiling
iserv_targets <- if cross then pure [] else iservBins
need (lib_targets ++ (map (\(_, p) -> p) (bin_targets ++ iserv_targets)))
distDir <- Context.distDir Stage1
rtsDir <- pkgUnitId Stage1 rts
-- let rtsDir = "rts"
let ghcBuildDir = root -/- stageString Stage1
rtsIncludeDir = ghcBuildDir -/- "lib" -/- distDir -/- rtsDir
-/- "include"
libdir <- liftIO . IO.makeAbsolute =<< stageLibPath Stage1
work_dir <- liftIO $ IO.makeAbsolute $ root -/- "stage-cabal"
let outputDir = work_dir -/- "bin"
includeDir <- liftIO $ IO.makeAbsolute rtsIncludeDir
createDirectory outputDir
need [root -/- "stage-cabal" -/- "cabal-packages"]
cwd <- liftIO $ IO.getCurrentDirectory
version <- setting ProjectVersion
let cabal_package_db = cwd -/- root -/- "stage-cabal" -/- "dist-newstyle" -/- "packagedb" -/- "ghc-" ++ version
forM_ (filter ((/= iserv) . fst) bin_targets) $ \(bin_pkg,_bin_path) -> do
let pgmName pkg
| pkg == ghc = "ghc"
| pkg == hpcBin = "hpc"
| otherwise = pkgName pkg
let cabal_bin_out = work_dir -/- "cabal-bin" -/- (pgmName bin_pkg)
needed_wrappers <- pkgToWrappers bin_pkg
forM_ needed_wrappers $ \wrapper_name -> do
let wrapper_prefix = unlines
["#!/usr/bin/env sh"
,"executablename="++show cabal_bin_out
,"libdir="++show libdir
,"bindir="++show outputDir
,"exedir="++show outputDir
,"includedir="++show includeDir
,"export GHC_PACKAGE_PATH="++show cabal_package_db++":"
]
output_file = outputDir -/- wrapper_name
wrapper_content <- wrapper wrapper_name
writeFile' output_file (wrapper_prefix ++ wrapper_content)
makeExecutable output_file
pure ()
-- Just symlink these for now
-- TODO: build these with cabal as well
forM_ iserv_targets $ \(_bin_pkg,bin_path') -> do
bin_path <- liftIO $ IO.makeAbsolute bin_path'
let orig_filename = takeFileName bin_path
output_file = outputDir -/- orig_filename
liftIO $ do
IO.removeFile output_file <|> pure ()
IO.createFileLink bin_path output_file
pure ()
writeFile' stamp "OK"
|