summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/GHC/Driver/Make.hs1
-rw-r--r--compiler/GHC/Driver/Pipeline.hs1
-rw-r--r--compiler/GHC/Runtime/Loader.hs23
3 files changed, 25 insertions, 0 deletions
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