/hadrian/src/Rules/CabalReinstall.hs

https://github.com/bgamari/ghc · Haskell · 112 lines · 82 code · 17 blank · 13 comment · 5 complexity · b9c708025251f2a135e335c81886ee0e MD5 · raw file

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