[Git][ghc/ghc][master] Add support for external static plugins (#20964)
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Wed Aug 10 13:45:08 UTC 2022
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
f95bbdca by Sylvain Henry at 2022-08-10T09:44:46-04:00
Add support for external static plugins (#20964)
This patch adds a new command-line flag:
-fplugin-library=<file-path>;<unit-id>;<module>;<args>
used like this:
-fplugin-library=path/to/plugin.so;package-123;Plugin.Module;["Argument","List"]
It allows a plugin to be loaded directly from a shared library. With
this approach, GHC doesn't compile anything for the plugin and doesn't
load any .hi file for the plugin and its dependencies. As such GHC
doesn't need to support two environments (one for plugins, one for
target code), which was the more ambitious approach tracked in #14335.
Fix #20964
Co-authored-by: Josh Meredith <joshmeredith2008 at gmail.com>
- - - - -
18 changed files:
- compiler/GHC/Driver/Plugins.hs
- + compiler/GHC/Driver/Plugins/External.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/Runtime/Loader.hs
- compiler/ghc.cabal.in
- docs/users_guide/extending_ghc.rst
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- testsuite/tests/plugins/Makefile
- testsuite/tests/plugins/all.T
- + testsuite/tests/plugins/plugins-external.hs
- + testsuite/tests/plugins/plugins-external.stderr
- + testsuite/tests/plugins/plugins-external.stdout
- + testsuite/tests/plugins/shared-plugin/LICENSE
- + testsuite/tests/plugins/shared-plugin/Makefile
- + testsuite/tests/plugins/shared-plugin/Setup.hs
- + testsuite/tests/plugins/shared-plugin/Simple/Plugin.hs
- + testsuite/tests/plugins/shared-plugin/shared-plugin.cabal
Changes:
=====================================
compiler/GHC/Driver/Plugins.hs
=====================================
@@ -1,4 +1,11 @@
{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE CPP #-}
+
+#if defined(HAVE_INTERNAL_INTERPRETER)
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE UnboxedTuples #-}
+#endif
-- | Definitions for writing /plugins/ for GHC. Plugins can hook into
@@ -14,6 +21,10 @@ module GHC.Driver.Plugins (
, CommandLineOption
, PsMessages(..)
, ParsedResult(..)
+
+ -- * External plugins
+ , loadExternalPlugins
+
-- ** Recompilation checking
, purePlugin, impurePlugin, flagRecompile
, PluginRecompile(..)
@@ -52,6 +63,7 @@ module GHC.Driver.Plugins (
, PluginWithArgs(..), pluginsWithArgs, pluginRecompile'
, LoadedPlugin(..), lpModuleName
, StaticPlugin(..)
+ , ExternalPlugin(..)
, mapPlugins, withPlugins, withPlugins_
) where
@@ -60,6 +72,7 @@ import GHC.Prelude
import GHC.Driver.Env
import GHC.Driver.Monad
import GHC.Driver.Phases
+import GHC.Driver.Plugins.External
import GHC.Unit.Module
import GHC.Unit.Module.ModIface
@@ -75,8 +88,12 @@ import GHC.Core.Opt.Monad ( CoreM )
import GHC.Core.Opt.Pipeline.Types ( CoreToDo )
import GHC.Hs
import GHC.Types.Error (Messages)
+import GHC.Linker.Types
+import GHC.Types.Unique.DFM
+
import GHC.Utils.Fingerprint
-import GHC.Utils.Outputable (Outputable(..), text, (<+>))
+import GHC.Utils.Outputable
+import GHC.Utils.Panic
import Data.List (sort)
@@ -85,8 +102,13 @@ import Data.List (sort)
import qualified Data.Semigroup
import Control.Monad
-import GHC.Linker.Types
-import GHC.Types.Unique.DFM
+
+#if defined(HAVE_INTERNAL_INTERPRETER)
+import GHCi.ObjLink
+import GHC.Exts (addrToAny#, Ptr(..))
+import GHC.Utils.Encoding
+#endif
+
-- | Command line options gathered from the -PModule.Name:stuff syntax
-- are given to you as this type
@@ -196,6 +218,14 @@ data LoadedPlugin = LoadedPlugin
-- ^ the module containing the plugin
}
+-- | External plugin loaded directly from a library without loading module
+-- interfaces
+data ExternalPlugin = ExternalPlugin
+ { epPlugin :: PluginWithArgs -- ^ Plugin with its arguments
+ , epUnit :: String -- ^ UnitId
+ , epModule :: String -- ^ Module name
+ }
+
-- | A static plugin with its arguments. For registering compiled-in plugins
-- through the GHC API.
data StaticPlugin = StaticPlugin
@@ -285,6 +315,10 @@ data Plugins = Plugins
-- To add dynamically loaded plugins through the GHC API see
-- 'addPluginModuleName' instead.
+ , externalPlugins :: ![ExternalPlugin]
+ -- ^ External plugins loaded directly from libraries without loading
+ -- module interfaces.
+
, loadedPlugins :: ![LoadedPlugin]
-- ^ Plugins dynamically loaded after processing arguments. What
-- will be loaded here is directed by DynFlags.pluginModNames.
@@ -299,12 +333,17 @@ data Plugins = Plugins
}
emptyPlugins :: Plugins
-emptyPlugins = Plugins [] [] ([], emptyUDFM)
-
+emptyPlugins = Plugins
+ { staticPlugins = []
+ , externalPlugins = []
+ , loadedPlugins = []
+ , loadedPluginDeps = ([], emptyUDFM)
+ }
pluginsWithArgs :: Plugins -> [PluginWithArgs]
pluginsWithArgs plugins =
map lpPlugin (loadedPlugins plugins) ++
+ map epPlugin (externalPlugins plugins) ++
map spPlugin (staticPlugins plugins)
-- | Perform an operation by using all of the plugins in turn.
@@ -328,3 +367,53 @@ data FrontendPlugin = FrontendPlugin {
}
defaultFrontendPlugin :: FrontendPlugin
defaultFrontendPlugin = FrontendPlugin { frontend = \_ _ -> return () }
+
+
+-- | Load external plugins
+loadExternalPlugins :: [ExternalPluginSpec] -> IO [ExternalPlugin]
+loadExternalPlugins [] = return []
+#if !defined(HAVE_INTERNAL_INTERPRETER)
+loadExternalPlugins _ = do
+ panic "loadExternalPlugins: can't load external plugins with GHC built without internal interpreter"
+#elif !defined(CAN_LOAD_DLL)
+loadExternalPlugins _ = do
+ panic "loadExternalPlugins: loading shared libraries isn't supported by this compiler"
+#else
+loadExternalPlugins ps = do
+ -- initialize the linker
+ initObjLinker RetainCAFs
+ -- load plugins
+ forM ps $ \(ExternalPluginSpec path unit mod_name opts) -> do
+ loadExternalPluginLib path
+ -- lookup symbol
+ let ztmp = zEncodeString mod_name ++ "_plugin_closure"
+ symbol
+ | null unit = ztmp
+ | otherwise = zEncodeString unit ++ "_" ++ ztmp
+ plugin <- lookupSymbol symbol >>= \case
+ Nothing -> pprPanic "loadExternalPlugins"
+ (vcat [ text "Symbol not found"
+ , text " Library path: " <> text path
+ , text " Symbol : " <> text symbol
+ ])
+ Just (Ptr addr) -> case addrToAny# addr of
+ (# a #) -> pure a
+
+ pure $ ExternalPlugin (PluginWithArgs plugin opts) unit mod_name
+
+loadExternalPluginLib :: FilePath -> IO ()
+loadExternalPluginLib path = do
+ -- load library
+ loadDLL path >>= \case
+ Just errmsg -> pprPanic "loadExternalPluginLib"
+ (vcat [ text "Can't load plugin library"
+ , text " Library path: " <> text path
+ , text " Error : " <> text errmsg
+ ])
+ Nothing -> do
+ -- resolve objects
+ resolveObjs >>= \case
+ True -> return ()
+ False -> pprPanic "loadExternalPluginLib" (text "Unable to resolve objects for library: " <> text path)
+
+#endif
=====================================
compiler/GHC/Driver/Plugins/External.hs
=====================================
@@ -0,0 +1,79 @@
+-- | External plugins
+--
+-- GHC supports two kinds of "static" plugins:
+-- 1. internal: setup with GHC-API
+-- 2. external: setup as explained below and loaded from shared libraries
+--
+-- The intended use case for external static plugins is with cross compilers: at
+-- the time of writing, GHC is mono-target and a GHC cross-compiler (i.e. when
+-- host /= target) can't build nor load plugins for the host using the
+-- "non-static" plugin approach. Fixing this is tracked in #14335. If you're not
+-- using a cross-compiler, you'd better use non-static plugins which are easier
+-- to build and and safer to use (see below).
+--
+-- External static plugins can be configured via the command-line with
+-- the -fplugin-library flag. Syntax is:
+--
+-- -fplugin-library=⟨file-path⟩;⟨unit-id⟩;⟨module⟩;⟨args⟩
+--
+-- Example:
+-- -fplugin-library=path/to/plugin;package-123;Plugin.Module;["Argument","List"]
+--
+-- Building the plugin library:
+-- 1. link with the libraries used to build the compiler you target. If you
+-- target a cross-compiler (stage2), you can't directly use it to build the
+-- plugin library. Use the stage1 compiler instead.
+--
+-- 2. if you use cabal to build the library, its unit-id will be set by cabal
+-- and will contain a hash (e.g. "my-plugin-unit-1345656546ABCDEF"). To force
+-- the unit id, use GHC's `-this-unit-id` command line flag:
+-- e.g. -this-unit-id my-plugin-unit
+-- You can set this in the .cabal file of your library with the following
+-- stanza: `ghc-options: -this-unit-id my-plugin-unit`
+--
+-- 3. To make your plugin easier to distribute, you may want to link it
+-- statically with all its dependencies. You would need to use `-shared`
+-- without `-dynamic` when building your library.
+--
+-- However, all the static dependencies have to be built with `-fPIC` and it's
+-- not done by default. See
+-- https://www.hobson.space/posts/haskell-foreign-library/ for a way to modify
+-- the compiler to do it.
+--
+-- In any case, don't link your plugin library statically with the RTS (e.g.
+-- use `-fno-link-rts`) as there are some global variables in the RTS that must
+-- be shared between the plugin and the compiler.
+--
+-- With external static plugins we don't check the type of the `plugin` closure
+-- we look up. If it's not a valid `Plugin` value, it will probably crash badly.
+--
+
+module GHC.Driver.Plugins.External
+ ( ExternalPluginSpec (..)
+ , parseExternalPluginSpec
+ )
+where
+
+import GHC.Prelude
+import Text.Read
+
+-- | External plugin spec
+data ExternalPluginSpec = ExternalPluginSpec
+ { esp_lib :: !FilePath
+ , esp_unit_id :: !String
+ , esp_module :: !String
+ , esp_args :: ![String]
+ }
+
+-- | Parser external static plugin specification from command-line flag
+parseExternalPluginSpec :: String -> Maybe ExternalPluginSpec
+parseExternalPluginSpec optflag =
+ case break (== ';') optflag of
+ (libPath, _:rest) -> case break (== ';') rest of
+ (libName, _:pack) -> case break (== ';') pack of
+ (modName, _:args) -> case readMaybe args of
+ Just as -> Just (ExternalPluginSpec libPath libName modName as)
+ Nothing -> Nothing
+ _ -> Nothing
+ _ -> Nothing
+ _ -> Nothing
=====================================
compiler/GHC/Driver/Session.hs
=====================================
@@ -229,6 +229,7 @@ import GHC.Builtin.Names ( mAIN_NAME )
import GHC.Driver.Phases ( Phase(..), phaseInputExt )
import GHC.Driver.Flags
import GHC.Driver.Backend
+import GHC.Driver.Plugins.External
import GHC.Settings.Config
import GHC.Utils.CliOption
import GHC.Core.Unfold
@@ -590,6 +591,9 @@ data DynFlags = DynFlags {
-- ^ the @-ffrontend-opt@ flags given on the command line, in *reverse*
-- order that they're specified on the command line.
+ externalPluginSpecs :: [ExternalPluginSpec],
+ -- ^ External plugins loaded from shared libraries
+
-- For ghc -M
depMakefile :: FilePath,
depIncludePkgDeps :: Bool,
@@ -1176,6 +1180,8 @@ defaultDynFlags mySettings =
pluginModNameOpts = [],
frontendPluginOpts = [],
+ externalPluginSpecs = [],
+
outputFile_ = Nothing,
dynOutputFile_ = Nothing,
outputHi = Nothing,
@@ -1715,6 +1721,11 @@ addPluginModuleNameOption optflag d = d { pluginModNameOpts = (mkModuleName m, o
[] -> "" -- should probably signal an error
(_:plug_opt) -> plug_opt -- ignore the ':' from break
+addExternalPlugin :: String -> DynFlags -> DynFlags
+addExternalPlugin optflag d = case parseExternalPluginSpec optflag of
+ Just r -> d { externalPluginSpecs = r : externalPluginSpecs d }
+ Nothing -> cmdLineError $ "Couldn't parse external plugin specification: " ++ optflag
+
addFrontendPluginOption :: String -> DynFlags -> DynFlags
addFrontendPluginOption s d = d { frontendPluginOpts = s : frontendPluginOpts d }
@@ -2695,6 +2706,8 @@ dynamic_flags_deps = [
, make_ord_flag defGhcFlag "fclear-plugins" (noArg clearPluginModuleNames)
, make_ord_flag defGhcFlag "ffrontend-opt" (hasArg addFrontendPluginOption)
+ , make_ord_flag defGhcFlag "fplugin-library" (hasArg addExternalPlugin)
+
------ Optimisation flags ------------------------------------------
, make_dep_flag defGhcFlag "Onot" (noArgM $ setOptLevel 0 )
"Use -O0 instead"
=====================================
compiler/GHC/Runtime/Loader.hs
=====================================
@@ -26,6 +26,7 @@ import GHC.Driver.Session
import GHC.Driver.Ppr
import GHC.Driver.Hooks
import GHC.Driver.Plugins
+import GHC.Driver.Plugins.External
import GHC.Linker.Loader ( loadModule, loadName )
import GHC.Runtime.Interpreter ( wormhole )
@@ -75,22 +76,48 @@ import Data.List (unzip4)
-- pluginModNames or pluginModNameOpts changes.
initializePlugins :: HscEnv -> IO HscEnv
initializePlugins hsc_env
- -- plugins not changed
+ -- check that plugin specifications didn't change
+
+ -- dynamic plugins
| loaded_plugins <- loadedPlugins (hsc_plugins hsc_env)
, map lpModuleName loaded_plugins == reverse (pluginModNames dflags)
- -- arguments not changed
, all same_args loaded_plugins
- = return hsc_env -- no need to reload plugins FIXME: doesn't take static plugins into account
+
+ -- external plugins
+ , external_plugins <- externalPlugins (hsc_plugins hsc_env)
+ , check_external_plugins external_plugins (externalPluginSpecs dflags)
+
+ -- FIXME: we should check static plugins too
+
+ = return hsc_env -- no change, no need to reload plugins
+
| otherwise
= do (loaded_plugins, links, pkgs) <- loadPlugins hsc_env
- let plugins' = (hsc_plugins hsc_env) { loadedPlugins = loaded_plugins, loadedPluginDeps = (links, pkgs) }
+ external_plugins <- loadExternalPlugins (externalPluginSpecs dflags)
+ let plugins' = (hsc_plugins hsc_env) { staticPlugins = staticPlugins (hsc_plugins hsc_env)
+ , externalPlugins = external_plugins
+ , loadedPlugins = loaded_plugins
+ , loadedPluginDeps = (links, pkgs)
+ }
let hsc_env' = hsc_env { hsc_plugins = plugins' }
withPlugins (hsc_plugins hsc_env') driverPlugin hsc_env'
where
+ dflags = hsc_dflags hsc_env
+ -- dynamic plugins
plugin_args = pluginModNameOpts dflags
same_args p = paArguments (lpPlugin p) == argumentsForPlugin p plugin_args
argumentsForPlugin p = map snd . filter ((== lpModuleName p) . fst)
- dflags = hsc_dflags hsc_env
+ -- external plugins
+ check_external_plugin p spec = and
+ [ epUnit p == esp_unit_id spec
+ , epModule p == esp_module spec
+ , paArguments (epPlugin p) == esp_args spec
+ ]
+ check_external_plugins eps specs = case (eps,specs) of
+ ([] , []) -> True
+ (_ , []) -> False -- some external plugin removed
+ ([] , _ ) -> False -- some external plugin added
+ (p:ps,s:ss) -> check_external_plugin p s && check_external_plugins ps ss
loadPlugins :: HscEnv -> IO ([LoadedPlugin], [Linkable], PkgsLoaded)
loadPlugins hsc_env
=====================================
compiler/ghc.cabal.in
=====================================
@@ -441,6 +441,7 @@ Library
GHC.Driver.Pipeline.Phases
GHC.Driver.Pipeline.Monad
GHC.Driver.Plugins
+ GHC.Driver.Plugins.External
GHC.Driver.Ppr
GHC.Driver.Session
GHC.Hs
=====================================
docs/users_guide/extending_ghc.rst
=====================================
@@ -268,7 +268,6 @@ option. The list of enabled plugins can be reset with the
the command line is not possible. Instead ``:set -fclear-plugins`` can be
used.
-
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
would invoke GHC like this:
@@ -286,6 +285,19 @@ would invoke GHC like this:
Linking Test ...
$
+
+Plugins can be also be loaded from libraries directly. It allows plugins to be
+loaded in cross-compilers (as a workaround for #14335).
+
+.. ghc-flag:: -fplugin-library=⟨file-path⟩;⟨unit-id⟩;⟨module⟩;⟨args⟩
+ :shortdesc: Load a pre-compiled static plugin from an external library
+ :type: dynamic
+ :category: plugins
+
+ Arguments are specified in a list form, so a plugin specified to
+ :ghc-flag:`-fplugin-library=⟨file-path⟩;⟨unit-id⟩;⟨module⟩;⟨args⟩` will look
+ like ``'path/to/plugin;package-123;Plugin.Module;["Argument","List"]'``.
+
Alternatively, core plugins can be specified with Template Haskell.
::
=====================================
testsuite/tests/count-deps/CountDepsAst.stdout
=====================================
@@ -116,6 +116,7 @@ GHC.Driver.Phases
GHC.Driver.Pipeline.Monad
GHC.Driver.Pipeline.Phases
GHC.Driver.Plugins
+GHC.Driver.Plugins.External
GHC.Driver.Ppr
GHC.Driver.Session
GHC.Hs
=====================================
testsuite/tests/count-deps/CountDepsParser.stdout
=====================================
@@ -117,6 +117,7 @@ GHC.Driver.Phases
GHC.Driver.Pipeline.Monad
GHC.Driver.Pipeline.Phases
GHC.Driver.Plugins
+GHC.Driver.Plugins.External
GHC.Driver.Ppr
GHC.Driver.Session
GHC.Hs
=====================================
testsuite/tests/plugins/Makefile
=====================================
@@ -205,3 +205,18 @@ test-echo-in-turn-many-args:
.PHONY: test-echo-in-line-many-args
test-echo-in-line-many-args:
"$(TEST_HC)" $(TEST_HC_OPTS) $(ghcPluginWayFlags) -v0 test-echo-in-line-many-args.hs -package-db echo-plugin/pkg.test-echo-in-line-many-args/local.package.conf
+
+
+ifeq "$(WINDOWS)" "YES"
+DLL = $1.dll
+else ifeq "$(DARWIN)" "YES"
+DLL = lib$1.dylib
+else
+DLL = lib$1.so
+endif
+
+.PHONY: plugins-external
+plugins-external:
+ cp shared-plugin/pkg.plugins01/dist/build/$(call DLL,HSsimple-plugin*) $(call DLL,HSsimple-plugin)
+ "$(TEST_HC)" $(TEST_HC_OPTS) $(ghcPluginWayFlags) --make -v0 -fplugin-library "$(PWD)/$(call DLL,HSsimple-plugin);simple-plugin-1234;Simple.Plugin;[\"Plugin\",\"loaded\",\"from\",\"a shared lib\"]" plugins-external.hs
+ ./plugins-external
=====================================
testsuite/tests/plugins/all.T
=====================================
@@ -311,3 +311,8 @@ test('test-echo-in-line-many-args',
[extra_files(['echo-plugin/']),
pre_cmd('$MAKE -s --no-print-directory -C echo-plugin package.test-echo-in-line-many-args TOP={top}')],
makefile_test, [])
+
+test('plugins-external',
+ [extra_files(['shared-plugin/']),
+ pre_cmd('$MAKE -s --no-print-directory -C shared-plugin package.plugins01 TOP={top}')],
+ makefile_test, [])
=====================================
testsuite/tests/plugins/plugins-external.hs
=====================================
@@ -0,0 +1,4 @@
+-- Intended to test that we can load plugins as external shared libraries
+module Main where
+
+main = putStrLn "Hello World"
=====================================
testsuite/tests/plugins/plugins-external.stderr
=====================================
@@ -0,0 +1,2 @@
+Simple Plugin Passes Queried
+Got options: Plugin loaded from a shared lib
=====================================
testsuite/tests/plugins/plugins-external.stdout
=====================================
@@ -0,0 +1 @@
+Hello World
=====================================
testsuite/tests/plugins/shared-plugin/LICENSE
=====================================
@@ -0,0 +1,10 @@
+Copyright (c) 2008, Max Bolingbroke
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the name of Max Bolingbroke nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=====================================
testsuite/tests/plugins/shared-plugin/Makefile
=====================================
@@ -0,0 +1,20 @@
+TOP=../../..
+include $(TOP)/mk/boilerplate.mk
+include $(TOP)/mk/test.mk
+
+clean.%:
+ rm -rf pkg.$*
+
+HERE := $(abspath .)
+$(eval $(call canonicalise,HERE))
+
+package.%:
+ $(MAKE) -s --no-print-directory clean.$*
+ mkdir pkg.$*
+ "$(TEST_HC)" -outputdir pkg.$* --make -v0 -o pkg.$*/setup Setup.hs
+
+ "$(GHC_PKG)" init pkg.$*/local.package.conf
+
+ pkg.$*/setup configure --distdir pkg.$*/dist -v0 $(CABAL_PLUGIN_BUILD) --prefix="$(HERE)/pkg.$*/install" --with-compiler="$(TEST_HC)" --with-hc-pkg="$(GHC_PKG)" --package-db=pkg.$*/local.package.conf $(if $(findstring YES,$(HAVE_PROFILING)), --enable-library-profiling)
+ pkg.$*/setup build --distdir pkg.$*/dist -v0
+ pkg.$*/setup install --distdir pkg.$*/dist -v0
=====================================
testsuite/tests/plugins/shared-plugin/Setup.hs
=====================================
@@ -0,0 +1,3 @@
+import Distribution.Simple
+
+main = defaultMain
=====================================
testsuite/tests/plugins/shared-plugin/Simple/Plugin.hs
=====================================
@@ -0,0 +1,26 @@
+{-# LANGUAGE TemplateHaskell #-}
+
+module Simple.Plugin(plugin) where
+
+import GHC.Types.Unique.FM
+import GHC.Plugins
+import qualified GHC.Utils.Error
+
+import Control.Monad
+import Data.Monoid hiding (Alt)
+import Data.Dynamic
+import qualified Language.Haskell.TH as TH
+
+plugin :: Plugin
+plugin = defaultPlugin {
+ installCoreToDos = install,
+ pluginRecompile = purePlugin
+ }
+
+install :: [CommandLineOption] -> [CoreToDo] -> CoreM [CoreToDo]
+install options todos = do
+ putMsgS $ "Simple Plugin Passes Queried"
+ putMsgS $ "Got options: " ++ unwords options
+
+ -- Create some actual passes to continue the test.
+ return todos
=====================================
testsuite/tests/plugins/shared-plugin/shared-plugin.cabal
=====================================
@@ -0,0 +1,21 @@
+Name: simple-plugin
+Version: 0.1
+Synopsis: A demonstration of the GHC plugin system.
+Cabal-Version: >= 1.2
+Build-Type: Simple
+License: BSD3
+License-File: LICENSE
+Author: Max Bolingbroke
+Homepage: http://blog.omega-prime.co.uk
+
+Library
+ Extensions: CPP
+ Build-Depends:
+ base,
+ template-haskell,
+ ghc >= 6.11
+ Exposed-Modules:
+ Simple.Plugin
+
+ -- explicitly set the unit-id to allow loading from a shared library
+ ghc-options: -this-unit-id simple-plugin-1234
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/f95bbdcae3e6710a92dd8244321677eef91890de
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/f95bbdcae3e6710a92dd8244321677eef91890de
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20220810/43c2447a/attachment-0001.html>
More information about the ghc-commits
mailing list