From af51225b02bc2e45184df685e87d8be74936db6e Mon Sep 17 00:00:00 2001 From: Matthew Pickering Date: Mon, 27 Mar 2023 13:20:26 +0100 Subject: docs: Add Note [Timing of plugin initialization] --- compiler/GHC/Driver/Make.hs | 1 + compiler/GHC/Driver/Pipeline.hs | 1 + compiler/GHC/Runtime/Loader.hs | 23 +++++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/compiler/GHC/Driver/Make.hs b/compiler/GHC/Driver/Make.hs index 2cc762b9cd..b7bc05f74a 100644 --- a/compiler/GHC/Driver/Make.hs +++ b/compiler/GHC/Driver/Make.hs @@ -696,6 +696,7 @@ load' :: GhcMonad m => Maybe ModIfaceCache -> LoadHowMuch -> Maybe Messager -> M load' mhmi_cache how_much mHscMessage mod_graph = do -- In normal usage plugins are initialised already by ghc/Main.hs this is protective -- for any client who might interact with GHC via load'. + -- See Note [Timing of plugin initialization] initializeSessionPlugins modifySession $ \hsc_env -> hsc_env { hsc_mod_graph = mod_graph } guessOutputFile diff --git a/compiler/GHC/Driver/Pipeline.hs b/compiler/GHC/Driver/Pipeline.hs index f709ad801c..f22a4a8655 100644 --- a/compiler/GHC/Driver/Pipeline.hs +++ b/compiler/GHC/Driver/Pipeline.hs @@ -531,6 +531,7 @@ oneShot orig_hsc_env stop_phase srcs = do -- In oneshot mode, initialise plugins specified on command line -- we also initialise in ghc/Main but this might be used as an entry point by API clients who -- should initialise their own plugins but may not. + -- See Note [Timing of plugin initialization] hsc_env <- initializePlugins orig_hsc_env o_files <- mapMaybeM (compileFile hsc_env stop_phase) srcs case stop_phase of diff --git a/compiler/GHC/Runtime/Loader.hs b/compiler/GHC/Runtime/Loader.hs index 3349ed0020..5617376f60 100644 --- a/compiler/GHC/Runtime/Loader.hs +++ b/compiler/GHC/Runtime/Loader.hs @@ -76,6 +76,29 @@ import Data.List (unzip4) import GHC.Iface.Errors.Ppr import GHC.Driver.Monad +{- Note [Timing of plugin initialization] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Plugins needs to be initialised as soon as possible in the pipeline. This is because +driver plugins are executed immediately after being loaded, which can modify anything +in the HscEnv, including the logger and DynFlags (for example #21279). For example, +in ghc/Main.hs the logger is used almost immediately after the session has been initialised +and so if a user overwrites the logger expecting all output to go there then unless +the plugins are initialised before that point then unexpected things will happen. + +We initialise plugins in ghc/Main.hs for the main ghc executable. + +When people are using the GHC API, they also need to initialise plugins +at the highest level possible for things to work as expected. We keep +some defensive calls to plugin initialisation in functions like `load'` and `oneshot` +to catch cases where API users have not initialised their own plugins. + +In addition to this, there needs to be an initialisation call for each module +just in case the user has enabled a plugin just for that module using OPTIONS_GHC +pragma. + +-} + -- | Initialise plugins specified by the current DynFlags and update the session. initializeSessionPlugins :: GhcMonad m => m () initializeSessionPlugins = getSession >>= liftIO . initializePlugins >>= setSession -- cgit v1.2.1