summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorAlp Mestanogullari <alpmestan@gmail.com>2019-09-27 01:50:21 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2019-10-23 05:58:48 -0400
commit900cf195ed9b372dadc378182a617a1bdf065908 (patch)
tree6bc8fdd70491f06d627d4f987ff7f06d611a692d /docs
parent1cd3fa299c85f1b324c22288669c75246e3bc575 (diff)
downloadhaskell-900cf195ed9b372dadc378182a617a1bdf065908.tar.gz
compiler: introduce DynFlags plugins
They have type '[CommandLineOpts] -> Maybe (DynFlags -> IO DynFlags)'. All plugins that supply a non-Nothing 'dynflagsPlugin' will see their updates applied to the current DynFlags right after the plugins are loaded. One use case for this is to superseede !1580 for registering hooks from a plugin. Frontend/parser plugins were considered to achieve this but they respectively conflict with how this plugin is going to be used and don't allow overriding/modifying the DynFlags, which is how hooks have to be registered. This commit comes with a test, 'test-hook-plugin', that registers a "fake" meta hook that replaces TH expressions with the 0 integer literal.
Diffstat (limited to 'docs')
-rw-r--r--docs/users_guide/8.10.1-notes.rst6
-rw-r--r--docs/users_guide/extending_ghc.rst106
2 files changed, 112 insertions, 0 deletions
diff --git a/docs/users_guide/8.10.1-notes.rst b/docs/users_guide/8.10.1-notes.rst
index eb06b02ac8..64c2da2e09 100644
--- a/docs/users_guide/8.10.1-notes.rst
+++ b/docs/users_guide/8.10.1-notes.rst
@@ -177,6 +177,12 @@ Compiler
been patched to no longer have have the MAX_PATH limit. Windows users should no longer
have any issues with long path names.
+- Introduce ``DynFlags`` plugins, that allow users to modidy the ``DynFlags``
+ that GHC is going to use when processing a set of files, from plugins.
+ They can be used for applying tiny configuration changes, registering hooks
+ and much more. See the :ref:`user guide <dynflags_plugins>` for
+ more details as well as an example.
+
GHCi
~~~~
diff --git a/docs/users_guide/extending_ghc.rst b/docs/users_guide/extending_ghc.rst
index 0ed65d13b3..4dfb4e4504 100644
--- a/docs/users_guide/extending_ghc.rst
+++ b/docs/users_guide/extending_ghc.rst
@@ -367,6 +367,23 @@ cabal for instance,) you can then use it by just specifying
``-fplugin=DoNothing.Plugin`` on the command line, and during the
compilation you should see GHC say 'Hello'.
+Running multiple plugins is also supported, by passing
+multiple ``-fplugin=...`` options. GHC will load the plugins
+in the order in which they are specified on the command line
+and, when appropriate, compose their effects in the same
+order. That is, if we had two Core plugins, ``Plugin1`` and
+``Plugin2``, each defining an ``install`` function like
+the one above, then GHC would first run ``Plugin1.install``
+on the default ``[CoreToDo]``, take the result and feed it to
+``Plugin2.install``. ``-fplugin=Plugin1 -fplugin=Plugin2``
+will update the Core pipeline by applying
+``Plugin1.install opts1 >=> Plugin2.install opts2`` (where
+``opts1`` and ``opts2`` are the options passed to each plugin
+using ``-fplugin-opt=...``). This is not specific to Core
+plugins but holds for all the types of plugins that can be
+composed or sequenced in some way: the first plugin to appear
+on the GHC command line will always act first.
+
.. _core-plugins-in-more-detail:
Core plugins in more detail
@@ -1265,3 +1282,92 @@ were passed to it, and then exits.
Provided you have compiled this plugin and registered it in a package,
you can just use it by specifying ``--frontend DoNothing.FrontendPlugin``
on the command line to GHC.
+
+.. _dynflags_plugins:
+
+DynFlags plugins
+~~~~~~~~~~~~~~~~
+
+A DynFlags plugin allows you to modify the ``DynFlags`` that GHC
+is going to use when processing a given (set of) file(s).
+``DynFlags`` is a record containing all sorts of configuration
+and command line data, from verbosity level to the integer library
+to use, including compiler hooks, plugins and pretty-printing options.
+DynFlags plugins allow plugin authors to update any of those values
+before GHC starts doing any actual work, effectively meaning that
+the updates specified by the plugin will be taken into account and
+influence GHC's behaviour.
+
+One of the motivating examples was the ability to register
+compiler hooks from a plugin. For example, one might want to modify
+the way Template Haskell code is executed. This is achievable by
+updating the ``hooks`` field of the ``DynFlags`` type, recording
+our custom "meta hook" in the right place. A simple application of
+this idea can be seen below:
+
+::
+
+ module DynFlagsPlugin (plugin) where
+
+ import BasicTypes
+ import GhcPlugins
+ import GHC.Hs.Expr
+ import GHC.Hs.Extension
+ import GHC.Hs.Lit
+ import Hooks
+ import TcRnMonad
+
+ plugin :: Plugin
+ plugin = defaultPlugin { dynflagsPlugin = hooksP }
+
+ hooksP :: [CommandLineOption] -> DynFlags -> IO DynFlags
+ hooksP opts dflags = return $ dflags
+ { hooks = (hooks dflags)
+ { runMetaHook = Just (fakeRunMeta opts) }
+ }
+
+ -- This meta hook doesn't actually care running code in splices,
+ -- it just replaces any expression splice with the "0"
+ -- integer literal, and errors out on all other types of
+ -- meta requests.
+ fakeRunMeta :: [CommandLineOption] -> MetaHook TcM
+ fakeRunMeta opts (MetaE r) _ = do
+ liftIO . putStrLn $ "Options = " ++ show opts
+ pure $ r zero
+
+ where zero :: LHsExpr GhcPs
+ zero = L noSrcSpan $ HsLit NoExtField $
+ HsInt NoExtField (mkIntegralLit (0 :: Int))
+
+ fakeRunMeta _ _ _ = error "fakeRunMeta: unimplemented"
+
+This simple plugin takes over the execution of Template Haskell code,
+replacing any expression splice it encounters by ``0`` (at type
+``Int``), and errors out on any other type of splice.
+
+Therefore, if we run GHC against the following code using the plugin
+from above:
+
+::
+
+ {-# OPTIONS -fplugin=DynFlagsPlugin #-}
+ {-# LANGUAGE TemplateHaskell #-}
+ module Main where
+
+ main :: IO ()
+ main = print $( [|1|] )
+
+This will not actually evaluate ``[|1|]``, but instead replace it
+with the ``0 :: Int`` literal.
+
+Just like the other types of plugins, you can write ``DynFlags`` plugins
+that can take and make use of some options that you can then specify
+using the ``-fplugin-opt`` flag. In the ``DynFlagsPlugin`` code from
+above, the said options would be available in the ``opts`` argument of
+``hooksP``.
+
+Finally, since those ``DynFlags`` updates happen after the plugins are loaded,
+you cannot from a ``DynFlags`` plugin register other plugins by just adding them
+to the ``plugins`` field of ``DynFlags``. In order to achieve this, you would
+have to load them yourself and store the result into the ``cachedPlugins``
+field of ``DynFlags``.