ghc-compat-plugin: Eases support for multiple GHC versions

[ agpl, compatibility, compiler-plugins, library ] [ Propose Tags ] [ Report a vulnerability ]

Controls various GHC options and extensions to make compilation across multiple versions easier, and to alert you to incompatibilities.


[Skip to Readme]

Flags

Manual Flags

NameDescriptionDefault
noisy-deprecations

Prior to GHC 9.10, the DEPRECATED pragma can’t distinguish between terms and types. Consenquently, you can get spurious warnings when there’s a name collision and the name in the other namespace is deprecated. Or you can choose to not get those warnings, at the risk of not being warned when there’s a name collision and the namespace you’re referencing is the one that’s deprecated.

Enabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

  • No Candidates
Versions [RSS] 0.0.1.0, 0.0.2.0
Change log CHANGELOG.md
Dependencies base (>=4.8.0 && <4.23), ghc (>=7.2.1 && <9.16), ghc-boot-th (>=8.0.1 && <9.16) [details]
Tested with ghc ==7.10.3 || ==8.0.2 || ==8.2.2 || ==8.4.1 || ==8.6.1 || ==8.8.1 || ==8.10.1 || ==9.0.1 || ==9.2.1 || ==9.4.1 || ==9.4.8 || ==9.6.1 || ==9.6.7 || ==9.8.1 || ==9.8.4 || ==9.10.1 || ==9.10.2 || ==9.10.3 || ==9.12.1 || ==9.12.2 || ==9.14.1
License AGPL-3.0-only
Copyright 2026 Greg Pfeil
Author Greg Pfeil <greg@technomadic.org>
Maintainer Greg Pfeil <greg@technomadic.org>
Uploaded by sellout at 2026-02-01T22:19:00Z
Category Compatibility, Compiler Plugins
Home page https://github.com/sellout/ghc-compat-plugin#readme
Bug tracker https://github.com/sellout/ghc-compat-plugin/issues
Source repo head: git clone https://github.com/sellout/ghc-compat-plugin.git(core)
this: git clone https://github.com/sellout/ghc-compat-plugin.git(tag v0.1.0)(core)
Distributions
Downloads 2 total (2 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2026-02-01 [all 1 reports]

Readme for ghc-compat-plugin-0.0.1.0

[back to package description]

GhcCompat plugin

Hackage Version Packaging status latest packaged versions

Eases support for multiple GHC versions

Controls various GHC options and extensions to make compilation across multiple versions easier, and to alert you to incompatibilities.

Often GHC will add warnings to encourage users to make use of newer language features. However, if you’re like me, you use -Weverything and also support a large number of GHC versions. This can lead to a bunch of fragile conditionalization as you need to disable certain warnings but not before those warnings were added to GHC.

This plugin does three things:

  1. reports if you use any language extensions that aren’t supported by your minimum GHC version,
  2. automatically disables any warnings where addressing them requires features that aren’t part of your minimum GHC version, and
  3. reports any warnings from no. 2 that were introduced before GHC 8.10.11.

So, currently, if you enable this plugin,

oldest GHC < then this plugin will allow from GHC auto unset
6.8.1 missing-kind-signatures 9.2.1
7.4.1 missing-poly-kind-signatures 9.8.1
7.8.1 deriving-typeable 7.10.1
missing-role-annotations 9.8.1
8.2.1 missing-deriving-strategies 8.8.1
8.6.1 star-is-type 8.6.1
8.10.1 prepositive-qualified-module 8.10.1
9.14.1 pattern-namespace-specifier 9.14.1

Note that there are often versions between the oldest one you support and the one where the plugin disables the warning. This is because the flag warning about a feature can be added long after the feature (for example, role annotations were added in GHC 7.8.1, but the warning to use them wasn’t added until GHC 9.8.1).

usage

Add the following to any stanzas2 in your Cabal package files.

library
  build-depends: ghc-compat-plugin >=0.0.1 && <0.1,
  ghc-options:
    -fplugin=GhcCompat
    -fplugin-opt=GhcCompat:minVersion=8.8.1

Note that in the last line, you must provide the oldest GHC version you support to the plugin, so it knows which flags to disable.

You can also add

    -fplugin-opt GhcCompat:reportIncompatibleExtensions=error

(where error can also be warn (the default) or no) in order to control how the plugin informs you of enabled extensions that aren’t compatible with all of your supported GHC versions.

NB: This plugin should load from GHC 7.2 (the first version of GHC to support plugins3). However, it currently won’t do anything before GHC 7.10.1. If you do need to support a GHC prior to 7.2, you can use the plugin conditionally, like

library
  if impl(ghc >= 7.2.1)
    build-depends: ghc-compat-plugin >=0.0.1 && <0.1,
    ghc-options:
      -fplugin=GhcCompat
      -fplugin-opt=GhcCompat:minVersion=6.8.1

versioning

This project largely follows the Haskell Package Versioning Policy (PVP), but is more strict in some ways.

The version always has four components, A.B.C.D. The first three correspond to those required by PVP, while the fourth matches the “patch” component from Semantic Versioning.

Here is a breakdown of some of the constraints:

sensitivity to additions to the API

PVP recommends that clients follow these import guidelines in order that they may be considered insensitive to additions to the API. However, this isn’t sufficient. We expect clients to follow these additional recommendations for API insensitivity

If you don’t follow these recommendations (in addition to the ones made by PVP), you should ensure your dependencies don’t allow a range of C values. That is, your dependencies should look like

yaya >=1.2.3 && <1.2.4

rather than

yaya >=1.2.3 && <1.3

use package-qualified imports everywhere

If your imports are package-qualified, then a dependency adding new modules can’t cause a conflict with modules you already import.

avoid orphans

Because of the transitivity of instances, orphans make you sensitive to your dependencies’ instances. If you have an orphan instance, you are sensitive to the APIs of the packages that define the class and the types of the instance.

One way to minimize this sensitivity is to have a separate package (or packages) dedicated to any orphans you have. Those packages can be sensitive to their dependencies’ APIs, while the primary package remains insensitive, relying on the tighter ranges of the orphan packages to constrain the solver.

transitively breaking changes (increments A)

removing a type class instance

Type class instances are imported transitively, and thus changing them can impact packages that only have your package as a transitive dependency.

widening a dependency range with new major versions

This is a consequence of instances being transitively imported. A new major version of a dependency can remove instances, and that can break downstream clients that unwittingly depended on those instances.

A library may declare that it always bumps the A component when it removes an instance (as this policy dictates). In that case, only A widenings need to induce A bumps. B widenings can be D bumps like other widenings, Alternatively, one may compare the APIs when widening a dependency range, and if no instances have been removed, make it a D bump.

breaking changes (increments B)

restricting an existing dependency’s version range in any way

Consumers have to contend not only with our version bounds, but also with those of other libraries. It’s possible that some dependency overlapped in a very narrow way, and even just restricting a particular patch version of a dependency could make it impossible to find a dependency solution.

restricting the license in any way

Making a license more restrictive may prevent clients from being able to continue using the package.

adding a dependency

A new dependency may make it impossible to find a solution in the face of other packages dependency ranges.

non-breaking changes (increments C)

adding a module

This is also what PVP recommends. However, unlike in PVP, this is because we recommend that package-qualified imports be used on all imports.

other changes (increments D)

widening a dependency range for non-major versions

This is fairly uncommon, in the face of ^>=-style ranges, but it can happen in a few situations.

deprecation

NB: This case is weaker than PVP, which indicates that packages should bump their major version when adding deprecation pragmas.

We disagree with this because packages shouldn’t be publishing with -Werror. The intent of deprecation is to indicate that some API will change. To make that signal a major change itself defeats the purpose. You want people to start seeing that warning as soon as possible. The major change occurs when you actually remove the old API.

Yes, in development, -Werror is often (and should be) used. However, that just helps developers be aware of deprecations more immediately. They can always add -Wwarn=deprecation in some scope if they need to avoid updating it for the time being.

licensing

This package is licensed under The GNU AGPL 3.0 only. If you need a license for usage that isn’t covered under the AGPL, please contact Greg Pfeil.

You should review the license report for details about dependency licenses.

comparisons

This was inspired by compatibility flags in other language implementations, like -Wc++11-compat in GCC and Clang.

1

This is because before GHC 8.10.1, plugins couldn’t modify warning flags, so we report them to allow them to be manually disabled.

2

I like to put it in a common section that’s imported by all my stanzas.

3

What good would a compatibility plugin be if it wasn’t extremely compatible?