Specifying runtime dependencies for shell scripts

I’m trying to learn how to package software with Nix. The software I want to package targets small routers, relies on shell scripting quite a bit, and uses tr that is a part of coreutils. The derivation is pretty run-of-the-mill:

{ lib, pkgs, stdenv, fetchFromGitHub, ... }:

stdenv.mkDerivation rec {
  pname = "zapret";
  src = fetchFromGitHub { owner = "bol-van"; repo = pname; };

  propagatedBuildInputs = with pkgs; [ libcap zlib libnetfilter_queue libnfnetlink coreutils ];

  buildPhase = ''
    # copy some files
    # replace hardcoded paths with ${placeholder "out"} using substituteInPlace
    make all -C ${placeholder "out"}/
  '';

  installPhase = ''
    # copy some files
  '';
}

However, the package doesn’t have access to coreutils at runtime when installed as systemd.packages, because Nix determines runtime dependencies automatically and there’s no reference to ${pkgs.coreutils}/bin/tr anywhere in the derived result.

What’s the generic way to deal with this? Patching all shell scripts to replace tr with ${pkgs.coreutils}/bin/tr seems extremely fragile and feels like a whack-a-mole (what if tr is replaced in the future? Does it reference another shell command I didn’t happen to test for? tr is too small of an anchor, etc).

1 Like

Have you tried to add coreutils to buildInputs ?

Yes, adding buildInputs = [ pkgs.coreutils ]; was the first thing I attempted to no avail.

For shell scripts, you can also use resholve.

1 Like

This post I wrote outlines the main approaches and tradeoffs (as I see them, at least):

3 Likes

I wish I could have some good documentation on how to fix this issue and what’s the difference between adding something in nativeBuildInputs ans buildInputs.

There’s also GitHub - nix-community/patsh: A command-line tool for patching shell scripts inspired by resholve [maintainer=@figsoda] that might be cool to have a look to.