Skip to content

RFC: design for better GHC plugin support in cabal #7901

@michaelpj

Description

@michaelpj

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:

  1. 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 normal build-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.
  1. 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

  1. 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.)

  1. plugin-depends package field for cabal.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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions