diff options
author | Sylvain Henry <sylvain@haskus.fr> | 2021-01-13 18:24:21 +0100 |
---|---|---|
committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2021-03-08 18:24:07 -0500 |
commit | daa6363f49df0dceb2c460da500461e564aa9ea2 (patch) | |
tree | 49891c015240ed281c603fdaebb0f26f49d47a6b /compiler/GHC/Driver | |
parent | e483775c3ff39523d18c44f04b4842518437fba8 (diff) | |
download | haskell-daa6363f49df0dceb2c460da500461e564aa9ea2.tar.gz |
DynFlags: move temp file management into HscEnv (#17957)
Diffstat (limited to 'compiler/GHC/Driver')
-rw-r--r-- | compiler/GHC/Driver/CodeOutput.hs | 56 | ||||
-rw-r--r-- | compiler/GHC/Driver/Env/Types.hs | 4 | ||||
-rw-r--r-- | compiler/GHC/Driver/Main.hs | 17 | ||||
-rw-r--r-- | compiler/GHC/Driver/Make.hs | 107 | ||||
-rw-r--r-- | compiler/GHC/Driver/MakeFile.hs | 11 | ||||
-rw-r--r-- | compiler/GHC/Driver/Pipeline.hs | 112 | ||||
-rw-r--r-- | compiler/GHC/Driver/Pipeline/Monad.hs | 2 | ||||
-rw-r--r-- | compiler/GHC/Driver/Session.hs | 42 |
8 files changed, 173 insertions, 178 deletions
diff --git a/compiler/GHC/Driver/CodeOutput.hs b/compiler/GHC/Driver/CodeOutput.hs index b459b7b447..8c990b16cb 100644 --- a/compiler/GHC/Driver/CodeOutput.hs +++ b/compiler/GHC/Driver/CodeOutput.hs @@ -36,7 +36,7 @@ import qualified GHC.Data.ShortText as ST import GHC.Data.Stream ( Stream ) import qualified GHC.Data.Stream as Stream -import GHC.SysTools.FileCleanup +import GHC.Utils.TmpFs import GHC.Utils.Error @@ -66,23 +66,24 @@ import System.IO ************************************************************************ -} -codeOutput :: Logger - -> DynFlags - -> UnitState - -> Module - -> FilePath - -> ModLocation - -> (a -> ForeignStubs) - -> [(ForeignSrcLang, FilePath)] - -- ^ additional files to be compiled with the C compiler - -> [UnitId] - -> Stream IO RawCmmGroup a -- Compiled C-- - -> IO (FilePath, - (Bool{-stub_h_exists-}, Maybe FilePath{-stub_c_exists-}), - [(ForeignSrcLang, FilePath)]{-foreign_fps-}, - a) - -codeOutput logger dflags unit_state this_mod filenm location genForeignStubs foreign_fps pkg_deps +codeOutput + :: Logger + -> TmpFs + -> DynFlags + -> UnitState + -> Module + -> FilePath + -> ModLocation + -> (a -> ForeignStubs) + -> [(ForeignSrcLang, FilePath)] + -- ^ additional files to be compiled with the C compiler + -> [UnitId] + -> Stream IO RawCmmGroup a -- Compiled C-- + -> IO (FilePath, + (Bool{-stub_h_exists-}, Maybe FilePath{-stub_c_exists-}), + [(ForeignSrcLang, FilePath)]{-foreign_fps-}, + a) +codeOutput logger tmpfs dflags unit_state this_mod filenm location genForeignStubs foreign_fps pkg_deps cmm_stream = do { @@ -117,7 +118,7 @@ codeOutput logger dflags unit_state this_mod filenm location genForeignStubs for Interpreter -> panic "codeOutput: Interpreter" NoBackend -> panic "codeOutput: NoBackend" ; let stubs = genForeignStubs a - ; stubs_exist <- outputForeignStubs logger dflags unit_state this_mod location stubs + ; stubs_exist <- outputForeignStubs logger tmpfs dflags unit_state this_mod location stubs ; return (filenm, stubs_exist, foreign_fps, a) } @@ -198,13 +199,20 @@ outputLlvm logger dflags filenm cmm_stream = ************************************************************************ -} -outputForeignStubs :: Logger -> DynFlags -> UnitState -> Module -> ModLocation -> ForeignStubs - -> IO (Bool, -- Header file created - Maybe FilePath) -- C file created -outputForeignStubs logger dflags unit_state mod location stubs +outputForeignStubs + :: Logger + -> TmpFs + -> DynFlags + -> UnitState + -> Module + -> ModLocation + -> ForeignStubs + -> IO (Bool, -- Header file created + Maybe FilePath) -- C file created +outputForeignStubs logger tmpfs dflags unit_state mod location stubs = do let stub_h = mkStubPaths dflags (moduleName mod) location - stub_c <- newTempName logger dflags TFL_CurrentModule "c" + stub_c <- newTempName logger tmpfs dflags TFL_CurrentModule "c" case stubs of NoStubs -> diff --git a/compiler/GHC/Driver/Env/Types.hs b/compiler/GHC/Driver/Env/Types.hs index e541dfe544..23282eab27 100644 --- a/compiler/GHC/Driver/Env/Types.hs +++ b/compiler/GHC/Driver/Env/Types.hs @@ -22,6 +22,7 @@ import GHC.Unit.Env import GHC.Unit.State import GHC.Unit.Types import GHC.Utils.Logger +import GHC.Utils.TmpFs import {-# SOURCE #-} GHC.Driver.Plugins import Control.Monad ( ap ) @@ -159,5 +160,8 @@ data HscEnv , hsc_hooks :: !Hooks -- ^ Hooks + + , hsc_tmpfs :: !TmpFs + -- ^ Temporary files } diff --git a/compiler/GHC/Driver/Main.hs b/compiler/GHC/Driver/Main.hs index d3695177d3..5be42094a0 100644 --- a/compiler/GHC/Driver/Main.hs +++ b/compiler/GHC/Driver/Main.hs @@ -207,6 +207,7 @@ import GHC.Utils.Outputable import GHC.Utils.Exception import GHC.Utils.Misc import GHC.Utils.Logger +import GHC.Utils.TmpFs import GHC.Data.FastString import GHC.Data.Bag @@ -248,6 +249,7 @@ newHscEnv dflags = do fc_var <- newIORef emptyInstalledModuleEnv emptyLoader <- uninitializedLoader logger <- initLogger + tmpfs <- initTmpFs -- FIXME: it's sad that we have so many "unitialized" fields filled with -- empty stuff or lazy panics. We should have two kinds of HscEnv -- (initialized or not) instead and less fields that are mutable over time. @@ -268,6 +270,7 @@ newHscEnv dflags = do , hsc_static_plugins = [] , hsc_unit_dbs = Nothing , hsc_hooks = emptyHooks + , hsc_tmpfs = tmpfs } -- ----------------------------------------------------------------------------- @@ -1528,6 +1531,7 @@ hscGenHardCode hsc_env cgguts location output_filename = do dflags = hsc_dflags hsc_env logger = hsc_logger hsc_env hooks = hsc_hooks hsc_env + tmpfs = hsc_tmpfs hsc_env data_tycons = filter isDataTyCon tycons -- cg_tycons includes newtypes, for the benefit of External Core, -- but we don't generate any code for newtypes @@ -1581,7 +1585,7 @@ hscGenHardCode hsc_env cgguts location output_filename = do (output_filename, (_stub_h_exists, stub_c_exists), foreign_fps, cg_infos) <- {-# SCC "codeOutput" #-} - codeOutput logger dflags (hsc_units hsc_env) this_mod output_filename location + codeOutput logger tmpfs dflags (hsc_units hsc_env) this_mod output_filename location foreign_stubs foreign_files dependencies rawcmms1 return (output_filename, stub_c_exists, foreign_fps, cg_infos) @@ -1593,6 +1597,7 @@ hscInteractive :: HscEnv hscInteractive hsc_env cgguts location = do let dflags = hsc_dflags hsc_env let logger = hsc_logger hsc_env + let tmpfs = hsc_tmpfs hsc_env let CgGuts{ -- This is the last use of the ModGuts in a compilation. -- From now on, we just use the bits we need. cg_module = this_mod, @@ -1615,7 +1620,7 @@ hscInteractive hsc_env cgguts location = do comp_bc <- byteCodeGen hsc_env this_mod prepd_binds data_tycons mod_breaks ------------------ Create f-x-dynamic C-side stuff ----- (_istub_h_exists, istub_c_exists) - <- outputForeignStubs logger dflags (hsc_units hsc_env) this_mod location foreign_stubs + <- outputForeignStubs logger tmpfs dflags (hsc_units hsc_env) this_mod location foreign_stubs return (istub_c_exists, comp_bc, spt_entries) ------------------------------ @@ -1625,6 +1630,7 @@ hscCompileCmmFile hsc_env filename output_filename = runHsc hsc_env $ do let dflags = hsc_dflags hsc_env let logger = hsc_logger hsc_env let hooks = hsc_hooks hsc_env + let tmpfs = hsc_tmpfs hsc_env home_unit = hsc_home_unit hsc_env platform = targetPlatform dflags -- Make up a module name to give the NCG. We can't pass bottom here @@ -1661,7 +1667,7 @@ hscCompileCmmFile hsc_env filename output_filename = runHsc hsc_env $ do in NoStubs `appendStubC` ip_init (_output_filename, (_stub_h_exists, stub_c_exists), _foreign_fps, _caf_infos) - <- codeOutput logger dflags (hsc_units hsc_env) cmm_mod output_filename no_loc foreign_stubs [] [] + <- codeOutput logger tmpfs dflags (hsc_units hsc_env) cmm_mod output_filename no_loc foreign_stubs [] [] rawCmms return stub_c_exists where @@ -1703,14 +1709,15 @@ doCodeGen hsc_env this_mod denv data_tycons let dflags = hsc_dflags hsc_env let logger = hsc_logger hsc_env let hooks = hsc_hooks hsc_env - platform = targetPlatform dflags + let tmpfs = hsc_tmpfs hsc_env + let platform = targetPlatform dflags let stg_binds_w_fvs = annTopBindingsFreeVars stg_binds dumpIfSet_dyn logger dflags Opt_D_dump_stg_final "Final STG:" FormatSTG (pprGenStgTopBindings (initStgPprOpts dflags) stg_binds_w_fvs) let stg_to_cmm = case stgToCmmHook hooks of - Nothing -> StgToCmm.codeGen logger + Nothing -> StgToCmm.codeGen logger tmpfs Just h -> h let cmm_stream :: Stream IO CmmGroup (CStub, ModuleLFInfos) diff --git a/compiler/GHC/Driver/Make.hs b/compiler/GHC/Driver/Make.hs index f13d13b198..bd885d9042 100644 --- a/compiler/GHC/Driver/Make.hs +++ b/compiler/GHC/Driver/Make.hs @@ -83,7 +83,7 @@ import GHC.Utils.Panic import GHC.Utils.Misc import GHC.Utils.Error import GHC.Utils.Logger -import GHC.SysTools.FileCleanup +import GHC.Utils.TmpFs import GHC.Types.Basic import GHC.Types.Target @@ -568,8 +568,6 @@ load' how_much mHscMessage mod_graph = do -- an unstable module (#7231). mg = fmap (fmap ModuleNode) stable_mg ++ unstable_mg - -- clean up between compilations - let cleanup hsc_env = cleanCurrentModuleTempFiles (hsc_logger hsc_env) (hsc_dflags hsc_env) liftIO $ debugTraceMsg logger dflags 2 (hang (text "Ready for upsweep") 2 (ppr mg)) @@ -581,7 +579,7 @@ load' how_much mHscMessage mod_graph = do setSession hsc_env{ hsc_HPT = emptyHomePackageTable } (upsweep_ok, modsUpswept) <- withDeferredDiagnostics $ - upsweep_fn mHscMessage pruned_hpt stable_mods cleanup mg + upsweep_fn mHscMessage pruned_hpt stable_mods mg -- Make modsDone be the summaries for each home module now -- available; this should equal the domain of hpt3. @@ -601,7 +599,7 @@ load' how_much mHscMessage mod_graph = do -- Clean up after ourselves hsc_env1 <- getSession - liftIO $ cleanCurrentModuleTempFiles logger dflags + liftIO $ cleanCurrentModuleTempFiles logger (hsc_tmpfs hsc_env1) dflags -- Issue a warning for the confusing case where the user -- said '-o foo' but we're not going to do any linking. @@ -620,6 +618,7 @@ load' how_much mHscMessage mod_graph = do hsc_env <- getSession linkresult <- liftIO $ link (ghcLink dflags) logger + (hsc_tmpfs hsc_env) (hsc_hooks hsc_env) dflags (hsc_unit_env hsc_env) @@ -665,9 +664,9 @@ load' how_much mHscMessage mod_graph = do lookupHpt hpt4 (moduleName ms_mod) >>= hm_linkable ] - liftIO $ - changeTempFilesLifetime dflags TFL_CurrentModule unneeded_temps - liftIO $ cleanCurrentModuleTempFiles logger dflags + tmpfs <- hsc_tmpfs <$> getSession + liftIO $ changeTempFilesLifetime tmpfs TFL_CurrentModule unneeded_temps + liftIO $ cleanCurrentModuleTempFiles logger tmpfs dflags let hpt5 = retainInTopLevelEnvs (map ms_mod_name mods_to_keep) hpt4 @@ -686,6 +685,7 @@ load' how_much mHscMessage mod_graph = do hsc_env <- getSession linkresult <- liftIO $ link (ghcLink dflags) logger + (hsc_tmpfs hsc_env) (hsc_hooks hsc_env) dflags (hsc_unit_env hsc_env) @@ -1067,14 +1067,14 @@ parUpsweep -> Maybe Messager -> HomePackageTable -> StableModules - -> (HscEnv -> IO ()) -> [SCC ModuleGraphNode] -> m (SuccessFlag, [ModuleGraphNode]) -parUpsweep n_jobs mHscMessage old_hpt stable_mods cleanup sccs = do +parUpsweep n_jobs mHscMessage old_hpt stable_mods sccs = do hsc_env <- getSession let dflags = hsc_dflags hsc_env let logger = hsc_logger hsc_env + let tmpfs = hsc_tmpfs hsc_env -- The bits of shared state we'll be using: @@ -1176,18 +1176,15 @@ parUpsweep n_jobs mHscMessage old_hpt stable_mods cleanup sccs = do -- deal with synchronously printing these messages. let lcl_logger = pushLogHook (const (parLogAction log_queue)) thread_safe_logger - -- - -- Use a local filesToClean var so that we can clean up - -- intermediate files in a timely fashion (as soon as - -- compilation for that module is finished) without having to - -- worry about accidentally deleting a simultaneous compile's - -- important files. - lcl_files_to_clean <- newIORef emptyFilesToClean - let lcl_dflags = dflags { filesToClean = lcl_files_to_clean } + -- Use a local TmpFs so that we can clean up intermediate files + -- in a timely fashion (as soon as compilation for that module + -- is finished) without having to worry about accidentally + -- deleting a simultaneous compile's important files. + lcl_tmpfs <- forkTmpFsFrom tmpfs -- Unmask asynchronous exceptions and perform the thread-local -- work to compile the module (see parUpsweep_one). - m_res <- MC.try $ unmask $ prettyPrintGhcErrors lcl_dflags $ + m_res <- MC.try $ unmask $ prettyPrintGhcErrors dflags $ case mod of InstantiationNode iuid -> do hsc_env <- readMVar hsc_env_var @@ -1195,8 +1192,8 @@ parUpsweep n_jobs mHscMessage old_hpt stable_mods cleanup sccs = do pure Succeeded ModuleNode ems -> parUpsweep_one (emsModSummary ems) home_mod_map comp_graph_loops - lcl_logger lcl_dflags (hsc_home_unit hsc_env) - mHscMessage cleanup + lcl_logger lcl_tmpfs dflags (hsc_home_unit hsc_env) + mHscMessage par_sem hsc_env_var old_hpt_var stable_mods mod_idx (length sccs) @@ -1208,7 +1205,7 @@ parUpsweep n_jobs mHscMessage old_hpt stable_mods cleanup sccs = do -- interrupt, and the user doesn't have to be informed -- about that. when (fromException exc /= Just ThreadKilled) - (errorMsg lcl_logger lcl_dflags (text (show exc))) + (errorMsg lcl_logger dflags (text (show exc))) return Failed -- Populate the result MVar. @@ -1220,13 +1217,8 @@ parUpsweep n_jobs mHscMessage old_hpt stable_mods cleanup sccs = do writeLogQueue log_queue Nothing -- Add the remaining files that weren't cleaned up to the - -- global filesToClean ref, for cleanup later. - FilesToClean - { ftcCurrentModule = cm_files - , ftcGhcSession = gs_files - } <- readIORef (filesToClean lcl_dflags) - addFilesToClean dflags TFL_CurrentModule $ Set.toList cm_files - addFilesToClean dflags TFL_GhcSession $ Set.toList gs_files + -- global TmpFs, for cleanup later. + mergeTmpFsInto lcl_tmpfs tmpfs -- Kill all the workers, masking interrupts (since killThread is -- interruptible). XXX: This is not ideal. @@ -1298,14 +1290,14 @@ parUpsweep_one -- ^ The list of all module loops within the compilation graph. -> Logger -- ^ The thread-local Logger + -> TmpFs + -- ^ The thread-local TmpFs -> DynFlags -- ^ The thread-local DynFlags -> HomeUnit -- ^ The home-unit -> Maybe Messager -- ^ The messager - -> (HscEnv -> IO ()) - -- ^ The callback for cleaning up intermediate files -> QSem -- ^ The semaphore for limiting the number of simultaneous compiles -> MVar HscEnv @@ -1320,7 +1312,7 @@ parUpsweep_one -- ^ The total number of modules -> IO SuccessFlag -- ^ The result of this compile -parUpsweep_one mod home_mod_map comp_graph_loops lcl_logger lcl_dflags home_unit mHscMessage cleanup par_sem +parUpsweep_one mod home_mod_map comp_graph_loops lcl_logger lcl_tmpfs lcl_dflags home_unit mHscMessage par_sem hsc_env_var old_hpt_var stable_mods mod_index num_mods = do let this_build_mod = mkBuildModule0 mod @@ -1430,9 +1422,7 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_logger lcl_dflags home_unit let withSem sem = MC.bracket_ (waitQSem sem) (signalQSem sem) mb_mod_info <- withSem par_sem $ handleSourceError (\err -> do logg err; return Nothing) $ do - -- Have the ModSummary and HscEnv point to our local log_action - -- and filesToClean var. - let lcl_mod = localize_mod mod + -- Have the HscEnv point to our local logger and tmpfs. let lcl_hsc_env = localize_hsc_env hsc_env -- Re-typecheck the loop @@ -1440,7 +1430,7 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_logger lcl_dflags home_unit -- we close a recursive module loop, see bug #12035. type_env_var <- liftIO $ newIORef emptyNameEnv let lcl_hsc_env' = lcl_hsc_env { hsc_type_env_var = - Just (ms_mod lcl_mod, type_env_var) } + Just (ms_mod mod, type_env_var) } lcl_hsc_env'' <- case finish_loop of Nothing -> return lcl_hsc_env' -- In the non-parallel case, the retypecheck prior to @@ -1454,7 +1444,7 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_logger lcl_dflags home_unit -- Compile the module. mod_info <- upsweep_mod lcl_hsc_env'' mHscMessage old_hpt stable_mods - lcl_mod mod_index num_mods + mod mod_index num_mods return (Just mod_info) case mb_mod_info of @@ -1483,18 +1473,16 @@ parUpsweep_one mod home_mod_map comp_graph_loops lcl_logger lcl_dflags home_unit return (hsc_env'', localize_hsc_env hsc_env'') -- Clean up any intermediate files. - cleanup lcl_hsc_env' + cleanCurrentModuleTempFiles (hsc_logger lcl_hsc_env') + (hsc_tmpfs lcl_hsc_env') + (hsc_dflags lcl_hsc_env') return Succeeded where - localize_mod mod - = mod { ms_hspp_opts = (ms_hspp_opts mod) - { filesToClean = filesToClean lcl_dflags } } - localize_hsc_env hsc_env = hsc_env { hsc_logger = lcl_logger - , hsc_dflags = (hsc_dflags hsc_env) - { filesToClean = filesToClean lcl_dflags } } + , hsc_tmpfs = lcl_tmpfs + } -- ----------------------------------------------------------------------------- -- @@ -1510,7 +1498,6 @@ upsweep => Maybe Messager -> HomePackageTable -- ^ HPT from last time round (pruned) -> StableModules -- ^ stable modules (see checkStability) - -> (HscEnv -> IO ()) -- ^ How to clean up unwanted tmp files -> [SCC ModuleGraphNode] -- ^ Mods to do (the worklist) -> m (SuccessFlag, [ModuleGraphNode]) @@ -1520,7 +1507,7 @@ upsweep -- 2. The 'HscEnv' in the monad has an updated HPT -- 3. A list of modules which succeeded loading. -upsweep mHscMessage old_hpt stable_mods cleanup sccs = do +upsweep mHscMessage old_hpt stable_mods sccs = do (res, done) <- upsweep' old_hpt emptyMG sccs 1 (length sccs) return (res, reverse $ mgModSummaries' done) where @@ -1588,7 +1575,9 @@ upsweep mHscMessage old_hpt stable_mods cleanup sccs = do hsc_env <- getSession -- Remove unwanted tmp files between compilations - liftIO (cleanup hsc_env) + liftIO $ cleanCurrentModuleTempFiles (hsc_logger hsc_env) + (hsc_tmpfs hsc_env) + (hsc_dflags hsc_env) -- Get ready to tie the knot type_env_var <- liftIO $ newIORef emptyNameEnv @@ -2274,10 +2263,11 @@ downsweep hsc_env old_summaries excl_mods allow_dup_roots -- otherwise those modules will fail to compile. -- See Note [-fno-code mode] #8025 let default_backend = platformDefaultBackend (targetPlatform dflags) - home_unit = hsc_home_unit hsc_env + let home_unit = hsc_home_unit hsc_env + let tmpfs = hsc_tmpfs hsc_env map1 <- case backend dflags of - NoBackend -> enableCodeGenForTH logger home_unit default_backend map0 - Interpreter -> enableCodeGenForUnboxedTuplesOrSums logger default_backend map0 + NoBackend -> enableCodeGenForTH logger tmpfs home_unit default_backend map0 + Interpreter -> enableCodeGenForUnboxedTuplesOrSums logger tmpfs default_backend map0 _ -> return map0 if null errs then pure $ concat $ modNodeMapElems map1 @@ -2372,12 +2362,13 @@ downsweep hsc_env old_summaries excl_mods allow_dup_roots -- See Note [-fno-code mode] enableCodeGenForTH :: Logger + -> TmpFs -> HomeUnit -> Backend -> ModNodeMap [Either ErrorMessages ExtendedModSummary] -> IO (ModNodeMap [Either ErrorMessages ExtendedModSummary]) -enableCodeGenForTH logger home_unit = - enableCodeGenWhen logger condition should_modify TFL_CurrentModule TFL_GhcSession +enableCodeGenForTH logger tmpfs home_unit = + enableCodeGenWhen logger tmpfs condition should_modify TFL_CurrentModule TFL_GhcSession where condition = isTemplateHaskellOrQQNonBoot should_modify (ModSummary { ms_hspp_opts = dflags }) = @@ -2395,11 +2386,12 @@ enableCodeGenForTH logger home_unit = -- or sums into GHCi while still allowing some code to be interpreted. enableCodeGenForUnboxedTuplesOrSums :: Logger + -> TmpFs -> Backend -> ModNodeMap [Either ErrorMessages ExtendedModSummary] -> IO (ModNodeMap [Either ErrorMessages ExtendedModSummary]) -enableCodeGenForUnboxedTuplesOrSums logger = - enableCodeGenWhen logger condition should_modify TFL_GhcSession TFL_CurrentModule +enableCodeGenForUnboxedTuplesOrSums logger tmpfs = + enableCodeGenWhen logger tmpfs condition should_modify TFL_GhcSession TFL_CurrentModule where condition ms = unboxed_tuples_or_sums (ms_hspp_opts ms) && @@ -2418,6 +2410,7 @@ enableCodeGenForUnboxedTuplesOrSums logger = -- marking modules for code generation. enableCodeGenWhen :: Logger + -> TmpFs -> (ModSummary -> Bool) -> (ModSummary -> Bool) -> TempFileLifetime @@ -2425,7 +2418,7 @@ enableCodeGenWhen -> Backend -> ModNodeMap [Either ErrorMessages ExtendedModSummary] -> IO (ModNodeMap [Either ErrorMessages ExtendedModSummary]) -enableCodeGenWhen logger condition should_modify staticLife dynLife bcknd nodemap = +enableCodeGenWhen logger tmpfs condition should_modify staticLife dynLife bcknd nodemap = traverse (traverse (traverse enable_code_gen)) nodemap where enable_code_gen :: ExtendedModSummary -> IO ExtendedModSummary @@ -2440,9 +2433,9 @@ enableCodeGenWhen logger condition should_modify staticLife dynLife bcknd nodema , ms_mod `Set.member` needs_codegen_set = do let new_temp_file suf dynsuf = do - tn <- newTempName logger dflags staticLife suf + tn <- newTempName logger tmpfs dflags staticLife suf let dyn_tn = tn -<.> dynsuf - addFilesToClean dflags dynLife [dyn_tn] + addFilesToClean tmpfs dynLife [dyn_tn] return tn -- We don't want to create .o or .hi files unless we have been asked -- to by the user. But we need them, so we patch their locations in diff --git a/compiler/GHC/Driver/MakeFile.hs b/compiler/GHC/Driver/MakeFile.hs index 57377212cb..f71b2e17b9 100644 --- a/compiler/GHC/Driver/MakeFile.hs +++ b/compiler/GHC/Driver/MakeFile.hs @@ -31,7 +31,7 @@ import GHC.Types.SourceError import GHC.Types.SrcLoc import Data.List (partition) import GHC.Data.FastString -import GHC.SysTools.FileCleanup +import GHC.Utils.TmpFs import GHC.Iface.Load (cannotFindModule) @@ -82,7 +82,8 @@ doMkDependHS srcs = do when (null (depSuffixes dflags)) $ liftIO $ throwGhcExceptionIO (ProgramError "You must specify at least one -dep-suffix") - files <- liftIO $ beginMkDependHS logger dflags + tmpfs <- hsc_tmpfs <$> getSession + files <- liftIO $ beginMkDependHS logger tmpfs dflags -- Do the downsweep to find all the modules targets <- mapM (\s -> GHC.guessTarget s Nothing) srcs @@ -131,11 +132,11 @@ data MkDepFiles mkd_tmp_file :: FilePath, -- Name of the temporary file mkd_tmp_hdl :: Handle } -- Handle of the open temporary file -beginMkDependHS :: Logger -> DynFlags -> IO MkDepFiles -beginMkDependHS logger dflags = do +beginMkDependHS :: Logger -> TmpFs -> DynFlags -> IO MkDepFiles +beginMkDependHS logger tmpfs dflags = do -- open a new temp file in which to stuff the dependency info -- as we go along. - tmp_file <- newTempName logger dflags TFL_CurrentModule "dep" + tmp_file <- newTempName logger tmpfs dflags TFL_CurrentModule "dep" tmp_hdl <- openFile tmp_file WriteMode -- open the makefile diff --git a/compiler/GHC/Driver/Pipeline.hs b/compiler/GHC/Driver/Pipeline.hs index f2e740ac41..bf9fbe8405 100644 --- a/compiler/GHC/Driver/Pipeline.hs +++ b/compiler/GHC/Driver/Pipeline.hs @@ -62,7 +62,7 @@ import GHC.Parser.Header import GHC.Parser.Errors.Ppr import GHC.SysTools -import GHC.SysTools.FileCleanup +import GHC.Utils.TmpFs import GHC.Linker.ExtraObj import GHC.Linker.Dynamic @@ -196,6 +196,7 @@ compileOne' m_tc_result mHscMessage = do let logger = hsc_logger hsc_env0 + let tmpfs = hsc_tmpfs hsc_env0 debugTraceMsg logger dflags1 2 (text "compile: input file" <+> text input_fnpp) -- Run the pipeline up to codeGen (so everything up to, but not including, STG) @@ -208,10 +209,10 @@ compileOne' m_tc_result mHscMessage let flags = hsc_dflags hsc_env0 in do unless (gopt Opt_KeepHiFiles flags) $ - addFilesToClean flags TFL_CurrentModule $ + addFilesToClean tmpfs TFL_CurrentModule $ [ml_hi_file $ ms_location summary] unless (gopt Opt_KeepOFiles flags) $ - addFilesToClean flags TFL_GhcSession $ + addFilesToClean tmpfs TFL_GhcSession $ [ml_obj_file $ ms_location summary] case (status, bcknd) of @@ -236,7 +237,7 @@ compileOne' m_tc_result mHscMessage let !linkable = LM (ms_hs_date summary) this_mod [] return $! HomeModInfo iface hmi_details (Just linkable) (HscUpdateSig iface hmi_details, _) -> do - output_fn <- getOutputFilename logger next_phase + output_fn <- getOutputFilename logger tmpfs next_phase (Temporary TFL_CurrentModule) basename dflags next_phase (Just location) @@ -286,7 +287,7 @@ compileOne' m_tc_result mHscMessage (hs_unlinked ++ stub_o) return $! HomeModInfo final_iface hmi_details (Just linkable) (HscRecomp{}, _) -> do - output_fn <- getOutputFilename logger next_phase + output_fn <- getOutputFilename logger tmpfs next_phase (Temporary TFL_CurrentModule) basename dflags next_phase (Just location) -- We're in --make mode: finish the compilation pipeline. @@ -418,7 +419,8 @@ compileEmptyStub dflags hsc_env basename location mod_name = do -- https://gitlab.haskell.org/ghc/ghc/issues/12673 -- and https://github.com/haskell/cabal/issues/2257 let logger = hsc_logger hsc_env - empty_stub <- newTempName logger dflags TFL_CurrentModule "c" + let tmpfs = hsc_tmpfs hsc_env + empty_stub <- newTempName logger tmpfs dflags TFL_CurrentModule "c" let home_unit = hsc_home_unit hsc_env src = text "int" <+> ppr (mkHomeModule home_unit mod_name) <+> text "= 0;" writeFile empty_stub (showSDoc dflags (pprCode CStyle src)) @@ -484,6 +486,7 @@ compileEmptyStub dflags hsc_env basename location mod_name = do -- libraries. link :: GhcLink -- ^ interactive or batch -> Logger -- ^ Logger + -> TmpFs -> Hooks -> DynFlags -- ^ dynamic flags -> UnitEnv -- ^ unit environment @@ -498,13 +501,13 @@ link :: GhcLink -- ^ interactive or batch -- exports main, i.e., we have good reason to believe that linking -- will succeed. -link ghcLink logger hooks dflags unit_env batch_attempt_linking hpt = +link ghcLink logger tmpfs hooks dflags unit_env batch_attempt_linking hpt = case linkHook hooks of Nothing -> case ghcLink of NoLink -> return Succeeded - LinkBinary -> link' logger dflags unit_env batch_attempt_linking hpt - LinkStaticLib -> link' logger dflags unit_env batch_attempt_linking hpt - LinkDynLib -> link' logger dflags unit_env batch_attempt_linking hpt + LinkBinary -> link' logger tmpfs dflags unit_env batch_attempt_linking hpt + LinkStaticLib -> link' logger tmpfs dflags unit_env batch_attempt_linking hpt + LinkDynLib -> link' logger tmpfs dflags unit_env batch_attempt_linking hpt LinkInMemory | platformMisc_ghcWithInterpreter $ platformMisc dflags -> -- Not Linking...(demand linker will do the job) @@ -519,13 +522,14 @@ panicBadLink other = panic ("link: GHC not built to link this way: " ++ show other) link' :: Logger + -> TmpFs -> DynFlags -- ^ dynamic flags -> UnitEnv -- ^ unit environment -> Bool -- ^ attempt linking in batch mode? -> HomePackageTable -- ^ what to link -> IO SuccessFlag -link' logger dflags unit_env batch_attempt_linking hpt +link' logger tmpfs dflags unit_env batch_attempt_linking hpt | batch_attempt_linking = do let @@ -565,11 +569,11 @@ link' logger dflags unit_env batch_attempt_linking hpt -- Don't showPass in Batch mode; doLink will do that for us. let link = case ghcLink dflags of - LinkBinary -> linkBinary - LinkStaticLib -> linkStaticLib - LinkDynLib -> linkDynLibCheck + LinkBinary -> linkBinary logger tmpfs + LinkStaticLib -> linkStaticLib logger + LinkDynLib -> linkDynLibCheck logger tmpfs other -> panicBadLink other - link logger dflags unit_env obj_files pkg_deps + link dflags unit_env obj_files pkg_deps debugTraceMsg logger dflags 3 (text "link: done") @@ -678,11 +682,12 @@ doLink hsc_env stop_phase o_files dflags = hsc_dflags hsc_env logger = hsc_logger hsc_env unit_env = hsc_unit_env hsc_env + tmpfs = hsc_tmpfs hsc_env in case ghcLink dflags of NoLink -> return () - LinkBinary -> linkBinary logger dflags unit_env o_files [] - LinkStaticLib -> linkStaticLib logger dflags unit_env o_files [] - LinkDynLib -> linkDynLibCheck logger dflags unit_env o_files [] + LinkBinary -> linkBinary logger tmpfs dflags unit_env o_files [] + LinkStaticLib -> linkStaticLib logger dflags unit_env o_files [] + LinkDynLib -> linkDynLibCheck logger tmpfs dflags unit_env o_files [] other -> panicBadLink other @@ -719,6 +724,7 @@ runPipeline stop_phase hsc_env0 (input_fn, mb_input_buf, mb_phase) dflags = dflags0 { dumpPrefix = Just (basename ++ ".") } hsc_env = hsc_env0 {hsc_dflags = dflags} logger = hsc_logger hsc_env + tmpfs = hsc_tmpfs hsc_env (input_basename, suffix) = splitExtension input_fn suffix' = drop 1 suffix -- strip off the . @@ -766,7 +772,7 @@ runPipeline stop_phase hsc_env0 (input_fn, mb_input_buf, mb_phase) input_fn' <- case (start_phase, mb_input_buf) of (RealPhase real_start_phase, Just input_buf) -> do let suffix = phaseInputExt real_start_phase - fn <- newTempName logger dflags TFL_CurrentModule suffix + fn <- newTempName logger tmpfs dflags TFL_CurrentModule suffix hdl <- openBinaryFile fn WriteMode -- Add a LINE pragma so reported source locations will -- mention the real input file, not this temp file. @@ -869,7 +875,8 @@ pipeLoop phase input_fn = do return input_fn output -> do pst <- getPipeState - final_fn <- liftIO $ getOutputFilename logger + tmpfs <- hsc_tmpfs <$> getPipeSession + final_fn <- liftIO $ getOutputFilename logger tmpfs stopPhase output (src_basename env) dflags stopPhase (maybe_loc pst) when (final_fn /= input_fn) $ do @@ -954,10 +961,11 @@ runHookedPhase pp input = do phaseOutputFilename :: Phase{-next phase-} -> CompPipeline FilePath phaseOutputFilename next_phase = do PipeEnv{stop_phase, src_basename, output_spec} <- getPipeEnv - PipeState{maybe_loc} <- getPipeState + PipeState{maybe_loc,hsc_env} <- getPipeState dflags <- getDynFlags logger <- getLogger - liftIO $ getOutputFilename logger stop_phase output_spec + let tmpfs = hsc_tmpfs hsc_env + liftIO $ getOutputFilename logger tmpfs stop_phase output_spec src_basename dflags next_phase maybe_loc -- | Computes the next output filename for something in the compilation @@ -976,17 +984,24 @@ phaseOutputFilename next_phase = do -- compiling; this can be used to override the default output -- of an object file. (TODO: do we actually need this?) getOutputFilename - :: Logger -> Phase -> PipelineOutput -> String - -> DynFlags -> Phase{-next phase-} -> Maybe ModLocation -> IO FilePath -getOutputFilename logger stop_phase output basename dflags next_phase maybe_location + :: Logger + -> TmpFs + -> Phase + -> PipelineOutput + -> String + -> DynFlags + -> Phase -- next phase + -> Maybe ModLocation + -> IO FilePath +getOutputFilename logger tmpfs stop_phase output basename dflags next_phase maybe_location | is_last_phase, Persistent <- output = persistent_fn | is_last_phase, SpecificFile <- output = case outputFile dflags of Just f -> return f Nothing -> panic "SpecificFile: No filename" | keep_this_output = persistent_fn - | Temporary lifetime <- output = newTempName logger dflags lifetime suffix - | otherwise = newTempName logger dflags TFL_CurrentModule + | Temporary lifetime <- output = newTempName logger tmpfs dflags lifetime suffix + | otherwise = newTempName logger tmpfs dflags TFL_CurrentModule suffix where hcsuf = hcSuf dflags @@ -1160,7 +1175,10 @@ runPhase (RealPhase (Cpp sf)) input_fn else do output_fn <- phaseOutputFilename (HsPp sf) hsc_env <- getPipeSession - liftIO $ doCpp logger (hsc_dflags hsc_env) (hsc_unit_env hsc_env) + liftIO $ doCpp logger + (hsc_tmpfs hsc_env) + (hsc_dflags hsc_env) + (hsc_unit_env hsc_env) True{-raw-} input_fn output_fn -- re-read the pragmas now that we've preprocessed the file @@ -1389,7 +1407,10 @@ runPhase (RealPhase CmmCpp) input_fn = do hsc_env <- getPipeSession logger <- getLogger output_fn <- phaseOutputFilename Cmm - liftIO $ doCpp logger (hsc_dflags hsc_env) (hsc_unit_env hsc_env) + liftIO $ doCpp logger + (hsc_tmpfs hsc_env) + (hsc_dflags hsc_env) + (hsc_unit_env hsc_env) False{-not raw-} input_fn output_fn return (RealPhase Cmm, output_fn) @@ -1415,6 +1436,7 @@ runPhase (RealPhase cc_phase) input_fn let dflags = hsc_dflags hsc_env let unit_env = hsc_unit_env hsc_env let home_unit = hsc_home_unit hsc_env + let tmpfs = hsc_tmpfs hsc_env let platform = ue_platform unit_env let hcc = cc_phase `eqPhase` HCc @@ -1492,7 +1514,7 @@ runPhase (RealPhase cc_phase) input_fn ghcVersionH <- liftIO $ getGhcVersionPathName dflags unit_env logger <- getLogger - liftIO $ GHC.SysTools.runCc (phaseForeignLanguage cc_phase) logger dflags ( + liftIO $ GHC.SysTools.runCc (phaseForeignLanguage cc_phase) logger tmpfs dflags ( [ GHC.SysTools.FileOption "" input_fn , GHC.SysTools.Option "-o" , GHC.SysTools.FileOption "" output_fn @@ -1747,7 +1769,7 @@ runPhase (RealPhase LlvmMangle) input_fn = do -- merge in stub objects runPhase (RealPhase MergeForeign) input_fn = do - PipeState{foreign_os} <- getPipeState + PipeState{foreign_os,hsc_env} <- getPipeState output_fn <- phaseOutputFilename StopLn liftIO $ createDirectoryIfMissing True (takeDirectory output_fn) if null foreign_os @@ -1755,7 +1777,8 @@ runPhase (RealPhase MergeForeign) input_fn = do else do dflags <- getDynFlags logger <- getLogger - liftIO $ joinObjectFiles logger dflags (input_fn : foreign_os) output_fn + let tmpfs = hsc_tmpfs hsc_env + liftIO $ joinObjectFiles logger tmpfs dflags (input_fn : foreign_os) output_fn return (RealPhase StopLn, output_fn) -- warning suppression @@ -1830,14 +1853,14 @@ getHCFilePackages filename = return [] -linkDynLibCheck :: Logger -> DynFlags -> UnitEnv -> [String] -> [UnitId] -> IO () -linkDynLibCheck logger dflags unit_env o_files dep_units = do +linkDynLibCheck :: Logger -> TmpFs -> DynFlags -> UnitEnv -> [String] -> [UnitId] -> IO () +linkDynLibCheck logger tmpfs dflags unit_env o_files dep_units = do when (haveRtsOptsFlags dflags) $ putLogMsg logger dflags NoReason SevInfo noSrcSpan $ withPprStyle defaultUserStyle (text "Warning: -rtsopts and -with-rtsopts have no effect with -shared." $$ text " Call hs_init_ghc() from your main() function to set these options.") - linkDynLib logger dflags unit_env o_files dep_units + linkDynLib logger tmpfs dflags unit_env o_files dep_units -- ----------------------------------------------------------------------------- @@ -1846,8 +1869,8 @@ linkDynLibCheck logger dflags unit_env o_files dep_units = do -- | Run CPP -- -- UnitState is needed to compute MIN_VERSION macros -doCpp :: Logger -> DynFlags -> UnitEnv -> Bool -> FilePath -> FilePath -> IO () -doCpp logger dflags unit_env raw input_fn output_fn = do +doCpp :: Logger -> TmpFs -> DynFlags -> UnitEnv -> Bool -> FilePath -> FilePath -> IO () +doCpp logger tmpfs dflags unit_env raw input_fn output_fn = do let hscpp_opts = picPOpts dflags let cmdline_include_paths = includePaths dflags let unit_state = ue_units unit_env @@ -1862,7 +1885,8 @@ doCpp logger dflags unit_env raw input_fn output_fn = do let verbFlags = getVerbFlags dflags let cpp_prog args | raw = GHC.SysTools.runCpp logger dflags args - | otherwise = GHC.SysTools.runCc Nothing logger dflags (GHC.SysTools.Option "-E" : args) + | otherwise = GHC.SysTools.runCc Nothing logger tmpfs dflags + (GHC.SysTools.Option "-E" : args) let platform = targetPlatform dflags targetArch = stringEncodeArch $ platformArch platform @@ -1905,7 +1929,7 @@ doCpp logger dflags unit_env raw input_fn output_fn = do pkgs = catMaybes (map (lookupUnit unit_state) uids) mb_macro_include <- if not (null pkgs) && gopt Opt_VersionMacros dflags - then do macro_stub <- newTempName logger dflags TFL_CurrentModule "h" + then do macro_stub <- newTempName logger tmpfs dflags TFL_CurrentModule "h" writeFile macro_stub (generatePackageVersionMacros pkgs) -- Include version macros for every *exposed* package. -- Without -hide-all-packages and with a package database @@ -2035,12 +2059,12 @@ via gcc. -} -joinObjectFiles :: Logger -> DynFlags -> [FilePath] -> FilePath -> IO () -joinObjectFiles logger dflags o_files output_fn = do +joinObjectFiles :: Logger -> TmpFs -> DynFlags -> [FilePath] -> FilePath -> IO () +joinObjectFiles logger tmpfs dflags o_files output_fn = do let toolSettings' = toolSettings dflags ldIsGnuLd = toolSettings_ldIsGnuLd toolSettings' osInfo = platformOS (targetPlatform dflags) - ld_r args = GHC.SysTools.runMergeObjects logger dflags ( + ld_r args = GHC.SysTools.runMergeObjects logger tmpfs dflags ( -- See Note [Produce big objects on Windows] concat [ [GHC.SysTools.Option "--oformat", GHC.SysTools.Option "pe-bigobj-x86-64"] @@ -2060,14 +2084,14 @@ joinObjectFiles logger dflags o_files output_fn = do if ldIsGnuLd then do - script <- newTempName logger dflags TFL_CurrentModule "ldscript" + script <- newTempName logger tmpfs dflags TFL_CurrentModule "ldscript" cwd <- getCurrentDirectory let o_files_abs = map (\x -> "\"" ++ (cwd </> x) ++ "\"") o_files writeFile script $ "INPUT(" ++ unwords o_files_abs ++ ")" ld_r [GHC.SysTools.FileOption "" script] else if toolSettings_ldSupportsFilelist toolSettings' then do - filelist <- newTempName logger dflags TFL_CurrentModule "filelist" + filelist <- newTempName logger tmpfs dflags TFL_CurrentModule "filelist" writeFile filelist $ unlines o_files ld_r [GHC.SysTools.Option "-filelist", GHC.SysTools.FileOption "" filelist] diff --git a/compiler/GHC/Driver/Pipeline/Monad.hs b/compiler/GHC/Driver/Pipeline/Monad.hs index 53d4e98b0d..4a33543527 100644 --- a/compiler/GHC/Driver/Pipeline/Monad.hs +++ b/compiler/GHC/Driver/Pipeline/Monad.hs @@ -22,7 +22,7 @@ import GHC.Driver.Phases import GHC.Driver.Env import GHC.Driver.Plugins -import GHC.SysTools.FileCleanup (TempFileLifetime) +import GHC.Utils.TmpFs (TempFileLifetime) import GHC.Types.SourceFile diff --git a/compiler/GHC/Driver/Session.hs b/compiler/GHC/Driver/Session.hs index 3633edf48c..8b7ddd321d 100644 --- a/compiler/GHC/Driver/Session.hs +++ b/compiler/GHC/Driver/Session.hs @@ -209,9 +209,6 @@ module GHC.Driver.Session ( LinkerInfo(..), CompilerInfo(..), - -- * File cleanup - FilesToClean(..), emptyFilesToClean, - -- * Include specifications IncludeSpecs(..), addGlobalInclude, addQuoteInclude, flattenIncludes, @@ -271,9 +268,6 @@ import Control.Monad.Trans.Except import Data.Ord import Data.Char import Data.List (intercalate, delete, sortBy) -import Data.Map (Map) -import qualified Data.Map as Map -import Data.Set (Set) import qualified Data.Set as Set import System.FilePath import System.Directory @@ -580,13 +574,6 @@ data DynFlags = DynFlags { packageEnv :: Maybe FilePath, -- ^ Filepath to the package environment file (if overriding default) - -- Temporary files - -- These have to be IORefs, because the defaultCleanupHandler needs to - -- know what to clean when an exception happens - filesToClean :: IORef FilesToClean, - dirsToClean :: IORef (Map FilePath FilePath), - -- The next available suffix to uniquely name a temp file, updated atomically - nextTempSuffix :: IORef Int, -- hsc dynamic flags dumpFlags :: EnumSet DumpFlag, @@ -1061,9 +1048,6 @@ initDynFlags dflags = do platformCanGenerateDynamicToo = platformOS (targetPlatform dflags) /= OSMinGW32 refDynamicTooFailed <- newIORef (not platformCanGenerateDynamicToo) - refNextTempSuffix <- newIORef 0 - refFilesToClean <- newIORef emptyFilesToClean - refDirsToClean <- newIORef Map.empty refRtldInfo <- newIORef Nothing refRtccInfo <- newIORef Nothing wrapperNum <- newIORef emptyModuleEnv @@ -1084,9 +1068,6 @@ initDynFlags dflags = do (useColor dflags, colScheme dflags) return dflags{ dynamicTooFailed = refDynamicTooFailed, - nextTempSuffix = refNextTempSuffix, - filesToClean = refFilesToClean, - dirsToClean = refDirsToClean, nextWrapperNum = wrapperNum, useUnicode = useUnicode', useColor = useColor', @@ -1212,9 +1193,6 @@ defaultDynFlags mySettings llvmConfig = depExcludeMods = [], depSuffixes = [], -- end of ghc -M values - nextTempSuffix = panic "defaultDynFlags: No nextTempSuffix", - filesToClean = panic "defaultDynFlags: No filesToClean", - dirsToClean = panic "defaultDynFlags: No dirsToClean", ghcVersionFile = Nothing, haddockOptions = Nothing, dumpFlags = EnumSet.empty, @@ -4883,26 +4861,6 @@ decodeSize str foreign import ccall unsafe "setHeapSize" setHeapSize :: Int -> IO () foreign import ccall unsafe "enableTimingStats" enableTimingStats :: IO () --- ----------------------------------------------------------------------------- --- Types for managing temporary files. --- --- these are here because FilesToClean is used in DynFlags - --- | A collection of files that must be deleted before ghc exits. --- The current collection --- is stored in an IORef in DynFlags, 'filesToClean'. -data FilesToClean = FilesToClean { - ftcGhcSession :: !(Set FilePath), - -- ^ Files that will be deleted at the end of runGhc(T) - ftcCurrentModule :: !(Set FilePath) - -- ^ Files that will be deleted the next time - -- 'FileCleanup.cleanCurrentModuleTempFiles' is called, or otherwise at the - -- end of the session. - } - --- | An empty FilesToClean -emptyFilesToClean :: FilesToClean -emptyFilesToClean = FilesToClean Set.empty Set.empty -- | Initialize the pretty-printing options initSDocContext :: DynFlags -> PprStyle -> SDocContext |