Rules Haskell Documentation
Total Page:16
File Type:pdf, Size:1020Kb
rules_haskell Documentation Tweag I/O Aug 30, 2021 Contents: 1 Is Bazel right for me? 3 1.1 Rule of thumb..............................................3 1.2 Rationale.................................................3 2 Introduction to Bazel: Building a Haskell project5 2.1 What you’ll learn.............................................5 2.2 Before you begin.............................................5 2.3 Build with Bazel.............................................6 2.4 Refine your Bazel build.........................................8 2.5 Use labels to reference targets...................................... 11 2.6 Further reading.............................................. 11 3 Common Haskell Build Use Cases 13 3.1 Starting a new project.......................................... 13 3.2 Making rules_haskell available..................................... 13 3.3 Picking a compiler............................................ 14 3.4 Loading targets in a REPL........................................ 15 3.5 Configuring IDE integration with ghcide................................ 15 3.6 Building Cabal packages......................................... 17 3.7 Building Cabal packages (using Nix).................................. 21 3.8 Generating API documentation..................................... 21 3.9 Linting your code............................................ 22 3.10 Using conditional compilation...................................... 22 3.11 Using source code pre-processors.................................... 23 3.12 Checking code coverage......................................... 23 3.13 Persistent Worker Mode (experimental)................................. 24 3.14 Building fully-statically-linked binaries................................. 25 3.15 Containerization with rules_docker................................... 27 3.16 Cross-compilation............................................ 30 i ii rules_haskell Documentation Bazel is a tool for automating the building and the testing of software. Follow this guide to get started building small Haskell projects using Bazel. For a deeper dive and solutions to more advanced use cases, see Common Haskell Build Use Cases. Refer to the Bazel documentation for more about Bazel. Requirements: • Bazel: See the start script for versions that are known to be compatible. Contents: 1 rules_haskell Documentation 2 Contents: CHAPTER 1 Is Bazel right for me? Nearly as many build tools exist as there are programming languages out there. C++ has Autotools/Make, CMake and many others. Java has Ant, Maven, Gradle and several more. Haskell has Cabal, Stack, Shake and several more. Each of these originated in a given language community but are in some cases generic enough to support building any language. Are any of them the right choice for your use case? Should you be combining several systems? That’s what this document should help you answer. 1.1 Rule of thumb If a combination of the following apply, then you’re better off using Cabal or Stack: • your project is an independently publishable single library, or small set of libraries; • your project is open source code and has at most small static assets (hence publishable on Hackage); • your project is nearly entirely Haskell code with perhaps a little bit of C; • your project has many dependencies on other packages found on Hackage but few if any system dependencies (like zlib, libpng etc); Bazel works well for the following use cases: • projects that cannot be hosted on Hackage (games with large static assets, proprietary code etc); • projects with a very large amount of code hosted in a single repository; • projects in which you or your team are writing code in two or more languages (e.g. Haskell/PureScript, or Haskell/Java, or Haskell/C++/FORTRAN); 1.2 Rationale For all the benefits it can bring, Bazel also has an upfront cost. Don’t pay that cost if the benefits don’t justify it. 3 rules_haskell Documentation If you don’t have much code to build, any build tool will do. Build issues like lack of complete reproducibility are comparatively easier to debug, and working around build system bugs by wiping the entire build cache first is entirely viable in this particular case. So might as well use low-powered Haskell-native build tools that ship with GHC. You won’t need sandboxed build actions to guarantee build system correctness, completely hermetic builds for good reproducibility, build caching, test result caching or distributed builds for faster build and test times. Those features start to matter for larger projects, and become essential for very large monorepos. Why exactly do these features matter? • Hermetic builds are builds that do not take any part of the host’s system configuration (set of installed system libraries and their versions, content of /etc, OS version, etc) as an input. If all build actions are deterministic, hermeticity guarantees that builds are reproducible anywhere, anytime. More developers on a project means more subtly different system configurations to cope with. The more system configurations, the more likely that the build will fail in one of these configurations but not in others. Unless the build is completely hermetic. • Sandboxing build actions guarantees that all inputs to all build actions are properly declared. This helps prevent build system correctness bugs, which are surprisingly and exceedingly common in most non-sandboxing build systems, especially as the build system becomes more complex. When a build system might be incorrect, users regularly have to wipe the entire build cache to work around issues. As the codebase becomes very large, rebuilding from scratch can cost a lot of CPU time. • Distributed build caches make building the code from a fresh checkout trivially fast. Continuous integration populates the build cache at every branch push, so that building all artifacts from fresh checkouts seldom needs to actually build anything at all locally. In the common case, builds become network-bound instead of CPU-bound. • Distributed build action execution mean that average build times can stay constant even as the codebase grows, because you can seamlessly distribute the build on more machines. • Test result caching is the key to keeping continuous integration times very low. Only those tests that depend on code that was modified need be rerun. On their own hermetic and sandboxed builds can already save quite a few headaches. But crucially, without them one can’t even hope to have any of the other features that follow them above. 4 Chapter 1. Is Bazel right for me? CHAPTER 2 Introduction to Bazel: Building a Haskell project In this tutorial, you’ll learn the basics of building Haskell applications with Bazel. You will set up your workspace and build a simple Haskell project that illustrates key Bazel concepts, such as targets and BUILD.bazel files. After completing this tutorial, take a look at Common Haskell build use cases for information on more advanced concepts such as writing and running Haskell tests. 2.1 What you’ll learn In this tutorial you’ll learn how to: • build a target, • visualize the project’s dependencies, • split the project into multiple targets and packages, • control target visibility across packages, • reference targets through labels. 2.2 Before you begin On a Unix system you will need the following tools installed. • gcc • libffi • libgmp • libtinfo5 • make 5 rules_haskell Documentation • python3 (python also needs to be available in $PATH. Depending on your distribution, this might require installing the python meta-package, which might use Python 2 or 3, rules_haskell works with both.) On Ubuntu you can obtain them by installing the following packages. build-essential libffi-dev libgmp-dev libtinfo5 libtinfo-dev python python3 On Windows you will need. • msys2 • python3 Next, install Bazel if you don’t have it installed already. Then, retrieve the rules_haskell GitHub repository: git clone https://github.com/tweag/rules_haskell/ The sample project for this tutorial is in the tutorial directory and is structured as follows: rules_haskell tutorial WORKSPACE main BUILD.bazel Main.hs lib BUILD.bazel Bool.hs The first thing to do is to: $ cd tutorial If you use the NixOS distribution, also run the following command: $ echo 'test --host_platform=@io_tweag_rules_nixpkgs//nixpkgs/platforms:host' >> . ,!bazelrc.local 2.3 Build with Bazel 2.3.1 Set up the workspace Before you can build a project, you need to set up its workspace. A workspace is a directory that holds your project’s source files and Bazel’s build outputs. It also contains files that Bazel recognizes as special: • the WORKSPACE file, which identifies the directory and its contents as a Bazel workspace and lives at the root of the project’s directory structure, • one or more BUILD.bazel files, which tell Bazel how to build different parts of the project. (A directory within the workspace that contains a BUILD.bazel file is a package. You will learn about packages later in this tutorial.) To designate a directory as a Bazel workspace, create a file named WORKSPACE in that directory. This file defines external dependencies. When Bazel builds the project, all inputs and dependencies must be in the same workspace. Files residing in different workspaces are independent of one another unless linked, which is beyond the scope of this tutorial. 6 Chapter 2. Introduction to Bazel: Building a Haskell project rules_haskell Documentation 2.3.2 Understand the WORKSPACE file The file tutorial/WORKSPACE defines how to obtain rules_haskell. This file only works