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 (pkgIdentifier) {- 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] findCabalPackageDb :: String -> FilePath findCabalPackageDb env = go $ map (\l -> (words l, l)) (lines env) where go [] = error $ "Couldn't find installed package db in " ++ show env go (("package-db":_, l):_) = drop 11 l go (_:xs) = go xs cabalBuildRules :: Rules () cabalBuildRules = do root <- buildRootRules root -/- "stage-cabal" -/- "cabal-packages" %> \_ -> 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) [] [] 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 <- pkgIdentifier 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"] env <- liftIO $ readFile $ root -/- "stage-cabal" -/- "cabal-packages" let cabal_package_db = findCabalPackageDb env 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"