Code Monkey home page Code Monkey logo

ghc-nix's Introduction

ghc-nix

demo

ghc-nix is an attempt to augment GHC with the ability to use Nix as a caching layer. This has the potential to dramatically speed up "pure Nix" builds by being able to re-use build artefacts for files that haven't changed. It also has the potential to speed up developers collaborating on work, by allowing them to pull down pre-built artefacts from a shared build server, rather than building locally.

What's the Plan?

When you do cabal build, Cabal calls out to GHC with a single exec call, primarily to ghc --make. GHC actually has a build system built in, and GHC will form a dependency graph and start doing minimal recompilation where possible. However, this is only useful if you have some kind of reusable directory to keep the cache artefacts - and that doesn't exist on build machines like Hydra.

The plan then is to replace ghc --make with something that can use the Nix store. cabal build has the -w option to give it another compiler, but it will still call that executable with the same arguments. If we can impersonate GHC, then we can get the caching we desire - that's what this project does.

When ghc-nix is called with --make, we use the GHC API to form a dependency graph, as ghc --make would. However, rather than just doing the build, instead we transform this dependency graph into a series of Nix expressions, each of which will build a single .hs source file into .o and .hi files. Finally, we aggregate all the build artefacts and place the files where they need to go for Cabal to continue with the next phase (linking).

However, just doing Nix builds is not enough, we need one more experimental Nix feature to get something useful - content-addressable store paths. Usually, the objects in a Nix store are hashed based on all of the dependencies that are required to produce the store path. This ultimately comes down to an exact hash of all the source code. However, this means that if you make object-file-preserving changes, you still end up recompiling everything downstream. For example, a single comment change causes all dependents to rebuild, even though they can't observe a change.

Once we've built the .o and .hi files, we rewrite the resulting store path to one who's hash is based on the contents of these files, and not the the files that built them. This cuts the connection between an object file and its source code, allowing early cut off.

This is supported as an experimental Nix feature - nix make-content-addressable.

Trying this Out

This project is still in very early days, so it's not too easy to use... yet. Maybe you can help here! To try ghc-nix out you will need:

Nix changes

  • A version of Nix that is at least 4511f09b490fad4ce0dcfbcd7c4fd83b11e7df46.

  • nix-command and ca-references enabled as experimental features.

Heres's a snippet of my configuration.nix that should get you this.

{
  systemFeatures =
    [ "benchmark" "big-parallel" "kvm" "nixos-test" "recursive-nix" "nix-command" "ca-references" ];

  extraOptions =
    ''
    experimental-features = recursive-nix nix-command ca-references
    '';

  package =
    let
      src =
        pkgs.fetchFromGitHub
          { owner =
              "NixOS";

            repo =
              "nix";

            rev =
              "9f7b4d068cc106e5d902dc6f52bf46d4a057fd00";

            sha256 =
              "187pfanj0g49ng5smfi8rwkq1l3r43mf85yv390h0ars050fxfik";
          };

    in
    ( import "${src}/release.nix" { nix = src; officialRelease = true; } ).build.x86_64-linux;
}

Building ghc-nix

ghc-nix is built like a normal Haskell project, but you will have to actually use cabal install to have this work. I do this, in the ghc-nix directory:

cabal install --installdir=./bin --overwrite-policy=always

Using ghc-nix

You can now finally use ghc-nix by going to a Cabal project and running:

cabal build -w /path/to/ghc-nix/bin/ghc-nix

You will need a working ghc on your PATH, too (this will hopefully change in the future).

If you get problems with packages not being found and you're using Nix, you might need to run:

NIX_GHC=$(type -p ghc)
eval $(grep export "$NIX_GHC")

ghc-nix's People

Contributors

matthewbauer avatar ocharles avatar gabriella439 avatar

Stargazers

