Strange `nix develop `behavior when overriding `installPhase`

Hello all,

I have a short derivation which does nothing apart from move its source files around a bit:

stdenv.mkDerivation {
  ...
  src = ./.;
  buildPhase = "";
  installPhase = ''
    mkdir -p $out/include
    cp $src/*.hpp $out/include/
  '';
}

If I run nix build this all works fine. However, if I run nix develop, I see that I have both a generic installPhase function:

$ type installPhase

installPhase is a function
installPhase () 
{ 
    runHook preInstall;
    if [ -n "$prefix" ]; then
        mkdir -p "$prefix";
    ...

as well as an environment variable with my custom installPhase in. Is this a bug? Should setting installPhase in the derivation not override the installPhase function, rather than being passed in as environment variable?

Thanks!

No, there is no special override code. Most of your attributes are exported as environment variables.

setup.sh sets the lookup order by checking the variable first if it exists, then falls back to the function of the same name: nixpkgs/setup.sh at d27f79a28f1e3da57436c3dfe1ccda5f78e3860f · NixOS/nixpkgs · GitHub

        # Evaluate the variable named $curPhase if it exists, otherwise the
        # function named $curPhase.
        eval "${!curPhase:-$curPhase}"

Thanks, that’s helpful to know. I’m still a bit confused about the situation I’m having, though -

  • nix build .#mypackage works fine,
  • but doing nix develop .#mypackage; configurePhase; buildPhase; installPhase gets me the error make: *** No rule to make target 'install'. Stop.

It seems odd to me that running the individual stages of the build in the development shell is getting a different result from nix build, and it looks like the nix develop shell is trying to run the default installPhase function rather than the installPhase code in the derivation.

By typing installPhase you are running default installPhase. If you overrode one you probably want to run your $installPhase. You’ll need to emulate eval "${!curPhase:-$curPhase}" code of genericBuild.

For example via eval "$installPhase". I usually just run genericBuild instead of hunting down the way to run every phase manually.

Right, I get this now. I thought setting the eg installPhase environment variables was overriding the default phases. But as you say, it’s not. Thanks.