Code change:
pub fn get_linker(sess: &Session) -> (String, Command, Vec<(OsString, OsString)>) { let envs = vec![("PATH".into(), command_path(sess))]; <ins> // If our linker looks like a batch script on Windows then to execute this // we'll need to spawn `cmd` explicitly. This is primarily done to handle // emscripten where the linker is `emcc.bat` and needs to be spawned as // `cmd /c emcc.bat ...`. // // This worked historically but is needed manually since #42436 (regression // was tagged as #42791) and some more info can be found on #44443 for // emscripten itself. let cmd = |linker: &str| { if cfg!(windows) && linker.ends_with(".bat") { let mut cmd = Command::new("cmd"); cmd.arg("/c").arg(linker); cmd } else { Command::new(linker) } }; </ins> if let Some(ref linker) = sess.opts.cg.linker { <del> (linker.clone(), Command::new(linker), envs) </del> <ins> (linker.clone(), cmd(linker), envs) </ins> } else if sess.target.target.options.is_like_msvc { let (cmd, envs) = msvc_link_exe_cmd(sess); ("link.exe".to_string(), cmd, envs) } else { let linker = &sess.target.target.options.linker; <del> (linker.clone(), Command::new(&linker), envs) </del> <ins> (linker.clone(), cmd(linker), envs) </ins> } }

Related discussion:
text: Also I have a big problem with accepting a "wont fix" on a regression with an explanation such as "this was always a mistake and we should have never allowed it". I understand API stability not only as a "compilability" but also behavioral contract. Please note that (possibly most) stdlib users might consider not being able to run bat files directly a serious drawback (not found in other mainstream languages).
Hmm this still came out stronger than intended . Please note that as a pragmatic programmer I'll test and implement the suggested workaround (thanks for the help with that!) previous comments were a well intended suggestions from someone concerned about rust and its success on the crowded programming language market. Please keep at the good work!:heart:
If you want something that is capable of running any executable script, what you really want is a wrapper around and not . In order to spawn a child process, Rust has to use either or . Rust decided to use which means it is fundamentally limited in the sort of behavior it can support by what does. In order to paper over differences in behavior between platforms Rust has to do a lot of its own work, such as searching in itself if you modify the of the to emulate posix semantics and that's already given rise to a bunch of bugs (). When Rust goes too far in providing cross platform behavior it ends up causing bugs like Some things simply do not work when you try to make the behavior the same across platforms Rust cannot completely unify the behavior across platforms. At some point Rust has to draw a line for where the platforms have different behavior and document it accordingly. fixes an issue which could result in a security hole. You could attempt to run but if it doesn't exist it might end up running a completely different binary named . It would be great if we could provide complete stability in behavior, but when fixing bugs there will inevitably be some corner case that is broken. It's unfortunate that quoting the binary name causes to no longer work but fortunately there is a clear way to change your code such that it reliably works across all Rust versions. I really wish we could let support binary paths longer than but a lot of people already rely on being able to directly execute bat scripts, far more than those that relied on , so I don't think we'll ever be able to fix this bug.