makeWrapper vs substitute

I’m packaging a Bash script that has a few runtime dependencies.

I’m using substitute to patch the shebang, but for the other dependencies it seems like I could either use substitute to patch in absolute paths or use wrapProgram to add the dependencies to the PATH.

Are there pros / cons I should take into consideration when making this decision?

To illustrate, a way oversimplified example might be a trivial bash script ./foo like,

#! /usr/bin/env bash
git log --pretty=oneline

If the default.nix substituted absolute paths to the script’s runtime dependencies, it might look like,

{ git, lib, runCommand, runtimeShell }:

runCommand "foo" { } ''
  mkdir -p $out/bin

  substitute ${./foo} $out/bin/foo \
      --replace '/usr/bin/env bash' ${runtimeShell} \
      --replace git ${git}/bin/git

  chmod +x $out/bin/foo
''

If instead it added dependencies to PATH, it could look like,

{ git, lib, makeWrapper, runCommand, runtimeShell }:

runCommand "foo" {
  nativeBuildInputs = [ makeWrapper ];
} ''
  mkdir -p $out/bin

  substitute ${./foo} $out/bin/foo \
      --replace '/usr/bin/env bash' ${runtimeShell}

  chmod +x $out/bin/foo

  wrapProgram $out/bin/foo \
      --prefix PATH : "${lib.makeBinPath [ git ]}"
''

Shebang patching should be done automatically on fixupPhase.
The reason why it doesn’t happen with recent nixpkgs is the absence of the new program in buildInputs.
Just buildInputs = [ bash ] should do the trick.

2 Likes

I wasn’t able to get patchShebangs to fire automatically, despite adding bash to buildInputs. Same with propogatedBuildInputs. I also tried adding stdenv to the dependencies but still no luck.

I can at least call patchShebangs directly instead of using substitute to do it.

Here’s what I’ve got so far.

{ bash, git, lib, makeWrapper, runCommand }:

in runCommand "foo" {
  nativeBuildInputs = [ makeWrapper ];
  propagatedBuildInputs [ bash git ];
} ''
  mkdir -p $out/bin

  cp ${./foo} $out/bin/foo
  chmod +x $out/bin/foo

  patchShebangs --host $out/bin

  wrapProgram $out/bin/foo \
      --prefix PATH : "${lib.makeBinPath [ bash git ]}"
''