The offending code is here which is apparently to have it search the child's %Path% for the binary to fix #15149. It has a few issues though.
Command::new("foo.exe").spawn() and Command::new("foo.exe").env("Thing", "").spawn() uses different rules for finding the binary which seems unexpected..exe. This means Command::new("foo.bar").env("Thing", "").spawn() attempts to launch foo.exe first. Command::new("foo.bar").spawn() correctly tries to launch foo.bar as CreateProcess will not replace the extension.%Path%. For example Command::new(r"C:\foo.bar").env("Thing", "").spawn() looks for C:\foo.exe several times..to_str().unwrap() means it panic!s if the program name is not valid Unicode.std::process::Command).An easy way to fix this is to just remove the hack so we just rely on the behaviour of CreateProcess on Windows which is a least documented. The behaviour is already very different between Windows and Linux and we should probably just accept that in order to get reliable results cross-platform it's best to use absolute paths.
Personally I'd much rather we didn't have this hack and just accepted that Windows and Unix are different and document their differences.
@ollie27 these all sound like bugs to me rather than weird behavior. Removing this behavior is not an option as the are plenty of programs currently relying on this behavior. Would be great to fix the issues, however!
It would definitely be nicer if Command didn't try to be too smart here, but breaking existing usage would also suck. For sccache I contributed to the which crate, which will append an exe extension on Windows if necessary (but not replace an existing extension). One thing that the which crate doesn't implement is support for using the extensions from the PATHEXT environment variable, which on my Windows 10 machine does include .COM. (The Python which package does support this.)
Another issue is that .spawn() assumes that ".exe" is the only extension that Windows' executables have: https://github.com/rust-lang/rust/blob/1.24.0/src/libstd/sys/windows/process.rs#L154
This ignores ".cmd", ".com", etc
Another issue is that .spawn() assumes that ".exe" is the only extension that Windows' executables have
I just found in https://github.com/rust-lang/rust/issues/50870#issuecomment-390309938 that it's consistent with CreateProcess to only try ".exe".
I just found a documentation about how file extensions work in Windows, and it might help since CMD finds the application to open a file with %PATHEXT% using this information (I found this on Stack Overflow answer, but it may be wrong.).
One thing that the
whichcrate doesn't implement is support for using the extensions from thePATHEXTenvironment variable, which on my Windows 10 machine _does_ include.COM.
By the way @luser, after reading through this thread I found that in the interim the which crate has gained support for other extensions through PATHEXT.
Most helpful comment
Another issue is that
.spawn()assumes that ".exe" is the only extension that Windows' executables have: https://github.com/rust-lang/rust/blob/1.24.0/src/libstd/sys/windows/process.rs#L154This ignores ".cmd", ".com", etc