Rusty avatar Drewry Pope avatar Qqwy / Marten avatar  avatar Fabián Vega Alcota avatar Arnau Abella avatar Marc Jakobi avatar ners avatar Danila Danko avatar  avatar Mia Jasmin Bautista Sanchez avatar Maximilian Bosch avatar Martin Myrseth avatar Mango The Fourth avatar Shohei Shimomura avatar Spencer Janssen avatar Thales Macedo Garitezi avatar Ryan Lahfa avatar Donna avatar Nikita avatar hussein-aitlahcen avatar Pete Murphy avatar KlarkC avatar Rahul Butani avatar Even Brenden avatar Rehno Lindeque avatar Kayla Firestack avatar jade avatar Andrea Ciceri avatar Terje Larsen avatar Jakub Kozłowski avatar Remy Goldschmidt avatar Sandro avatar Hécate avatar GuangTao Zhang avatar  avatar Tristan de Cacqueray avatar Ellie Hermaszewska avatar Rosario Pulella avatar Emmanuel Denloye-Ito avatar Shae Erisson avatar Andreas Källberg avatar Ari Becker avatar Oleg Pykhalov avatar  avatar Peter Kolloch avatar Scott Fleischman avatar Robert Kreuzer avatar Cody Goodman avatar Philip Lykke Carlsen avatar Adrian Marti avatar Shinya Yamaguchi avatar Zach Hamlin avatar Mohammad Hasani avatar Ole avatar Eric Crosson avatar Kiara Grouwstra avatar Matthías Páll Gissurarson avatar Tim Pierson avatar  avatar  avatar Brett Mandler avatar Alexander Carter avatar  avatar  avatar toonn avatar cem guresci avatar Hal Henke avatar Richard Wallace avatar Matthew Pickering avatar Evan Rowley avatar Luc Tielen avatar Lupino avatar Paul Young avatar  avatar Lucas Alexander Floriani avatar Peter Siska avatar Daniel Díaz Carrete avatar Jürgen Keck avatar Medson Oliveira avatar  avatar Sibelius Seraphini avatar Mrinal avatar Flavio Corpa avatar John Children avatar James Brock avatar Daniel Kahlenberg avatar Steven Shaw avatar Przemysław Kopański avatar Greg Hale avatar Petter Rasmussen avatar Vladimir Kalnitsky avatar Yuriy Pitomets avatar  avatar  avatar Volodymyr Kyrylov avatar Domen Kožar avatar Alessandro Marrella avatar Tyler Weir avatar Kristleifur Daðason avatar

Watchers

 avatar Richard Wallace avatar Pi3r avatar Olle Fredriksson avatar  avatar Andreas Källberg avatar Alex Vorobiev avatar James Cloos avatar Evan Relf avatar Luc Tielen avatar Rahul Butani avatar Emmanuel Denloye-Ito avatar  avatar Danny avatar  avatar

ghc-nix's Issues

nixpkgs version to build ghc-nix

Hi, what nixpkgs git rev would you recommend building ghc-nix with? I'm getting errors during the build when I do cabal install from within the shell provided by the shell.nix. Thanks.

Edit:
Actually it might be that I wasn't specifying the appropriate compiler.

Edit 2:
So I installed ghc107 with haskell.compiler.ghc8107 and ran cabal install --installdir=./bin --overwrite-policy=always without using nix-shell, and that worked.

But maybe it would be nice to add some pins in the readme perhaps?

Revival?

WIth dynamic derivations as specified in RFC 92, we could get this to work seamlessly.

Awesome! I've got questions!

This looks really neat. Here's a few questions I have though:

  • do you have timing information for identical rebuilds?
    • first run: (everything needs to be built) cabal vs. ghc-nix. I guess you could force ghc-nix to rebuild everything by giving the hs-builder an argument and embed that into the derivation, e.g. a splace or some # comment, to prevent pre-existing cache-hits.
  • second run: (evertying is already built) cabal vs. ghc-nix
  • we essentially generate a nix expression for each haskell file, this seems pretty similar to snack, except that we don't try to do it all in nix. Does the explosion of nix-expressions cause issues?
  • any reason this would not work with Setup.hs?
  • Finally, ghc-nix calles out to nix a lot, unless I missread the source, so this won't work inside a nix-build unless we have recursive nix?

