`command not found` in derivation buildPhase?

I am trying to build ksh from https://github.com/ksh93/ksh. This is my ksh.nix:

{ pkgs, lib ? import <nixpkgs> {} }:
pkgs.stdenv.mkDerivation {
  name = "ksh";

  src = pkgs.fetchFromGitHub {
    owner = "ksh93";
    repo = "ksh";
    rev = "d79...61b";
    sha256 = "QVL...L4=";
  };

  nativeBuildInputs = with pkgs; [
    gcc
    coreutils-full
  ];

  buildPhase = ''
    ./bin/package make
  '';

  meta = {
    mainProgram = "ksh";
    platforms = lib.platforms.linux;
  };

  passthru = {
    shellPath = "/bin/ksh";
  };
}

The problem is that the compilation process gives an error,

       > + PATH=/run/current-system/sw/bin:/bin:/usr/bin:/nix/var/nix/profiles/default/bin
       > + command cp /build/source/src/cmd/INIT/iffe.sh iffe
       > mamake: line 14: cp: command not found

This is despite having cp installed with coreutils-full, which I had obtained from ls -l /run/current-system/sw/bin/cp:

lrwxrwxrwx 1 root root 70 Jan  1  1970 /run/current-system/sw/bin/cp -> /nix/store/si964wmmwd8qc03hwxy47iw27dp4bcmj-coreutils-full-9.11/bin/cp

I did also try just coreutils as a package, which gave the same error. How could I fix this?

That’s showing that coreutils is available in the running system, not the build environment.

I could be wrong but I also don’t think you need that nativeBuildInputs at all? Not sure if that’s causing the issue though.

ksh uses getconf to get the path where utilities such as cp are. You can make a small wrapper so that cp can be found.

{
  pkgs ? import <nixpkgs> {},
  lib ? pkgs.lib,
  writeShellScriptBin ? pkgs.writeShellScriptBin,
  getconf ? pkgs.getconf
}:
pkgs.stdenv.mkDerivation {
  name = "ksh";

  src = pkgs.fetchFromGitHub {
    owner = "ksh93";
    repo = "ksh";
    rev = "d792e242b3668ec2ec84efbbbd13a5657266e61b";
    hash = "sha256-QVLf3GJ03uaJi0Y+egrRxCUXzSwd1j1EecDB1BrKaL4=";
  };

  nativeBuildInputs = [
    (writeShellScriptBin "getconf" ''
      if [ "$1" = PATH ]; then
        echo "$PATH"
      else
        exec ${lib.getExe getconf} "$@"
      fi
    '')
  ];

  buildPhase = ''
    sh ./bin/package make
  '';

  installPhase = ''
    mkdir -p $out
    sh ./bin/package install $out
  '';

  meta = {
    mainProgram = "ksh";
    platforms = lib.platforms.linux;
  };

  passthru = {
    shellPath = "/bin/ksh";
  };
}

Woah, this works! So from what I understand in writeShellScriptBin, getconf is either gained directly from PATH, or the /nix/store/… path if not found. Is there a reason why importing getconf directly in nativeBuildScripts does not place getconf into the path?

The issue isn’t that getconf was not in the path, the issue is that glibc’s getconf reports the default path as /run/current-system/sw/bin:/bin:/usr/bin:/nix/var/nix/profiles/default/bin which is not correct within the build environment. The script just echos $PATH instead.

Ah, I see, thank you! I learned a lot.