summaryrefslogtreecommitdiff
path: root/docs/users_guide/extending_ghc.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/users_guide/extending_ghc.rst')
-rw-r--r--docs/users_guide/extending_ghc.rst321
1 files changed, 312 insertions, 9 deletions
diff --git a/docs/users_guide/extending_ghc.rst b/docs/users_guide/extending_ghc.rst
index 4a3e02e83e..ef07f61f2d 100644
--- a/docs/users_guide/extending_ghc.rst
+++ b/docs/users_guide/extending_ghc.rst
@@ -130,10 +130,10 @@ when invoked:
import GHC
import GHC.Paths ( libdir )
- import DynFlags ( defaultLogAction )
-
- main =
- defaultErrorHandler defaultLogAction $ do
+ import DynFlags ( defaultFatalMessager, defaultFlushOut )
+
+ main =
+ defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
@@ -157,7 +157,7 @@ Compiling it results in:
[1 of 1] Compiling Main ( simple_ghc_api.hs, simple_ghc_api.o )
Linking simple_ghc_api ...
$ ./simple_ghc_api
- $ ./test_main
+ $ ./test_main
hi
$
@@ -179,12 +179,15 @@ GHC's intermediate language, Core. Plugins are suitable for experimental
analysis or optimization, and require no changes to GHC's source code to
use.
-Plugins cannot optimize/inspect C--, nor can they implement things like
+Plugins cannot optimize/inspect C-\\-, nor can they implement things like
parser/front-end modifications like GCC, apart from limited changes to
the constraint solver. If you feel strongly that any of these
restrictions are too onerous,
:ghc-wiki:`please give the GHC team a shout <MailingListsAndIRC>`.
+Plugins do not work with ``-fexternal-interpreter``. If you need to run plugins
+with ``-fexternal-interpreter`` let GHC developers know in :ghc-ticket:`14335`.
+
.. _using-compiler-plugins:
Using compiler plugins
@@ -196,13 +199,22 @@ module in a registered package that exports a plugin. Arguments can be given to
plugins with the :ghc-flag:`-fplugin-opt=⟨module⟩:⟨args⟩` option.
.. ghc-flag:: -fplugin=⟨module⟩
+ :shortdesc: Load a plugin exported by a given module
+ :type: dynamic
+ :category: plugins
Load the plugin in the given module. The module must be a member of a
package registered in GHC's package database.
.. ghc-flag:: -fplugin-opt=⟨module⟩:⟨args⟩
+ :shortdesc: Give arguments to a plugin module; module must be specified with
+ :ghc-flag:`-fplugin=⟨module⟩`
+ :type: dynamic
+ :category: plugins
+
+ Give arguments to a plugin module; module must be specified with
+ :ghc-flag:`-fplugin=⟨module⟩`.
- Pass arguments ⟨args⟩ to the given plugin.
As an example, in order to load the plugin exported by ``Foo.Plugin`` in
the package ``foo-ghc-plugin``, and give it the parameter "baz", we
@@ -221,12 +233,27 @@ would invoke GHC like this:
Linking Test ...
$
+Alternatively, core plugins can be specified with Template Haskell.
+
+::
+
+ addCorePlugin "Foo.Plugin"
+
+This inserts the plugin as a core-to-core pass. Unlike `-fplugin=(module)`,
+the plugin module can't reside in the same package as the module calling
+:th-ref:`Language.Haskell.TH.Syntax.addCorePlugin`. This way, the
+implementation can expect the plugin to be built by the time
+it is needed.
+
Plugin modules live in a separate namespace from
the user import namespace. By default, these two namespaces are
the same; however, there are a few command line options which
control specifically plugin packages:
.. ghc-flag:: -plugin-package ⟨pkg⟩
+ :shortdesc: Expose ⟨pkg⟩ for plugins
+ :type: dynamic
+ :category: plugins
This option causes the installed package ⟨pkg⟩ to be exposed for plugins,
such as :ghc-flag:`-fplugin=⟨module⟩`. The package ⟨pkg⟩ can be specified
@@ -241,6 +268,9 @@ control specifically plugin packages:
to be linked into the resulting executable or shared object.
.. ghc-flag:: -plugin-package-id ⟨pkg-id⟩
+ :shortdesc: Expose ⟨pkg-id⟩ for plugins
+ :type: dynamic
+ :category: plugins
Exposes a package in the plugin namespace like :ghc-flag:`-plugin-package
⟨pkg⟩`, but the package is named by its installed package ID rather than by
@@ -251,6 +281,9 @@ control specifically plugin packages:
described in :ref:`package-thinning-and-renaming`.
.. ghc-flag:: -hide-all-plugin-packages
+ :shortdesc: Hide all packages for plugins by default
+ :type: dynamic
+ :category: plugins
By default, all exposed packages in the normal, source import namespace are
also available for plugins. This causes those packages to be hidden by
@@ -319,7 +352,7 @@ Core plugins in more detail
``CoreToDo`` is effectively a data type that describes all the kinds of
optimization passes GHC does on Core. There are passes for
-simplification, CSE, vectorisation, etc. There is a specific case for
+simplification, CSE, etc. There is a specific case for
plugins, ``CoreDoPluginPass :: String -> PluginPass -> CoreToDo`` which
should be what you always use when inserting your own pass into the
pipeline. The first parameter is the name of the plugin, and the second
@@ -392,7 +425,7 @@ in a module it compiles:
where printBind :: DynFlags -> CoreBind -> CoreM CoreBind
printBind dflags bndr@(NonRec b _) = do
putMsgS $ "Non-recursive binding named " ++ showSDoc dflags (ppr b)
- return bndr
+ return bndr
printBind _ bndr = return bndr
.. _getting-annotations:
@@ -567,6 +600,276 @@ the plugin to create equality axioms for use in evidence terms, but GHC
does not check their consistency, and inconsistent axiom sets may lead
to segfaults or other runtime misbehaviour.
+.. _source-plugins:
+
+Source plugins
+~~~~~~~~~~~~~~
+
+In addition to core and type checker plugins, you can install plugins that can
+access different representations of the source code. The main purpose of these
+plugins is to make it easier to implement development tools.
+
+There are several different access points that you can use for defining plugins
+that access the representations. All these fields receive the list of
+``CommandLineOption`` strings that are passed to the compiler using the
+:ghc-flag:`-fplugin-opt` flags.
+
+::
+
+ plugin :: Plugin
+ plugin = defaultPlugin {
+ parsedResultAction = parsed
+ , typeCheckResultAction = typechecked
+ , spliceRunAction = spliceRun
+ , interfaceLoadAction = interfaceLoad
+ , renamedResultAction = renamed
+ }
+
+Parsed representation
+^^^^^^^^^^^^^^^^^^^^^
+
+When you want to define a plugin that uses the syntax tree of the source code,
+you would like to override the ``parsedResultAction`` field. This access point
+enables you to get access to information about the lexical tokens and comments
+in the source code as well as the original syntax tree of the compiled module.
+
+::
+
+ parsed :: [CommandLineOption] -> ModSummary -> HsParsedModule
+ -> Hsc HsParsedModule
+
+The ``ModSummary`` contains useful
+meta-information about the compiled module. The ``HsParsedModule`` contains the
+lexical and syntactical information we mentioned before. The result that you
+return will change the result of the parsing. If you don't want to change the
+result, just return the ``HsParsedModule`` that you received as the argument.
+
+Type checked representation
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When you want to define a plugin that needs semantic information about the
+source code, use the ``typeCheckResultAction`` field. For example, if your
+plugin have to decide if two names are referencing the same definition or it has
+to check the type of a function it is using semantic information. In this case
+you need to access the renamed or type checked version of the syntax tree with
+``typeCheckResultAction`` or ``renamedResultAction``.
+
+::
+
+ typechecked :: [CommandLineOption] -> ModSummary -> TcGblEnv -> TcM TcGblEnv
+ renamed :: [CommandLineOption] -> TcGblEnv -> HsGroup GhcRn -> TcM (TcGblEnv, HsGroup GhcRn)
+
+By overriding the ``renamedResultAction`` field we can modify each ``HsGroup``
+after it has been renamed. A source file is seperated into groups depending on
+the location of template haskell splices so the contents of these groups may
+not be intuitive. In order to save the entire renamed AST for inspection
+at the end of typechecking you can set ``renamedResultAction`` to ``keepRenamedSource``
+which is provided by the ``Plugins`` module.
+This is important because some parts of the renamed
+syntax tree (for example, imports) are not found in the typechecked one.
+
+
+
+Evaluated code
+^^^^^^^^^^^^^^
+
+When the compiler type checks the source code, :ref:`template-haskell` Splices
+and :ref:`th-quasiquotation` will be replaced by the syntax tree fragments
+generated from them. However for tools that operate on the source code the
+code generator is usually more interesting than the generated code. For this
+reason we included ``spliceRunAction``. This field is invoked on each expression
+before they are evaluated. The input is type checked, so semantic information is
+available for these syntax tree fragments. If you return a different expression
+you can change the code that is generated.
+
+
+::
+
+ spliceRun :: [CommandLineOption] -> LHsExpr GhcTc -> TcM (LHsExpr GhcTc)
+
+
+However take care that the generated definitions are still in the input of
+``typeCheckResultAction``. If your don't take care to filter the typechecked
+input, the behavior of your tool might be inconsistent.
+
+Interface files
+^^^^^^^^^^^^^^^
+
+Sometimes when you are writing a tool, knowing the source code is not enough,
+you also have to know details about the modules that you import. In this case we
+suggest using the ``interfaceLoadAction``. This will be called each time when
+the code of an already compiled module is loaded. It will be invoked for modules
+from installed packages and even modules that are installed with GHC. It will
+NOT be invoked with your own modules.
+
+::
+
+ interfaceLoad :: forall lcl . [CommandLineOption] -> ModIface
+ -> IfM lcl ModIface
+
+In the ``ModIface`` datatype you can find lots of useful information, including
+the exported definitions and type class instances.
+
+
+Source plugin example
+^^^^^^^^^^^^^^^^^^^^^
+
+In this example, we inspect all available details of the compiled source code.
+We don't change any of the representation, but write out the details to the
+standard output. The pretty printed representation of the parsed, renamed and
+type checked syntax tree will be in the output as well as the evaluated splices
+and quasi quotes. The name of the interfaces that are loaded will also be
+displayed.
+
+::
+
+ module SourcePlugin where
+
+ import Control.Monad.IO.Class
+ import DynFlags (getDynFlags)
+ import Plugins
+ import HscTypes
+ import TcRnTypes
+ import HsExtension
+ import HsDecls
+ import HsExpr
+ import HsImpExp
+ import Avail
+ import Outputable
+ import HsDoc
+
+ plugin :: Plugin
+ plugin = defaultPlugin { parsedResultAction = parsedPlugin
+ , renamedResultAction = Just renamedAction
+ , typeCheckResultAction = typecheckPlugin
+ , spliceRunAction = metaPlugin
+ , interfaceLoadAction = interfaceLoadPlugin
+ }
+
+ parsedPlugin :: [CommandLineOption] -> ModSummary -> HsParsedModule -> Hsc HsParsedModule
+ parsedPlugin _ _ pm
+ = do dflags <- getDynFlags
+ liftIO $ putStrLn $ "parsePlugin: \n" ++ (showSDoc dflags $ ppr $ hpm_module pm)
+ return pm
+
+ renamedAction :: [CommandLineOption] -> ModSummary
+ -> ( HsGroup GhcRn, [LImportDecl GhcRn]
+ , Maybe [(LIE GhcRn, Avails)], Maybe LHsDocString )
+ -> TcM ()
+ renamedAction _ _ ( gr, _, _, _ )
+ = do dflags <- getDynFlags
+ liftIO $ putStrLn $ "typeCheckPlugin (rn): " ++ (showSDoc dflags $ ppr gr)
+
+ typecheckPlugin :: [CommandLineOption] -> ModSummary -> TcGblEnv -> TcM TcGblEnv
+ typecheckPlugin _ _ tc
+ = do dflags <- getDynFlags
+ liftIO $ putStrLn $ "typeCheckPlugin (rn): \n" ++ (showSDoc dflags $ ppr $ tcg_rn_decls tc)
+ liftIO $ putStrLn $ "typeCheckPlugin (tc): \n" ++ (showSDoc dflags $ ppr $ tcg_binds tc)
+ return tc
+
+ metaPlugin :: [CommandLineOption] -> LHsExpr GhcTc -> TcM (LHsExpr GhcTc)
+ metaPlugin _ meta
+ = do dflags <- getDynFlags
+ liftIO $ putStrLn $ "meta: " ++ (showSDoc dflags $ ppr meta)
+ return meta
+
+ interfaceLoadPlugin :: [CommandLineOption] -> ModIface -> IfM lcl ModIface
+ interfaceLoadPlugin _ iface
+ = do dflags <- getDynFlags
+ liftIO $ putStrLn $ "interface loaded: " ++ (showSDoc dflags $ ppr $ mi_module iface)
+ return iface
+
+When you compile a simple module that contains Template Haskell splice
+
+::
+
+ {-# LANGUAGE TemplateHaskell #-}
+ module A where
+
+ a = ()
+
+ $(return [])
+
+with the compiler flags ``-fplugin SourcePlugin`` it will give the following
+output:
+
+.. code-block:: none
+
+ parsePlugin:
+ module A where
+ a = ()
+ $(return [])
+ interface loaded: Prelude
+ interface loaded: GHC.Float
+ interface loaded: GHC.Base
+ interface loaded: Language.Haskell.TH.Lib.Internal
+ interface loaded: Language.Haskell.TH.Syntax
+ interface loaded: GHC.Types
+ meta: return []
+ interface loaded: GHC.Integer.Type
+ typeCheckPlugin (rn):
+ Just a = ()
+ typeCheckPlugin (tc):
+ {$trModule = Module (TrNameS "main"#) (TrNameS "A"#), a = ()}
+
+
+.. _plugin_recompilation:
+
+Controlling Recompilation
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default, modules compiled with plugins are always recompiled even if the source file is
+unchanged. This most conservative option is taken due to the ability of plugins
+to perform arbitrary IO actions. In order to control the recompilation behaviour
+you can modify the ``pluginRecompile`` field in ``Plugin``. ::
+
+ plugin :: Plugin
+ plugin = defaultPlugin {
+ installCoreToDos = install,
+ pluginRecompile = purePlugin
+ }
+
+By inspecting the example ``plugin`` defined above, we can see that it is pure. This
+means that if the two modules have the same fingerprint then the plugin
+will always return the same result. Declaring a plugin as pure means that
+the plugin will never cause a module to be recompiled.
+
+In general, the ``pluginRecompile`` field has the following type::
+
+ pluginRecompile :: [CommandLineOption] -> IO PluginRecompile
+
+The ``PluginRecompile`` data type is an enumeration determining how the plugin
+should affect recompilation. ::
+ data PluginRecompile = ForceRecompile | NoForceRecompile | MaybeRecompile Fingerprint
+
+A plugin which declares itself impure using ``ForceRecompile`` will always
+trigger a recompilation of the current module. ``NoForceRecompile`` is used
+for "pure" plugins which don't need to be rerun unless a module would ordinarily
+be recompiled. ``MaybeRecompile`` computes a ``Fingerprint`` and if this ``Fingerprint``
+is different to a previously computed ``Fingerprint`` for the plugin, then
+we recompile the module.
+
+As such, ``purePlugin`` is defined as a function which always returns ``NoForceRecompile``. ::
+
+ purePlugin :: [CommandLineOption] -> IO PluginRecompile
+ purePlugin _ = return NoForceRecompile
+
+Users can use the same functions that GHC uses internally to compute fingerprints.
+The `GHC.Fingerprint
+<https://hackage.haskell.org/package/base-4.10.1.0/docs/GHC-Fingerprint.html>`_ module provides useful functions for constructing fingerprints. For example, combining
+together ``fingerprintFingerprints`` and ``fingerprintString`` provides an easy to
+to naively fingerprint the arguments to a plugin. ::
+
+ pluginFlagRecompile :: [CommandLineOption] -> IO PluginRecompile
+ pluginFlagRecompile =
+ return . MaybeRecompile . fingerprintFingerprints . map fingerprintString . sort
+
+``defaultPlugin`` defines ``pluginRecompile`` to be ``impurePlugin`` which
+is the most conservative and backwards compatible option. ::
+
+ impurePlugin :: [CommandLineOption] -> IO PluginRecompile
+ impurePlugin _ = return ForceRecompile
+
.. _frontend_plugins:
Frontend plugins