Thanks! Amazing work!

How can I help?

The idea, and the benchmarks, are very promising! I'd love to contribute to making this more widely usable. Is there a roadmap, or summary of things needed?

My first attempt was to get a ghc-nix-built package packageable in nix. By which I mean something like so. Running with cabal build -w works well, but the nixpkgs-test default.nix linked seems to have bit-rotten, mostly due issues arising from sandboxing. I noticed a few places seem to assume ghc-nix is running outside of a sandbox (for instance nixBuildTool, which fetches dependencies at runtime rather than being set up to already have them). I'm now wondering whether my initial goal matches where the project is going, so thought I'd ask.

But in general, am happy to help however makes sense!

Awesome library.. some issues testing it out.

I'm using Nix at work and I've been eager for something like this for building Haskell with Nix. Because I'm not currently running on NixOS, I decided to try out the nix expression contained ghc-nix/nixpkgs-test. After reading this file, I'm came to the conclusion that this was perhaps meant to be a template for building Haskell libraries with ghc-nix. However, I tried nix-build in that directory and my build fails. Here is the output I get. I'm not entirely sure why these dependencies would be missing.

Configuring ghc-nix-0.1.0.0...
CallStack (from HasCallStack):
  die', called at libraries/Cabal/Cabal/Distribution/Simple/Configure.hs:958:20 in Cabal-2.2.0.1:Distribution.Simple.Configure
  configureFinalizedPackage, called at libraries/Cabal/Cabal/Distribution/Simple/Configure.hs:462:12 in Cabal-2.2.0.1:Distribution.Simple.Configure
  configure, called at libraries/Cabal/Cabal/Distribution/Simple.hs:596:20 in Cabal-2.2.0.1:Distribution.Simple
  confHook, called at libraries/Cabal/Cabal/Distribution/Simple/UserHooks.hs:67:5 in Cabal-2.2.0.1:Distribution.Simple.UserHooks
  configureAction, called at libraries/Cabal/Cabal/Distribution/Simple.hs:178:19 in Cabal-2.2.0.1:Distribution.Simple
  defaultMainHelper, called at libraries/Cabal/Cabal/Distribution/Simple.hs:115:27 in Cabal-2.2.0.1:Distribution.Simple
  defaultMain, called at /nix/store/4mdp8nhyfddh7bllbi7xszz7k9955n79-Setup.hs:2:8 in main:Main
Setup: Encountered missing dependencies:
async >=2.2.2 && <2.3,
base >=4.12,
containers >=0.6.0.1 && <0.7,
ghc >=8.6.5 && <8.7,
ghc-paths >=0.1.0.12 && <0.2

builder for '/nix/store/iyzljhdrcz60x6ywpd3rnwcsjsgb3vzq-ghc-nix-0.1.0.0.drv' failed with exit code 1
cannot build derivation '/nix/store/f9cfiwrbq6y5ahx3k8r7q96avdypchnz-fused-effects-0.1.1.0.drv': 1 dependencies couldn't be built
error: build of '/nix/store/f9cfiwrbq6y5ahx3k8r7q96avdypchnz-fused-effects-0.1.1.0.drv' failed

FYI. I'm running Arch Linux.

Dependent files via embedFile are not provided in Nix derivation

Uses of embedFile fail currently because the embedded file is not available to the Nix derivation.

GHC has a variable in TcGblEnv called tcg_dependent_files which lists all of the files used in the module. Is it possible to find files from that? Ideally we wouldn't have to typecheck the whole module but just find these dependent files.

perf improvement: generate derivations ourselves, bypassing nix evaluation

I was talking to @puckipedia about this project and we were both somewhat surprised that Nix evaluations are invoked for each command invocation via nix-build on some Nix source, rather than emitting .drv files directly and skipping the nix language.

Emitting .drv files directly, then calling nix-store --add and nix-store --realise would save time and avoid the overhead of O(modules) number of Nix evaluations (although I do not have traces of exactly how much).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.