Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interop: enable preserveArgvZero #84

Merged
merged 1 commit into from
Apr 27, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 46 additions & 5 deletions modules/wsl-distro.nix
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ with builtins; with lib;
description = "Include Windows PATH in WSL PATH";
};
};

compatibility = {
interopPreserveArgvZero = mkOption {
type = nullOr bool;
default = null;
description = ''
Register binfmt interpreter for Windows executables with 'preserves argv[0]' flag.

Default (null): autodetect, at some performance cost.
To avoid the performance cost, set this to true for WSL Preview 0.58 and up,
or to false for older versions (including pre-Microsoft Store).
'';
};
};
};

config =
Expand All @@ -65,11 +79,38 @@ with builtins; with lib;
isContainer = true;

binfmt.registrations = mkIf cfg.interop.register {
WSLInterop = {
magicOrExtension = "MZ";
interpreter = "/init";
fixBinary = true;
};
WSLInterop =
let
compat = cfg.compatibility.interopPreserveArgvZero;

# WSL Preview 0.58 and up registers the /init binfmt interp for Windows executable
# with the "preserve argv[0]" flag, so if you run `./foo.exe`, the interp gets invoked
# as `/init foo.exe ./foo.exe`.
# argv[0] --^ ^-- actual path
#
# Older versions expect to be called without the argv[0] bit, simply as `/init ./foo.exe`.
#
# We detect that by running `/init /known-not-existing-path.exe` and checking the exit code:
# the new style interp expects at least two arguments, so exits with exit code 1,
# presumably meaning "parsing error"; the old style interp attempts to actually run
# the executable, fails to find it, and exits with 255.
compatWrapper = pkgs.writeShellScript "nixos-wsl-binfmt-hack" ''
/init /nixos-wsl-does-not-exist.exe
[ $? -eq 255 ] && shift
exec /init $@
'';

# use the autodetect hack if unset, otherwise call /init directly
interpreter = if compat == null then compatWrapper else "/init";

# enable for the wrapper and autodetect hack
preserveArgvZero = if compat == false then false else true;
in
{
magicOrExtension = "MZ";
fixBinary = true;
inherit interpreter preserveArgvZero;
};
};
};
environment.noXlibs = lib.mkForce false; # override xlibs not being installed (due to isContainer) to enable the use of GUI apps
Expand Down