@@ -42,6 +42,20 @@ with builtins; with lib;
42
42
description = "Include Windows PATH in WSL PATH" ;
43
43
} ;
44
44
} ;
45
+
46
+ compatibility = {
47
+ interopPreserveArgvZero = mkOption {
48
+ type = nullOr bool ;
49
+ default = null ;
50
+ description = ''
51
+ Register binfmt interpreter for Windows executables with 'preserves argv[0]' flag.
52
+
53
+ Default (null): autodetect, at some performance cost.
54
+ To avoid the performance cost, set this to true for WSL Preview 0.58 and up,
55
+ or to false for older versions (including pre-Microsoft Store).
56
+ '' ;
57
+ } ;
58
+ } ;
45
59
} ;
46
60
47
61
config =
@@ -65,10 +79,35 @@ with builtins; with lib;
65
79
isContainer = true ;
66
80
67
81
binfmt . registrations = mkIf cfg . interop . register {
68
- WSLInterop = {
82
+ WSLInterop = let
83
+ compat = cfg . compatibility . interopPreserveArgvZero ;
84
+
85
+ # WSL Preview 0.58 and up registers the /init binfmt interp for Windows executable
86
+ # with the "preserve argv[0]" flag, so if you run `./foo.exe`, the interp gets invoked
87
+ # as `/init foo.exe ./foo.exe`.
88
+ # argv[0] --^ ^-- actual path
89
+ #
90
+ # Older versions expect to be called without the argv[0] bit, simply as `/init ./foo.exe`.
91
+ #
92
+ # We detect that by running `/init /known-not-existing-path.exe` and checking the exit code:
93
+ # the new style interp expects at least two arguments, so exits with exit code 1,
94
+ # presumably meaning "parsing error"; the old style interp attempts to actually run
95
+ # the executable, fails to find it, and exits with 255.
96
+ compatWrapper = pkgs . writeShellScript "nixos-wsl-binfmt-hack" ''
97
+ /init /nixos-wsl-does-not-exist.exe
98
+ [ $? -eq 255 ] && shift
99
+ exec /init $@
100
+ '' ;
101
+
102
+ # use the autodetect hack if unset, otherwise call /init directly
103
+ interpreter = if compat == null then compatWrapper else "/init" ;
104
+
105
+ # enable for the wrapper and autodetect hack
106
+ preserveArgvZero = if compat == false then false else true ;
107
+ in {
69
108
magicOrExtension = "MZ" ;
70
- interpreter = "/init" ;
71
109
fixBinary = true ;
110
+ inherit interpreter preserveArgvZero ;
72
111
} ;
73
112
} ;
74
113
} ;
0 commit comments