You have nerd sniped me in the worst possible way. I can never unsee this, and now I will have to write an sbt plugin that spits out the corresponding nix per-jar/per-binary.
I’ve done that in a successful way in real life, twice.
When I was working for https://www.tweag.io/ at our client, https://www.kittyhawk.aero/. I was maintaining a large codebase in bazel, using mostly GitHub - tweag/rules_nixpkgs: Rules for importing Nixpkgs packages into Bazel.. We were in 2019. I had many issues with bazel, especially, the remote cache was unreliable, most rule had bug or were not suitable for our uses cases (we were doing a lot of code generation, cross compilation and had a few complex rules to apply on the codebase due to aerial certification of our software).
I decided to follow a smooth migration path, so actually, I wrote a bit of nix code which was loading all the bazel BUILD
files and was parsing it (using python) to generate nix code.
I then left tweag and kittyhawk and joined https://www.novainsilico.ai/. I was hired because I had experience with bazel: they had a large codebase built with it bazel. For one year, I maintained the bazel build system and one day, I decided that it was enough and I started the same experiment.
In one day, I wrote again from scratch the python parser, able to convert .BUILD
files to .nix
as well as the base of the build system in order to build our haskell codebase. The nix
builder was merged a few days after and we kept the BUILD
file as reference for a few months then decided to remove the indirection and commit the intermediate nix files. For example, here is one of our build file, right now, used daily by many engineers:
{ top
, self
, pkgs
, glob
, nova_haskell_library
, ...
}:
bindings = nova_haskell_library {
name = "bindings";
srcs = [ c2hs ] ++ glob { patterns = [ "bindings/**/*.hs" ]; };
deps = [ pkgs.libsbml ];
};
Note that since, we decided to move away from the “bazel feature set” and introduce the feature we want. For example, the deps
argument, representing the list of dependencies, is not required anymore and everything is auto-detected at nix build
time.
A few notes about it:
- I don’t know how bazel evolved since 2021, but in 2021 nix was superior in all aspect but one: intremental build of small element.
- If you do not have time to maintain a build system, do not use nix (as a build system) nor bazel, use a monolithic
nix shell
and build whatever your language is with whatever is the standard tool. - If you do not have special requirements, but just want a “polyglot” build system, go for bazel, if the rule for your langage exists and are of good quality, it will be great
- If on the other hand you have time, special requirements or that simply the rules available for your language are not available or of quality, I would suggest to go to nix instead of bazel. Again, I don’t know how bazel evolved since 2021, but at that time, it had been a nightmare for me.
- Having a transition from bazel to nix by parsing the
BUILD
files and producing a nix file had allowed me to smoothly replace bazel by nix. - Nix does have a really nice property: everything is written in nix. With bazel, that’s a bit more complex and (again, in 2021), some stuff were just plainly impossible without cloning bazel itself and writing java.
- From my point of view, a build system is a generic tool + code adapted to your problem. The question is what is part of the generic tool and what is part of the code adapted to your problem. I think that nix does the right thing here (e.g. it provides a language to define build, as well as a build environment which takes care of remote / caching / sandboxing, …), but not more. The part adapted to your problem is really specific. Actually, that’s why I had never published anything: all the nix code written on both projects are specific to the project.
Sorry, I took the opportunity of this post to do a “short” write about my experience with a migration from bazel to nix and by how our “nix based custom build system” looks like bazel. I should have done that way earlier, but never took the time. Please take what I wrote with a grain of salt: using bazel is still one of the biggest failure I had as a software engineer. I have this feeling that I really missed something, when my colleagues, boss, …, who are all software engineers more skilled than what I will never be, all loved bazel, and that I dislike it.