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 /stage-cabal/bin along with appropriate wrapper scripts. The libdir of the reinstalled GHC points to the libdir of the stage 2 compiler (in /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"