Nix packages vs environments/shells/devShell

I’m a Nix newbie undergoing a fairly substantial packaging effort, and have several hundred auto-generated packages compiling, but I’m struggling with environment setup. For example, I know that when I do a plain nix develop, I either get dropped into the flake’s devShell output, or if that doesn’t exist I get the develop environment of the defaultPackage output, equivalent to nix develop [that-package]. However:

  • I can’t tell what I need to do to build the develop shell for a package without actually entering it (for example, to cache or even just inspect it). When I do nix develop foo, I see it building a foo-env installable— what is that thing and where is it? Is that the entirety of the shell definition, or are there hooks or other parts that are only available to the nix interpreter during evaluation? (for example, the stuff visible to invocations like nix eval .#<pkgname>.meta)
  • How do I make my own derivation work with nix shell, for example one based on buildEnv (nixpkgs/default.nix at a5b3afece376f255309bf959f6651e91a1c6e1b4 · NixOS/nixpkgs · GitHub)? It didn’t seem like it was enough to just create a nix-support/setup-hook file in the postBuild— is this even possible, or is the correct strategy to have a mkShell that has a buildEnv as a buildInput, in the case where I want to both set up a unified symlink workspace, but also set a bunch of envvars?
  • The mkShell definition (nixpkgs/default.nix at a5b3afece376f255309bf959f6651e91a1c6e1b4 · NixOS/nixpkgs · GitHub) specifically prohibits building with its noBuildPhase. Does this mean that whatever the definition is that it generates is never accessible externally? (For example, if I wanted to do something like source path/to/thing with it rather than needing to always launch a subshell.)

I know there are a bunch of confused bits here, and like I say I think I’ve made good headway on the packaging side, but now I’m needing to understand more of the guts of what’s going on with Nix at runtime and coming up short. Thanks!

1 Like

From a shell that is based on a package definition you conventionally do

unpackPhase;
cd $src;
patchPhase;
configurePhase;
buildPhase;
installPhase;
fixupPhase;

Those are the usual phases but a particular package may have pre<NAME>Phase and post<NAME>Phase for each of those above, or some phases might not be used.

I believe there’s an environment variable that contains the list of phases used. I usually just read the package derivation personally. They are shell functions so set|grep Phase; should also work.

Yeah, so I’m aware that I can nix develop foo and then use the resulting shell to step through the build for foo. My question is more "what would the steps be to roll my own nix develop foo. For example, I can do:

nix build .#foo.inputDerivation

And the result of that appears to be a file that you could source in a new terminal, since it’s full of declare -x entire for envvars. But it’s clearly not the whole story, since actually running nix develop foo also runs a bunch of hooks on entrance to the shell. The result of those hook runs is not captured in the inputDerivation. Do I just need to source $stdenv; runHook ????, or is there some deeper magic going on here?

1 Like

I’ve committed the minor sin of not reading all of this thread, but a couple nights ago I was working on something semi-adjacent and noticed one of the newer Nix commands that may do what you want, here.

I haven’t tried it out, myself, but take a look at nix print-dev-env --help or nix print-dev-env

Thanks! It does seem like nix print-dev-env does exactly what I was wanting as far as capturing the state of the develop shell. I do wish it was clearer what was going on here so that I could “roll my own” and not feel so dependent on secret Nix magic. But this will do for now.