Our team is currently struggling with development environments.
gcc, clang, cmake, conan
different python modules (even interpreters with different versions), etc. So far, every developer gets a computer with Ubuntu and they are responsible for setting up their own environment. There are some lose guidelines (i.e. gcc-12.0.0
, clang-14.0.1
, conan-1.59.0
, etc.), but it happened already more than once that some had installed gcc-11
instead of 12
, etc. which then further down in the build process caused issues.So we are basically looking for a way to have reproducible development environments, that still leave enough flexibility to each developer (i.e. our build system is based around conan
and cmake
, so any modern IDE can be used to build, debug, and run the projects).
Now this is not a new problem, but the information on Stack Overflow is unfortunately not that easy to find and maybe even outdated (e.g. here).
From reading on the internet, it seems that one possible solution to the problem is called nix
. What I don't understand is the role of nix
in the context of an OS and package manager. Assuming I have a Ubuntu computer in front of me. This has all the standard locations on the filesystem (i.e. /
, /bin
, /home
, etc.). I can now:
nix
on said computer/nix/store
, (i.e. the gcc
build there does not go into /bin
or /usr/bin
).Now presumably I can then later use these installed packages to build the software I want to build, but how exactly? If they are not in $PATH
, then how do I use them? If I add them to $PATH
, then whats the point of having them and how do I guarantee that they don't clash with what is already installed and inside $PATH
? Can I use this setup with any IDE of my choosing?
If nix
is the wrong tool for the problem I described above, I am more than happy to consider others. docker
seems to be one alternative, but this has its own downsides...
Nix is a great tool for this sort of thing. But don't think about a "config" (that term usually refers to NixOS, which you are not using and don't need to use).
What you should do is write a file named shell.nix
that contains an expression in the Nix language that calls mkShell to define all the dependencies you need. Then you run nix-shell
in that directory and Nix will automatically build/install all the dependencies that you need, and then launch a special shell with those dependencies on your PATH, in front of the default stuff from your system. Then you can do your development work in that shell.
Here's an example shell.nix
I wrote recently when I wanted to compile the LLVM project from source:
let
pkgs = import <nixpkgs> {};
in
pkgs.mkShell {
buildInputs = [
pkgs.cmake
pkgs.pkg-config
pkgs.gdb
pkgs.ninja
pkgs.python3
];
NIX_HARDENING_ENABLE = "";
}
What I did above was just import the user's current nixpkgs
channel, but for reproducibility you'll want to pin a specific version of Nixpkgs in your expression so that everyone gets the same version of GCC and all the other packages.
To really understand what Nix is doing and what it gets you, I recommend reading Eelco Dolstra's thesis.