Overriding a package without rebuilding it

Is it possible to run a script on the output of a package without having to rebuild it?
The package I would like to modify takes several hours to build, but I just need to add some lines to a bash script it contains in it’s $out folder.

You could “wrap” it, by copying it’s out to a new out, changing only the scripts you need to change.

Yeah, I thought of something like that aswell. I just thought there would be a convenience function for that which would also leave the attributes and override functions intact.

Sorry to hijack this thread, I am trying to do the same (change the bash script generated by nix to wrap a compiled executable).

@NobbZ By “wrap” you mean wrap the original derivation in a new derivation, not wrap a file in /bin with the makeWrapper shell command available during builds?

@busti Can you elaborate what you have done?

The basic idea is that you create a new package entirely and then have that copy the outputs of the first package to it’s output directory.

3 Likes

I do what you’re asking for a lot for my projects, and use the copying technique suggested by the other answers.

Here is a fully commented example:

2 Likes

The symlinkJoin trivial builder constructs a new derivation populated by just directories and symlinks from the paths argument. Then in postBuild you can do whatever you want, like wrapProgram or substituteInPlace. Since it operates on the output of the original, it doesn’t rebuild the original.

  dict = pkgs.symlinkJoin {
    name = "dict-wrapped";
    paths = [ pkgs.dict ];
    nativeBuildInputs = [ pkgs.makeBinaryWrapper ];
    postBuild = ''
      wrapProgram "$out/bin/dictd" \
        --add-flags '--config "${myconfigfile}"'
    '';
  };
5 Likes

limitation: symlinkJoin cannot replace files (also cannot delete files)

so, when multiple paths have the same file, then symlinkJoin will use the first file

symlinkJoin is defined in nixpkgs/pkgs/build-support/trivial-builders.nix

symlinkJoin is basically just xorg.lndir

        for i in $(cat $pathsPath); do
          ${lndir}/bin/lndir -silent $i $out
        done

reproduce:

cd $(mktemp -d)
nix-shell -p xorg.lndir
mkdir a b z
touch a/f b/f
for path in a b; do lndir $PWD/$path z; done
# f: /tmp/tmp.wbIlOkiaFH/a/f
readlink z/f
# /tmp/tmp.wbIlOkiaFH/a/f

see also symlinkjoin: print warning when keeping existing file by milahu · Pull Request #214710 · NixOS/nixpkgs · GitHub