Liquid Haskell integration for Cabal and Stack.
liquidhaskell-cabal provides drop-in LiquidHaskell integration for projects built with Cabal
and/or Stack.
(See liquidhaskell-cabal-demo for an
example project setup.)
-
Make sure you have LiquidHaskell version 0.6 or above installed and available in your
$PATH. -
Open up your
Setup.hsfile. For most projects, it will look like this:import Distribution.Simple main = defaultMainReplace that with:
import LiquidHaskell.Cabal main = liquidHaskellMainThis hooks LiquidHaskell into your Cabal/Stack-based build.
(For projects already using a custom
Setup.hsfile, see the section on "CustomSetup.hsFiles" below.) -
Next, it's time to set up your project's .cabal file.
Add
liquidhaskell-cabalto thebuild-dependslists of each of your libraries and executables:library build-depends: {- ... other dependencies ... -} , liquidhaskell-cabal >= 0.2.1 {- ... perhaps more dependencies? ... -}Then add a
custom-setupstanza at the top level, outside thelibraryandexecutalesections:custom-setup setup-depends: base, Cabal, liquidhaskell-cabal >= 0.2.1This tells Cabal to make the
base,Cabal, andliquidhaskell-cabalpackages available when buildingSetup.hs. It goes at the top level of your .cabal file, next tolibrary,executable, andtest-suite. And as with othersetup-dependslists, you can optionally set version bounds here.You'll also need a flag called
liquidhaskellin your .cabal file;liquidhaskell-cabalonly activates if it sees that a flag with this name is enabled. It is highly recommended that this be disabled by default, so that end users of your package don't need to know about LiquidHaskell to install it:flag liquidhaskell description: After building, verify with LiquidHaskell default: FalseFinally, make sure the
build-typefield in your .cabal file is set toCustom(most projects useSimple):build-type: CustomEach library and executable in your package can optionally specify its own LiquidHaskell flags and whitelist of source files to verify with LiquidHaskell; see the section on "Additional
.cabalFields" below for more on that. -
When building, you may see a warning that looks like:
Ignoring unknown section type: custom-setupThis is because old versions of Cabal (before version 1.24) don't recognize the
custom-setupstanza. If you're building with Stack, see the next step; otherwise, you'll need to installliquidhaskell-cabalmanually to make it available to yourSetup.hs:$ cabal install liquidhaskell-cabal-0.2.1.0 -
If you're building with Stack, add the following to your project's
stack.yaml:extra-deps: - liquidhaskell-cabal-0.2.1.0(If your
stack.yamlalready has anextra-depslist, addliquidhaskell-cabal-0.2.1.0to the existing one instead of starting a second list.)Then, if you're using a version of Stack prior to 1.4, add the following as well:
explicit-setup-deps: "*": trueOtherwise, with Stack 1.4+, the
custom-setupstanza in the.cabalfile will be recognized automatically, and theexplicit-setup-depsfield is unnecessary.
That's it! You should be good to go.
If you're using Stack, you can build and check with LiquidHaskell by adding
--flag <package name>:liquidhaskell to your stack build command:
stack build --flag mypackage:liquidhaskell
Otherwise, pass -fliquidhaskell to cabal configure to switch on
LiquidHaskell checking for your builds:
cabal configure -fliquidhaskell && cabal build
(Running cabal configure without -fliquidhaskell will turn it back off.)
liquidhaskell-cabal includes a few new fields that you can add to your .cabal file for each
executable or library.
Extra command line flags to pass to LiquidHaskell (these are described in the LiquidHaskell README).
Multiple x-liquidhaskell-options fields may be specified per component. The concatenation of the
command line flags extracted from each will be passed to LiquidHaskell.
library
(... other fields ...)
x-liquidhaskell-options: --diff --no-termination
executable myexecutable
(... other fields ...)
x-liquidhaskell-options: --diff
x-liquidhaskell-options: --no-termination
When you only want LiquidHaskell to verify a subset of your project's files, instead of the whole thing, add an instance of this field for each path you want checked.
Both file and directory paths are supported, so listing A/B will also include A/B/C.hs. When
this field is missing, liquidhaskell-cabal defaults to checking all Haskell files in the project.
library
(... other fields ...)
x-liquidhaskell-verify: src/A.hs
x-liquidhaskell-verify: src/B
executable myexecutable
(... other fields ...)
x-liquidhaskell-verify: app/Main.hs
For most projects, the simple Setup.hs file given above (using
liquidHaskellMain) should be sufficient. However, for those already using
custom Setup.hs files, the LiquidHaskell.Cabal module
(Haddock)
provides more granular means of hooking LiquidHaskell into the build process.
liquidHaskellHooks
is a Cabal UserHooks structure pre-configured for LiquidHaskell. Using it,
the basic Setup.hs file is equivalent to:
import Distribution.Simple
import LiquidHaskell.Cabal
main = defaultMainWithHooks liquidHaskellHooksliquidHaskellPostBuildHook
is the Cabal postBuild hook that actually configures and runs LiquidHaskell.
Using it, the above is equivalent to:
import Distribution.Simple
import LiquidHaskell.Cabal
main = defaultMainWithHooks $
simpleUserHooks { postBuild = liquidHaskellPostBuildHook }Projects already using a postBuild hook can invoke
liquidHaskellPostBuildHook from within it, passing in the appropriate
arguments:
import Distribution.Simple
import LiquidHaskell.Cabal
main = defaultMainWithHooks $
simpleUserHooks { postBuild = myFancyHook }
myFancyHook :: Args -> BuildFlags -> PackageDescription -> LocalBuildInfo -> IO ()
myFancyHook args buildFlags pkgDesc lbi = do
{- ... other important code ... -}
liquidHaskellPostBuildHook args buildFlags pkgDesc lbi
{- ... even more code ... -}Copyright (C) 2016-2019 Michael Smith <michael@spinda.net>
This project is licensed under the BSD 3-clause license.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you shall be licensed as above, without any additional terms or conditions.