Bazel automates building and testing software. It scales to very large multi-language projects. This project extends Bazel with build rules for Haskell. Get started building your own project using these rules wih the setup script below.
The full reference documentation for rules is at https://haskell.build.
You'll need Bazel >= 0.27 installed.
If you are on NixOS, skip to the Nixpkgs section.
The easy way
In a fresh directory, run:
$ curl https://haskell.build/start | sh
$ bazel build //... # Build all targets $ bazel test //... # Run all tests
This rule set supports using Nixpkgs to provision your GHC
toolchain and to fetch hackage packages from there. To create your
--use-nix, like so:
$ sh <(curl https://haskell.build/start) --use-nix
This generates the same files as above, but uses
If you are on NixOS, this is the only way to set up your project, because the GHC toolchain provisioned through binary distributions cannot be executed on NixOS.
If you are on macOS, you will have to set the environment variable
BAZEL_USE_CPP_ONLY_TOOLCHAIN = 1, so that Bazel picks the correct C compiler.
Tutorial and Examples
A collection of example rules is in ./examples.
No such file or directory
If you see error messages complaining about missing
ld or indeed
some other executable):
cc: error trying to exec 'as': execvp: No such file or directory `cc' failed in phase `Assembler'. (Exit code: 1)
It means that your
gcc cannot find
as by itself. This happens only on
certain operating systems which have
gcc compiled without
--with-ld flags. We need to make
as visible manually in that case:
# Create a symlink to system executable 'as' genrule( name = "toolchain_as", outs = ["as"], cmd = "ln -s /usr/bin/as $@", ) # Make it visible to rules_haskell rules: haskell_toolchain( name = "ghc", tools = ["@ghc//:bin"], version = "8.4.1", extra_binaries = [":toolchain_as"], # <---- )
__STDC_VERSION__ does not advertise C99 or later
If you see an error message like this:
/root/.cache/bazel/_bazel_root/b8b1b1d6144a88c698a010767d2217af/external/ghc/lib/ghc-8.4.1/include/Stg.h:29:3: error: error: #error __STDC_VERSION__ does not advertise C99 or later # error __STDC_VERSION__ does not advertise C99 or later ^ | 29 | # error __STDC_VERSION__ does not advertise C99 or later | ^
It means that your
gcc selects incorrect flavor of C by default. We need
C99 or later, as the error message says, so try this:
haskell_toolchain( name = "ghc", tools = ["@ghc//:bin"], version = "8.4.1", compiler_flags = ["-optc-std=c99"], # <---- )
bazel fails because some executable cannot be found
Make sure you run your build in a pure nix shell
nix-shell --pure shell.nix). If it still doesn’t build,
it is likely a bug.
A Haskell dependency fails with strange error messages
If you get cabal error messages the likes of:
CallStack (from HasCallStack): dieNoWrap, called at libraries/Cabal/Cabal/Distribution/Utils/LogProgress.hs:61:9 in Cabal-184.108.40.206:Distribution.Utils.LogProgress Error: The following packages are broken because other packages they depend on are missing. These broken packages must be rebuilt before they can be used. installed package lens-labels-0.2.0.1 is broken due to missing package profunctors-5.2.2-HzcVdviprlKb7Ap1woZu4, tagged-0.8.5-HviTdonkllN1ZD6he1Zn8I
you’ve most likely hit GHC’s infamous non-deterministic library ID bug.
Warning about home modules during non-sandboxed builds
Say you have a folder that mixes source files for two different libraries or for a library and an executable. If you build with sandboxing turned off, it is possible that GHC will use the source files for one library during the build of the other. The danger in this situation is that because GHC used inputs that Bazel didn't know about, incremental rebuilds might not be correct. This is why you get a warning of the following form if this happens:
<no location info>: warning: [-Wmissing-home-modules] Modules are not listed in command line but needed for compilation: Foo
Turning sandboxing on (this is Bazel's default on Linux and macOS)
protects against this problem. If sandboxing is not an option, simply
put the source files for each target in a separate directory (you can
still use a single
BUILD file to define all targets).
Saving common command-line flags to a file
If you find yourself constantly passing the same flags on the
command-line for certain commands (such as
--compiler), you can augment the
.bazelrc file in
this repository with a
.bazelrc.local file. This file is ignored by
Reference a local checkout of
When you develop on
rules_haskell, you usually do it in the context
of a different project that has
rules_haskell as a
dependency, like so:
http_archive( name = "rules_haskell", strip_prefix = "rules_haskell-" + version, sha256 = …, urls = …, )
To reference a local checkout instead, use the
--override_repository command line option:
bazel build/test/run/sync \ --override_repository rules_haskell=/path/to/checkout
If you don’t want to type that every time, temporarily add it to
To run the test suite for these rules, you'll need Nix installed. First, from the project’s folder start a pure nix shell:
$ nix-shell --pure shell.nix
This will make sure that bazel has the exact same environment
on every development system (
To build and run tests locally, execute:
$ bazel test //...
Skylark code in this project is formatted according to the output of buildifier. You can check that the formatting is correct using:
$ bazel run //:buildifier
If tests fail then run the following to fix the formatting:
$ git rebase --exec "bazel run //:buildifier-fix" <first commit>
<first commit> is the first commit in your pull request.
This fixes formatting for each of your commits separately, to keep
the history clean.
You have to find a new git commit where all our
dependencies are available from the official NixOS Hydra binary cache.
At least for
x86-linux this is guaranteed for the
channels. You can find the
nixpkgs git commit of current
That might be too old for your use-case (because all tests have to pass for that channel to be updated), so as a fallback there is:
You copy that hash to
./nixpkgs/default.nix. Don’t forget to
sha256 or it will use the old version. Please update the
date comment to the date of the
nixpkgs commit you are pinning to.
Pull Requests are checked by CircleCI.
If a check fails and you cannot reproduce it locally (e.g. it failed on Darwin and you only run Linux), you can ssh into CircleCI to aid debugging.
“unable to start any build”
error: unable to start any build; either increase '--max-jobs' or enable remote builds
--builders "" and
--max-jobs 0 on CI to be sure all
dependencies are coming from binary caches. You might need to add an
exception (TODO: where to add exception) or switch to a different