-
Notifications
You must be signed in to change notification settings - Fork 722
Description
This came out of some discussion on IRC. I started writing an issue, but on reflection I think there's a relatively plausible design sitting there, so I wrote it down.
Motivation
GHC compiler plugins are currently not terribly easy to use with cabal
, and require some amount of manual fiddling. In addition, they are not specified as declaratively as they could be (i.e. cabal has no concept of a "plugin"), which prevents cabal from doing some things as well as it could do.
I think there are two broad kinds of plugin that we should be thinking about:
- Package plugins
Package plugins are those which are required by the package itself. They usually have a load-bearing role, in that they are actually necessary to compile the package. An example is the record-dot-preprocessor
plugin.
Today, these can be used by:
- Adding the plugin package to the component's
build-depends
stanza - Passing the appropriate
-fplugin
GHC option
Package plugins as implemented today have a few weaknesses:
- They don't use
-fplugin-package
, since they are just specified as normalbuild-depends
. This means they get unnecessarily linked into the final build product (Add support for -fplugin-package #6169). - They are solved for as part of the main build plan, even though (see above) they don't need to be linked into the final build product.
- If/when the upstream GHC support for a native package db for plugins is completed, cabal will not be able to use it (because it doesn't know they're plugins).
- Users have to specify the
-fplugin
options themselves, as well as any-fplugin-opt
flags.
- Global plugins
Global plugins are ones which users want to run on all packages that get built, regardless of whether the package itself says it requires any plugins. An example is the ghc-tags-plugin
plugin. Often these are used to e.g. get additional compile-time information out of dependencies.
Today these are very difficult to use (#7685, #6307, probably more). Partly the issue is that doing this nicely requires both setting a GHC option for upstream packages (doable today in cabal.project
), but also building the plugin package and ensuring it is present in the appropriate package db when building the upstream package (hard to do without hacks like specifying your own manually created plugin db).
Since these sorts of plugins are also frequently used just in development, it would be particularly nice if they could easily be specified via cabal.project.local
(#6169 (comment)).
Proposal
plugin-depends
field for.cabal
files
(Prior art: #2965, but I'm putting it a little differently, so I'll repeat.)
The goal here is to make the situation nicer for package plugins. To that end, we teach cabal a plugin-depends
field for component stanzas for .cabal
files. plugin-depends
contains a list of package/module pairs.
Initially, it could start out as a simple wrapper for build-depends
, and then we could progressively augment it to have the following features:
- Also imply the appropriate
-fplugin
flags. (This is why we need the module component!-fplugin
needs the actual plugin module.) - Be passed via
-fplugin-package
(in particular, I don't think this needs to be a prerequisite, contra RFE: local plugins and build-tool-depends #6307 (comment)) - Be included in an appropriate native package db when/if that exists
- Be solved for as part of an independent build plan for native dependencies (relies on the previous item)
This deliberately doesn't cover -fplugin-opt
flags. It seems reasonable for users to add those themselves.
(I'm also disagreeing with my past self here, who thought that we should just have native-build-depends
and have that include plugins. However, the idea of including the extra information about modules that's needed to automatically pass -fplugin
flags seems appealing to me, and requires a plugin-specific field. You could do this with a combination of native-build-depends
and active-plugins
(the latter taking a list of modules); maybe that would be nicer.)
plugin-depends
package field forcabal.project
files
The goal here is to make the situation nicer for global plugins. To that end, we teach cabal a plugin-depends
field for package stanzas in cabal.project
files.
This field simply augments the plugin-depends
field for the corresponding package. Plugins that truly want to be globally applied can then use package *
as usual.