summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/deSugar/Desugar.hs2
-rw-r--r--compiler/iface/MkIface.hs18
-rw-r--r--compiler/main/DynFlags.hs19
-rw-r--r--compiler/main/DynamicLoading.hs13
-rw-r--r--compiler/main/Plugins.hs45
-rw-r--r--compiler/main/Plugins.hs-boot1
-rw-r--r--compiler/typecheck/TcRnDriver.hs3
-rw-r--r--testsuite/tests/plugins/all.T6
-rw-r--r--testsuite/tests/plugins/static-plugins-module.hs2
-rw-r--r--testsuite/tests/plugins/static-plugins.hs80
-rw-r--r--testsuite/tests/plugins/static-plugins.stdout25
11 files changed, 178 insertions, 36 deletions
diff --git a/compiler/deSugar/Desugar.hs b/compiler/deSugar/Desugar.hs
index 0ed35f2d4c..aa24ee0a5d 100644
--- a/compiler/deSugar/Desugar.hs
+++ b/compiler/deSugar/Desugar.hs
@@ -169,7 +169,7 @@ deSugar hsc_env
; let used_names = mkUsedNames tcg_env
pluginModules =
- map lpModule (plugins (hsc_dflags hsc_env))
+ map lpModule (cachedPlugins (hsc_dflags hsc_env))
; deps <- mkDependencies (thisInstalledUnitId (hsc_dflags hsc_env))
(map mi_module pluginModules) tcg_env
diff --git a/compiler/iface/MkIface.hs b/compiler/iface/MkIface.hs
index aba14baa2d..7b66472d7a 100644
--- a/compiler/iface/MkIface.hs
+++ b/compiler/iface/MkIface.hs
@@ -119,7 +119,8 @@ import Data.Ord
import Data.IORef
import System.Directory
import System.FilePath
-import Plugins ( PluginRecompile(..), Plugin(..), LoadedPlugin(..))
+import Plugins ( PluginRecompile(..), PluginWithArgs(..), LoadedPlugin(..),
+ pluginRecompile', plugins )
--Qualified import so we can define a Semigroup instance
-- but it doesn't clash with Outputable.<>
@@ -189,7 +190,7 @@ mkIfaceTc hsc_env maybe_old_fingerprint safe_mode mod_details
= do
let used_names = mkUsedNames tc_result
let pluginModules =
- map lpModule (plugins (hsc_dflags hsc_env))
+ map lpModule (cachedPlugins (hsc_dflags hsc_env))
deps <- mkDependencies
(thisInstalledUnitId (hsc_dflags hsc_env))
(map mi_module pluginModules) tc_result
@@ -1324,17 +1325,16 @@ checkPlugins :: HscEnv -> ModIface -> IfG RecompileRequired
checkPlugins hsc iface = liftIO $ do
-- [(ModuleName, Plugin, [Opts])]
let old_fingerprint = mi_plugin_hash iface
- loaded_plugins = plugins (hsc_dflags hsc)
- res <- mconcat <$> mapM checkPlugin loaded_plugins
+ res <- mconcat <$> mapM pluginRecompile' (plugins (hsc_dflags hsc))
return (pluginRecompileToRecompileRequired old_fingerprint res)
fingerprintPlugins :: HscEnv -> IO Fingerprint
fingerprintPlugins hsc_env = do
- fingerprintPlugins' (plugins (hsc_dflags hsc_env))
+ fingerprintPlugins' $ plugins(hsc_dflags hsc_env)
-fingerprintPlugins' :: [LoadedPlugin] -> IO Fingerprint
+fingerprintPlugins' :: [PluginWithArgs] -> IO Fingerprint
fingerprintPlugins' plugins = do
- res <- mconcat <$> mapM checkPlugin plugins
+ res <- mconcat <$> mapM pluginRecompile' plugins
return $ case res of
NoForceRecompile -> fingerprintString "NoForceRecompile"
ForceRecompile -> fingerprintString "ForceRecompile"
@@ -1344,10 +1344,6 @@ fingerprintPlugins' plugins = do
(MaybeRecompile fp) -> fp
-
-checkPlugin :: LoadedPlugin -> IO PluginRecompile
-checkPlugin (LoadedPlugin plugin _ opts) = pluginRecompile plugin opts
-
pluginRecompileToRecompileRequired :: Fingerprint -> PluginRecompile -> RecompileRequired
pluginRecompileToRecompileRequired old_fp pr =
case pr of
diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 3fb3874c63..48c7103dd9 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -984,12 +984,18 @@ data DynFlags = DynFlags {
frontendPluginOpts :: [String],
-- ^ the @-ffrontend-opt@ flags given on the command line, in *reverse*
-- order that they're specified on the command line.
- plugins :: [LoadedPlugin],
- -- ^ plugins loaded after processing arguments. What will be loaded here
- -- is directed by pluginModNames. Arguments are loaded from
+ cachedPlugins :: [LoadedPlugin],
+ -- ^ plugins dynamically loaded after processing arguments. What will be
+ -- loaded here is directed by pluginModNames. Arguments are loaded from
-- pluginModNameOpts. The purpose of this field is to cache the plugins so
- -- they don't have to be loaded each time they are needed.
- -- See 'DynamicLoading.initializePlugins'.
+ -- they don't have to be loaded each time they are needed. See
+ -- 'DynamicLoading.initializePlugins'.
+ staticPlugins :: [StaticPlugin],
+ -- ^ staic plugins which do not need dynamic loading. These plugins are
+ -- intended to be added by GHC API users directly to this list.
+ --
+ -- To add dynamically loaded plugins through the GHC API see
+ -- 'addPluginModuleName' instead.
-- GHC API hooks
hooks :: Hooks,
@@ -1917,7 +1923,8 @@ defaultDynFlags mySettings (myLlvmTargets, myLlvmPasses) =
pluginModNames = [],
pluginModNameOpts = [],
frontendPluginOpts = [],
- plugins = [],
+ cachedPlugins = [],
+ staticPlugins = [],
hooks = emptyHooks,
outputFile = Nothing,
diff --git a/compiler/main/DynamicLoading.hs b/compiler/main/DynamicLoading.hs
index 7420f7cc01..0a5264e3f2 100644
--- a/compiler/main/DynamicLoading.hs
+++ b/compiler/main/DynamicLoading.hs
@@ -83,13 +83,15 @@ initializePlugins _ df
return df
#else
initializePlugins hsc_env df
- | map lpModuleName (plugins df) == pluginModNames df -- plugins not changed
- && all (\p -> lpArguments p == argumentsForPlugin p (pluginModNameOpts df))
- (plugins df) -- arguments not changed
+ | map lpModuleName (cachedPlugins df)
+ == pluginModNames df -- plugins not changed
+ && all (\p -> paArguments (lpPlugin p)
+ == argumentsForPlugin p (pluginModNameOpts df))
+ (cachedPlugins df) -- arguments not changed
= return df -- no need to reload plugins
| otherwise
= do loadedPlugins <- loadPlugins (hsc_env { hsc_dflags = df })
- return $ df { plugins = loadedPlugins }
+ return $ df { cachedPlugins = loadedPlugins }
where argumentsForPlugin p = map snd . filter ((== lpModuleName p) . fst)
#endif
@@ -106,7 +108,8 @@ loadPlugins hsc_env
dflags = hsc_dflags hsc_env
to_load = pluginModNames dflags
- attachOptions mod_nm (plug, mod) = LoadedPlugin plug mod (reverse options)
+ attachOptions mod_nm (plug, mod) =
+ LoadedPlugin (PluginWithArgs plug (reverse options)) mod
where
options = [ option | (opt_mod_nm, option) <- pluginModNameOpts dflags
, opt_mod_nm == mod_nm ]
diff --git a/compiler/main/Plugins.hs b/compiler/main/Plugins.hs
index 430b0790f9..de04415244 100644
--- a/compiler/main/Plugins.hs
+++ b/compiler/main/Plugins.hs
@@ -32,8 +32,10 @@ module Plugins (
, keepRenamedSource
-- * Internal
+ , PluginWithArgs(..), plugins, pluginRecompile'
, LoadedPlugin(..), lpModuleName
- , withPlugins, withPlugins_
+ , StaticPlugin(..)
+ , mapPlugins, withPlugins, withPlugins_
) where
import GhcPrelude
@@ -120,20 +122,33 @@ data Plugin = Plugin {
-- For the full discussion, check the full proposal at:
-- https://ghc.haskell.org/trac/ghc/wiki/ExtendedPluginsProposal
+data PluginWithArgs = PluginWithArgs
+ { paPlugin :: Plugin
+ -- ^ the actual callable plugin
+ , paArguments :: [CommandLineOption]
+ -- ^ command line arguments for the plugin
+ }
-- | A plugin with its arguments. The result of loading the plugin.
-data LoadedPlugin = LoadedPlugin {
- lpPlugin :: Plugin
- -- ^ the actual callable plugin
+data LoadedPlugin = LoadedPlugin
+ { lpPlugin :: PluginWithArgs
+ -- ^ the actual plugin together with its commandline arguments
, lpModule :: ModIface
- -- ^ the module containing the plugin
- , lpArguments :: [CommandLineOption]
- -- ^ command line arguments for the plugin
+ -- ^ the module containing the plugin
+ }
+
+-- | A static plugin with its arguments. For registering compiled-in plugins
+-- through the GHC API.
+data StaticPlugin = StaticPlugin
+ { spPlugin :: PluginWithArgs
+ -- ^ the actual plugin together with its commandline arguments
}
lpModuleName :: LoadedPlugin -> ModuleName
lpModuleName = moduleName . mi_module . lpModule
+pluginRecompile' :: PluginWithArgs -> IO PluginRecompile
+pluginRecompile' (PluginWithArgs plugin args) = pluginRecompile plugin args
data PluginRecompile = ForceRecompile | NoForceRecompile | MaybeRecompile Fingerprint
@@ -196,16 +211,24 @@ keepRenamedSource _ gbl_env group =
type PluginOperation m a = Plugin -> [CommandLineOption] -> a -> m a
type ConstPluginOperation m a = Plugin -> [CommandLineOption] -> a -> m ()
+plugins :: DynFlags -> [PluginWithArgs]
+plugins df =
+ map lpPlugin (cachedPlugins df) ++
+ map spPlugin (staticPlugins df)
+
-- | Perform an operation by using all of the plugins in turn.
withPlugins :: Monad m => DynFlags -> PluginOperation m a -> a -> m a
-withPlugins df transformation input
- = foldM (\arg (LoadedPlugin p _ opts) -> transformation p opts arg)
- input (plugins df)
+withPlugins df transformation input = foldM go input (plugins df)
+ where
+ go arg (PluginWithArgs p opts) = transformation p opts arg
+
+mapPlugins :: DynFlags -> (Plugin -> [CommandLineOption] -> a) -> [a]
+mapPlugins df f = map (\(PluginWithArgs p opts) -> f p opts) (plugins df)
-- | Perform a constant operation by using all of the plugins in turn.
withPlugins_ :: Monad m => DynFlags -> ConstPluginOperation m a -> a -> m ()
withPlugins_ df transformation input
- = mapM_ (\(LoadedPlugin p _ opts) -> transformation p opts input)
+ = mapM_ (\(PluginWithArgs p opts) -> transformation p opts input)
(plugins df)
type FrontendPluginAction = [String] -> [(String, Maybe Phase)] -> Ghc ()
diff --git a/compiler/main/Plugins.hs-boot b/compiler/main/Plugins.hs-boot
index 4ccd3d8402..c90c6ebaf7 100644
--- a/compiler/main/Plugins.hs-boot
+++ b/compiler/main/Plugins.hs-boot
@@ -7,3 +7,4 @@ import GhcPrelude ()
data Plugin
data LoadedPlugin
+data StaticPlugin
diff --git a/compiler/typecheck/TcRnDriver.hs b/compiler/typecheck/TcRnDriver.hs
index 3b12837bdc..0a6d7e5bb2 100644
--- a/compiler/typecheck/TcRnDriver.hs
+++ b/compiler/typecheck/TcRnDriver.hs
@@ -2832,8 +2832,7 @@ withTcPlugins hsc_env m =
return (solve s, stop s)
getTcPlugins :: DynFlags -> [TcRnMonad.TcPlugin]
-getTcPlugins dflags = catMaybes $ map get_plugin (plugins dflags)
- where get_plugin p = tcPlugin (lpPlugin p) (lpArguments p)
+getTcPlugins dflags = catMaybes $ mapPlugins dflags (\p args -> tcPlugin p args)
runRenamerPlugin :: TcGblEnv
-> HsGroup GhcRn
diff --git a/testsuite/tests/plugins/all.T b/testsuite/tests/plugins/all.T
index 9a1a7ea398..72a42da91a 100644
--- a/testsuite/tests/plugins/all.T
+++ b/testsuite/tests/plugins/all.T
@@ -193,3 +193,9 @@ test('plugin-recomp-change-prof',
when(not config.have_profiling,skip)
],
run_command, ['$MAKE -s --no-print-directory plugin-recomp-change-prof'])
+
+test('static-plugins',
+ [extra_files(['simple-plugin/']),
+ extra_run_opts('"' + config.libdir + '"')],
+ compile_and_run,
+ ['-package ghc -isimple-plugin/'])
diff --git a/testsuite/tests/plugins/static-plugins-module.hs b/testsuite/tests/plugins/static-plugins-module.hs
new file mode 100644
index 0000000000..4aafd0de8a
--- /dev/null
+++ b/testsuite/tests/plugins/static-plugins-module.hs
@@ -0,0 +1,2 @@
+module Main where
+main = print "Hello world!"
diff --git a/testsuite/tests/plugins/static-plugins.hs b/testsuite/tests/plugins/static-plugins.hs
new file mode 100644
index 0000000000..36e18b86b5
--- /dev/null
+++ b/testsuite/tests/plugins/static-plugins.hs
@@ -0,0 +1,80 @@
+module Main where
+
+import Avail
+import Control.Monad.IO.Class
+import DynFlags
+ (getDynFlags, parseDynamicFlagsCmdLine, defaultFatalMessager, defaultFlushOut)
+import GHC
+import GHC.Fingerprint.Type
+import HsDecls
+import HsDoc
+import HsExpr
+import HsExtension
+import HsImpExp
+import HscTypes
+import Outputable
+import Plugins
+import System.Environment
+import TcRnTypes
+
+import Simple.SourcePlugin (plugin)
+
+main = do
+ libdir:args <- getArgs
+ defaultErrorHandler defaultFatalMessager defaultFlushOut $ do
+ runGhc (Just libdir) $ do
+ dflags <- getSessionDynFlags
+ -- liftIO $ print args
+ -- (dflags,_,_)
+ -- <- parseDynamicFlagsCmdLine dflags (map noLoc args)
+ -- we need to LinkInMemory otherwise `setTarget [] >> load LoadAllTargets`
+ -- below will fail.
+ setSessionDynFlags dflags { ghcLink = LinkInMemory}
+
+ -- Start with a pure plugin, this should trigger recomp.
+ liftIO $ putStrLn "==pure.0"
+ loadWithPlugins [StaticPlugin $ PluginWithArgs plugin0_pure []]
+
+ -- The same (or a different) pure plugin shouldn't trigger recomp.
+ liftIO $ putStrLn "==pure.1"
+ loadWithPlugins [StaticPlugin $ PluginWithArgs plugin0_pure []]
+
+ -- Next try with a fingerprint plugin, should trigger recomp.
+ liftIO $ putStrLn "==fp0.0"
+ loadWithPlugins [StaticPlugin $ PluginWithArgs plugin_fp0 []]
+
+ -- With the same fingerprint plugin, should not trigger recomp.
+ liftIO $ putStrLn "==fp0.1"
+ loadWithPlugins [StaticPlugin $ PluginWithArgs plugin_fp0 []]
+
+ -- Change the plugin fingerprint, should trigger recomp.
+ liftIO $ putStrLn "==fp1"
+ loadWithPlugins [StaticPlugin $ PluginWithArgs plugin_fp1 []]
+
+ -- TODO: this currently doesn't work, patch pending
+ -- -- Even though the plugin is now pure we should still recomp since we
+ -- -- used a potentially impure plugin before
+ -- liftIO $ putStrLn "pure.2"
+ -- loadWithPlugins [StaticPlugin $ PluginWithArgs plugin0_pure []]
+
+ where
+ loadWithPlugins the_plugins = do
+ -- first unload (like GHCi :load does)
+ GHC.setTargets []
+ _ <- GHC.load LoadAllTargets
+
+ target <- guessTarget "static-plugins-module.hs" Nothing
+ setTargets [target]
+
+ dflags <- getSessionDynFlags
+ setSessionDynFlags dflags { staticPlugins = the_plugins
+ , outputFile = Nothing }
+ load LoadAllTargets
+
+
+plugin_fp0 =
+ plugin { pluginRecompile = \_ -> pure $ MaybeRecompile $ Fingerprint 0 0 }
+plugin_fp1 =
+ plugin { pluginRecompile = \_ -> pure $ MaybeRecompile $ Fingerprint 0 1 }
+plugin0_pure =
+ plugin { pluginRecompile = \_ -> pure $ NoForceRecompile }
diff --git a/testsuite/tests/plugins/static-plugins.stdout b/testsuite/tests/plugins/static-plugins.stdout
new file mode 100644
index 0000000000..f7520a7cfb
--- /dev/null
+++ b/testsuite/tests/plugins/static-plugins.stdout
@@ -0,0 +1,25 @@
+==pure.0
+parsePlugin()
+interfacePlugin: Prelude
+interfacePlugin: GHC.Float
+interfacePlugin: GHC.Base
+interfacePlugin: System.IO
+typeCheckPlugin (rn)
+interfacePlugin: GHC.Prim
+interfacePlugin: GHC.Show
+interfacePlugin: GHC.Types
+interfacePlugin: GHC.TopHandler
+typeCheckPlugin (tc)
+interfacePlugin: GHC.CString
+interfacePlugin: GHC.Integer.Type
+interfacePlugin: GHC.Natural
+==pure.1
+==fp0.0
+parsePlugin()
+typeCheckPlugin (rn)
+typeCheckPlugin (tc)
+==fp0.1
+==fp1
+parsePlugin()
+typeCheckPlugin (rn)
+typeCheckPlugin (tc)