Describe the problem
In Nix, wrappers are required to properly configure paths and can cause dirty issues #60260. In this thread, I focus on one issue of wrappers.
So far, wrapping is done using exec -a "$0" application-unwrapped. When wrapping an executable (i.e. not a script), I think it works nicely as the program cannot really detect that it is inside a wrapper (if the -a is forgotten, it can indeed cause troubles as I just experimented it #60260). However, for scripts the $0 variable is not propagated (this seems to be a quite fundamental issue due to the fact that the interpreter of the scripts does not care about $0): as a consequence, the program thinks that it's name is program-unwrapped. Most of the time it is not a great problem (except that help page may sounds funny with unwrapped paths), but sometimes it can cause more troubles. This is the case notably when the program tries to use $0 to start a new instance of himself (at runtime, or to respawn later, why not in a cron or as a new application...). This is done in carla #117781 but also in chromium #150826 (chromium is a binary, so it's not too much of an issue...) or in Awesome window manager #60229. It requires additional patches, from inside Nixpkgs that may be hard to maintain later and cause additional debugging time from the maintainer.
Steps To Reproduce
Steps to reproduce the behavior:
Create a file myscript.sh:
#!/usr/bin/env bash
echo "My name is $0, and MYENV is $MYENV"
the file derivation.nix:
{ stdenv, makeWrapper }:
stdenv.mkDerivation rec {
name = "-${version}";
version = "";
src = ./.;
nativeBuildInputs = [ makeWrapper ];
installPhase = ''
mkdir -p $out/bin
cp myscript.sh $out/bin
chmod +x $out/bin/myscript.sh
patchShebangs $out/bin/myscript.sh
wrapProgram $out/bin/myscript.sh --set MYENV "WIN :)"
'';
}
the file default.nix:
{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}
and run:
$ nix-build
$ ./result/bin/myscript.sh
My name is /nix/store/yc5nf2cdbjzn35n6vqlsmbbi0f5vhymf--/bin/.myscript.sh-wrapped, and MYENV is WIN :)
Expected behavior
I'd expect to see:
My name is ./result/myscript.sh, and MYENV is WIN :)
Proposed solution
A solution would be not to add a wrapper replacing the script, but to put the wrapper code directly in the interpreter of the script as I proposed it here:
{ stdenv, runtimeShell, makeWrapper, writeShellScriptBin }:
let
# TODO: A maybe cleaner solution would be directly copy the first line of the file, remove the #! and take it as interpreter.
# In case a patchshebang is required, we can maybe do the patchshebang before the wrapping so that the new interpreter.
# directly takes the appropriate patchshebang.
# For this example we know we are running a bash shell, so we just use runtimeShell directly.
# (for python scripts, replace runtimeShell with something like ${python3}/bin/python3 instead)
myWrapper = writeShellScriptBin "myWrapper" ''
# Setup environment variables...
export MYENV="WIN :-)"
# Call the original wrapper, and forward all arguments.
exec ${runtimeShell} "$@"
'';
in
stdenv.mkDerivation rec {
name = "-${version}";
version = "";
src = ./.;
nativeBuildInputs = [ makeWrapper ];
installPhase = ''
mkdir -p $out/bin
cp myscript.sh $out/bin
chmod +x $out/bin/myscript.sh
# TODO: find a more elegant solution to replace the shebang. (see discussion above comment)
substituteInPlace $out/bin/myscript.sh --replace '#!/usr/bin/env bash' '#!${myWrapper}/bin/myWrapper'
'';
}
Result:
My name is ./result/myscript.sh, and MYENV is WIN :-)
Describe the problem
In Nix, wrappers are required to properly configure paths and can cause dirty issues #60260. In this thread, I focus on one issue of wrappers.
So far, wrapping is done using
exec -a "$0" application-unwrapped. When wrapping an executable (i.e. not a script), I think it works nicely as the program cannot really detect that it is inside a wrapper (if the-ais forgotten, it can indeed cause troubles as I just experimented it #60260). However, for scripts the$0variable is not propagated (this seems to be a quite fundamental issue due to the fact that the interpreter of the scripts does not care about$0): as a consequence, the program thinks that it's name isprogram-unwrapped. Most of the time it is not a great problem (except that help page may sounds funny with unwrapped paths), but sometimes it can cause more troubles. This is the case notably when the program tries to use$0to start a new instance of himself (at runtime, or to respawn later, why not in a cron or as a new application...). This is done in carla #117781 but also in chromium #150826 (chromium is a binary, so it's not too much of an issue...) or in Awesome window manager #60229. It requires additional patches, from inside Nixpkgs that may be hard to maintain later and cause additional debugging time from the maintainer.Steps To Reproduce
Steps to reproduce the behavior:
Create a file
myscript.sh:the file
derivation.nix:the file
default.nix:and run:
Expected behavior
I'd expect to see:
Proposed solution
A solution would be not to add a wrapper replacing the script, but to put the wrapper code directly in the interpreter of the script as I proposed it here:
Result: