Change:
Put the following as in : This will make interpret the shebang as running . You can also put alongside . This is likely ; you can find it with <subcmd</subor <subpwsh</sub. Alternatively, run with to explicitly select to use the default Python 3 version rather than looking at the shebang. You should also be able to set so will use to run. To debug, set <subpwsh</sub/<subcmd</sub. a shebang line to to allow to work on unixy platforms with but not (the previous shebang line was ). This means that no longer works on Windows machines which run python via the Python Launcher for Windows, as tries to interpret the shebang line (in order to use the correct python version) and ends up instead trying to run , which obviously doesn't exist on a Windows machine. Explicitly asking for a specific version from (e.g. by running for the latest 3.x version) will successfully run the script, as then ignores the shebang line. In theory this is ; should not be trying to run something that isn't python. In practice, though, this is how most Windows users will be launching python, as this is the launcher set up to handle files when installing python from the official installer from the website or  in winget. (The msstore python which the default-installed and shims point to reportedly do not install the launcher.) Additionally, this worked fine previously, and only broke with . reports that didn't work on Windows; I believe this is due to the order of events used in the described testing. first installed the msstore python. They then uninstalled the msstore python and installed the official python distribution, with "add python 3.10 to PATH" unchecked, reporting it to be unchecked by default. However, it was my experience that the official distribution did* add python to the path by default; I suspect that the reason it didn't work for Walther was because (parts of) the msstore python was still in PATH, and the installer did not want to overwrite an existing installation. With my installation, a and shebang both work, and a shebang results in a "Requested Python version (2) is not installed". Changing the shebang to has previously been delayed due to concerns about Windows compatibility. The specific situation seems to be this: When python is handled through the launcher (i.e. the shell uses the registered handler), all python will seamlessly work on Windows. However, when using a MSYS-like shell (e.g. Git Bash) which directly interprets shebangs, it will try to run the program, which most likely does not exist on a Windows machine. (E.g. in my winget install of , I have and in path, but no .)
label C-bug
Since this is also relevant, from the docs: As much as MS would like to push the msstore version of python, the full installer is still generally preferred for developers. (Also, thanks, I used the blank template because I wasn't sure what to use for build tooling.)
label A-rustbuild
While this is being shaken out in (I agree with &mdash; ideally this would be at most a warning, and should interpret the file as if there were no shebang, which I believe already works): Is there a different possible entrypoint with better availability across systems? explains that would look for it inside of "%SystemRoot%System32" or "%SystemRoot%SysWOW64". Perhaps ? do you notice anything promising-looking in those directories that might exist on most platforms in a default installation?
From the discussion on the cpython issue it sounds like this is already fixed in the upcoming Python 3.11's launcher. The release is scheduled for October 2022. We can decide whether to revert our x.py change until October. I am hesitant because it would involve re-breaking the Linux and macOS users, while Linux distributions (since 2020) and macOS upgrades (since October 2021) are deleting .
provides a workaround: can be used to specify that a shebang should instead run {insert executable}. Unfortunately for us at least, is loaded from and the same directory is in (e.g. with a default install), so we can't just drop a next to to fix the behavior of . I'm not 100% sure whether this is considered a feature or a bug in the new launcher at the moment, though, given the comment about not changing the old launcher's behavior, even though they said the no--lookup behavior might make sense in the new launcher... A different alternative would be to change the shebang to in the interim; this was previously rejected as it was thought to break Windows, but in theory it shouldn't[^1]. This would instead break old unixy users who were partially broken by only having available, as well as MSYS users who do not have a available (but imho if you're running a unixy environment, you should probably have , or other things will probably cause issues as well.) [^1]: As I uninstalled the shim to msstore, I can't test to see if would detect and try to launch that instead of an actual python interpreter. will attempt to use msstore-installed python if the full installer python is not available, so it's possible the shim would be selected. Unless exists on unixy systems... probably not. (My system is fairly clean; I did a clean install of Win11 around the start of summer.) <details<summaryA list of maybe-potentially-useful-but-probably-not executables I spotted scrolling through:</summaryYes this list includes pretty obviously non-useful commands. I picked basically anything with even a vaguely not-windows-specific name in System32. - - - - - - - - - - - (note: installer. I don't have WSL installed on this machine yet, otherwise I'd probably have a available) </details
I'm probably missing something obvious (I have basically 0 Python experience), but why can't we just document that Windows users do ? That works both before and after this change.
If you use the installer with the default options then it won't add python to the path. That said, it is just a tick box to select it.
Btw, I feel like I mentioned the failure mode in the OP on the original PR but perhaps I wasn't clear enough.
This change broke existing workflows. Existing contributors aren't looking at documentation, and it seems weird to put the responsibility on them.
I think this is an oversimplification; we regularly put responsibility on existing contributors. If an existing contributor's muscle-memory workflow breaks, most of them will not quit the project over it. They will look somewhere for guidance. The next step in this issue is figuring out where they look for guidance (probably directly in x.py, first), and putting guidance there.
In general, I agree with this point and I'm also frustrated when my workflows are interrupted so I definitely empathize. We should absolutely strive to minimize workflow changes to project contributors! At the same time, it should probably be noted that at no point (from what I can see) have we ever told people to run on Windows-msvc (I have no knowledge of Windows-gnu and never use it), at least in the The file says to run and that line back to the introduction of the Python based build system 6 years ago. Overall it's becoming increasingly clear to me that we need to move away from the current Python based system because of problems like this. had a fantastic idea there and I'm very excited to see that happen! Until that time though, we're very much stuck between a rock and a hard place. The reasons put forth in still seem compelling to me so I would prefer (speaking only for myself, personally) that we try to find a way to make the error message clearer as mentioned rather than reverting.
Here's I think a near-full summary of the Windows behavior as it currently exists: (pwsh; in cmd) works iff an ftype handler has been registered for ; this is the case if the “full installer” was used, or if the msstore python was used and a default “Open With” has been manually set to a python interpreter. With a “full installer” python, and work; and do not. With msstore python, or (as applicable) may work; I tested installing msstore python and did not get a exe in path, but this behavior may be different if the default shim which launches msstore has not been uninstalled.(and if is the ftype registration) attempt to emulate the behavior of , failing with an unhelpful error if is not in path, trying to run . (If a is available, it is run.) , , and work as before. Through , any is documented as launching via ; this applies with any vcommand shebang. Through an MSYS like shell, the shebang is always interpreted and the program is always run like on any other POSIX shell. As such, is the most Windows-portable shebang line. is probably also completely acceptable; imho it is not unreasonable to expect a POSIXy shell environment on Windows to provide as a (soft) alias to (the logic of) . where fails lookup may start to call the default python when launched via with Python 3.11+, and may even skip path lookup entirely. It's impossible to say for sure until it releases whether the current implemented behavior diverging from the existing launcher is desired or will be changed to match it. However, trying to envoke does seem to be considered a bug.
Actually, I first blamed nushell It was only after someone else prompted me that I checked in pwsh and realized the error was not coming from the shell and then went to check and spotted the changed shebang. However, even though the contributing guidelines say to run , using is generally understood as the proper way to launch python on Windows[^1], the same way a unix user might translate documentation suggesting using into or . [^1]: If it weren't intended to be used like this, but only as an ftype handler to enable to work like on POSIX platforms, then it shouldn't have been to PATH. At least to this Windows user, it seems the “more correct” behavior for is to ask for as “some python” and detect and handle getting instead of , or to up front ask for , than it is to ask for and polyglot-relaunch with . I understand the practicality of distros removing and requiring an explicit install, but losing the ability to ask for “ or , I'll handle it” is unfortunate. Then ignoring the bootstrap problem entirely, it'd be nice for at least some directories to “just work” under the system/rustup . If e.g. is required for , but rustup- “just works” for development/testing[^2], then and any weirdness about getting it to run[^3] becomes less important for most uses. [^2]: e.g. by a rustup toolchain toml which asks for the bootstrap compiler to be selected through rustup and sets an undocumented key to enable the behavior style alias for to the installable version of the script would also eliminate the need to use python/ entirely, unless doing a bootstrap build without a preinstalled toolchain. That is still a thing which should be supported, but the less common it is, the greater the allowance we have for requiring slightly nonstandard workflows.
Wouldn't it be easier to just add a separate for Windows? (Or whatever other file extension and script language works out of the box on Windows.)
I believe the possibility of / (on Windows) and (on POSIX) has been discussed a few time before, though search is failing me atm.
In I commented on (there ) to the extent of roughly: To this Windows user, it seems to make more sense to have an than an . with a shebang works for (somewhat less than) everyone, since it's just a regular python file using the python interpreter as its interpreter. The actual broken workflows with a shebang that maybe would've worked before is just any distro with defined but not . Two reminders on that: it will still work if those users use , and transparently does the right thing with any shebang. But why not make work for ~all POSIX systems (iow the ones that would normally expect to work) via the (ba)sh polyglot? Well, if you're providing shell-specific entrypoints anyway (e.g. ), imho it makes sense then to have the sh-specific trampoline in instead of polyglotted at the head of . Maybe that logic doesn't hold, since "anyone" respecting the shebang "should" have (ba)sh available. (Caveat: win32 + exists, thus the discussion at all.) Maybe the greater number of x.py users on unixy platforms than Windows means papering over the split for unixy users is more worthwhile. But it's also worth noting in this comparison the failure modes as well: for Windows + it's ; for unixy + it's (and perhaps some distros will even have a hint to ). The failure mode of on unixy platforms is clear, and likely an error message that a unix user already knows how to interpret the meaning of. The failure mode of on Windows is opaque, and something very few users will have any[^1] intuition for what went wrong. IMHO, this makes it fairly clear that using a shebang (and providing an trampoline) is superior to using a (and providing an trampoline). But as someone on Windows, I'm obviously biased. But also, I've already set up to pretend is , so the choice here has little impact on me; it's more backed by trying to minimize the confusion (and importantly, new developer bounce rate[^2]) of the failure case messaging. [^1]: As a narcissistic example, I'm a reasonably techy Windows user with experience using POSIX systems and tooling. My first reaction was to blame something going wrong in my (admittedly, nonstandard) shell rather than consider that it was somehow the script's fault. [^2]: If anything, I'm additionally worried that this will give Windows users trying to first-time hack on the compiler a "oh, this only builds on unix" impression if they see in an error message, and just leave before looking to see if there's another way to build[^3]. It's not an uncommon thing to deal with for Windows devs that even portable software only really builds properly on unix. Whereas, for better or for worse, linux-on-the-desktop developers are much more likely to see their error message and have the takeaway of "the build system requires ." [^3]: Again, it's not uncommon for when this exists for it to be a poorly maintained blob of Visual Studio build instructions (if you're lucky, an automated translation from the actual build system) which work less well than the real unix build system.
It's worth pointing out here that on Windows with WSL the 'failure mode' for is instead that... it runs, except under WSL ( handles so it finds the launcher, and runs that) which leads to much fun of things mostly working except for sometimes git submodule updates failing and the platform detection defaulting to linux (because, it is running under linux)
That seems like a serious failure mode. I hadn't considered that. (Aside: I find it a bit weird that the python launcher will launch something that isn't python. But it is what it is.)
Being explicit: the behavior is now tracked via a GitHub issue (). The seemingly most likely upstream classification is that The behavior of interpreting shebangs with a non-python executable is undocumented behavior. Changing the behavior of the existing launcher of searching path when given a is likely a nonstarter. It's more than that, even; will use as the interpreter. Classic is kinda a shebang interpreter first. For some recursive fun, set a shebang... Changing the behavior when the path search fails to output a specific error rather than asking the OS to run is reasonable. The new launcher (to be provided with Python 3.11+) can (and currently does) remove the undocumented path search behavior, just using the default python interpreter.
FWIW, as a contributor using Windows, that's what I've always done. I didn't know was even a thing!
same for me, I often work on windows but use cygwin that doesn't have any problem with the change.
Update on upstream: the new launcher has reimplemented the PATH lookup (though in a way that fails much more gracefully when lookup fails) and . If we want to avoid always running under WSL on Windows when launches under WSL, we'll need to do something along the lines of .
A summary of the current situation: changed the shebang from to . For systems without python3 installed, there are new and scripts which will find an appropriate version of python. If you find that none of these options work for you, or the new situation is more inconvenient for you than before, please comment here or open a new issue :)
As a procedural note, this should probably be unpinned in perhaps about a week if nobody reports an issue with the fix/mitigation/direction chosen. Ofc a new issue can always be opened after (or even before) that.

Discussion:
src/test/ui  src/tools/linkchecker <ins> ## MSVC native builders # these intentionally don't use `$(BOOTSTRAP)` so we can test the shebang on Windows </ins> ci-subset-1: <del> $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2:%=--exclude %) </del> <ins> $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 $(TESTS_IN_2:%=--exclude %) </ins> ci-subset-2: <del> $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2) </del> <ins> $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 $(TESTS_IN_2) ## MingW native builders </ins> TESTS_IN_MINGW_2 :=  src/test/ui ci-mingw-subset-1: <del> $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %) </del> <ins> $(Q)$(CFG_SRC_DIR)/x.sh test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %) </ins> ci-mingw-subset-2: $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2)

FROM ubuntu:20.04 ARG DEBIAN_FRONTEND=noninteractive <ins> # NOTE: intentionally installs both python2 and python3 so we can test support for both. </ins> RUN apt-get update && apt-get install -y --no-install-recommends  g++  gcc-multilib 

curl  ca-certificates  python2.7  <ins> python3.9  </ins> git  cmake  sudo 

xz-utils  nodejs <ins> # Install powershell so we can test x.ps1 on Linux RUN apt-get update &&  apt-get install -y apt-transport-https software-properties-common &&  curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb &&  dpkg -i packages-microsoft-prod.deb &&  apt-get update &&  apt-get install -y powershell </ins> COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh

--enable-llvm-link-shared  --set rust.thin-lto-import-instr-limit=10 <del> ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy &&  </del> <ins> # NOTE: intentionally uses all of `x.py`, `x.sh`, and `x.ps1` to make sure they all work on Linux. ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy &&  </ins> # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have # both 32-bit and 64-bit outputs updated by the PR author, before # the PR is approved and tested for merging. # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, # despite having different output on 32-bit vs 64-bit targets. <del> python2.7 ../x.py --stage 2 test src/test/mir-opt  </del> <ins> ../x.sh --stage 2 test src/test/mir-opt  </ins> --host='' --target=i686-unknown-linux-gnu &&  # Run the UI test suite again, but in `--pass=check` mode # # This is intended to make sure that both `--pass=check` continues to # work. # <del> python2.7 ../x.py --stage 2 test src/test/ui --pass=check  </del> <ins> ../x.ps1 --stage 2 test src/test/ui --pass=check  </ins> --host='' --target=i686-unknown-linux-gnu &&  # Run tidy at the very end, after all the other tests. python2.7 ../x.py --stage 2 test src/tools/tidy

#[cfg(unix)] pub fn check(path: &Path, bad: &mut bool) { <ins> use std::ffi::OsStr; </ins> const ALLOWED: &[&str] = &["configure"]; crate::walk_no_read(

}, &mut |entry| { let file = entry.path(); <del> let filename = file.file_name().unwrap().to_string_lossy(); let extensions = [".py", ".sh"]; if extensions.iter().any(|e| filename.ends_with(e)) { </del> <ins> let extension = file.extension(); let scripts = ["py", "sh", "ps1"]; if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) { </ins> return; }

<ins> #!/usr/bin/env pwsh # See x.sh for why these scripts exist. $xpy = Join-Path $PSScriptRoot x.py # Start-Process for some reason splits arguments on spaces. (Isn't powershell supposed to be simpler than bash?) # Double-quote all the arguments so it doesn't do that. $xpy_args = @("""$xpy""") foreach ($arg in $args) { $xpy_args += """$arg""" } foreach ($python in "py", "python3", "python", "python2") { # NOTE: this only tests that the command exists in PATH, not that it's actually # executable. The latter is not possible in a portable way, see # https://github.com/PowerShell/PowerShell/issues/12625. if (Get-Command $python -ErrorAction SilentlyContinue) { if ($python -eq "py") { # Use python3, not python2 $xpy_args = @("-3") + $xpy_args } $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args Exit $process.ExitCode } } Write-Error "${PSCommandPath}: error: did not find python installed" Exit 1 </ins>

<del> #!/usr/bin/env bash </del> <ins> #!/usr/bin/env python3 # Some systems don't have `python3` in their PATH. This isn't supported by x.py directly; # they should use `x.sh` or `x.ps1` instead. </ins> <del> # Modern Linux and macOS systems commonly only have a thing called `python3` and # not `python`, while Windows commonly does not have `python3`, so we cannot # directly use python in the shebang and have it consistently work. Instead we # embed some bash to look for a python to run the rest of the script. # # On Windows, `py -3` sometimes works. We need to try it first because `python3` # sometimes tries to launch the app store on Windows. '''': for PYTHON in "py -3" python3 python python2; do if command -v $PYTHON >/dev/null; then exec $PYTHON "$0" "$@" break fi done echo "$0: error: did not find python installed" >&2 exit 1 ''' # The rest of this file is Python. # </del> # This file is only a "symlink" to bootstrap.py, all logic should go there. import os import sys # If this is python2, check if python3 is available and re-execute with that <del> # interpreter. </del> <ins> # interpreter. Only python3 allows downloading CI LLVM. </ins> # <del> # `./x.py` would not normally benefit from this because the bash above tries # python3 before 2, but this matters if someone ran `python x.py` and their # system's `python` is python2. </del> <ins> # This matters if someone's system `python` is python2. </ins> if sys.version_info.major < 3: try: os.execvp("py", ["py", "-3"] + sys.argv)

<ins> #!/bin/sh # Modern Linux and macOS systems commonly only have a thing called `python3` and # not `python`, while Windows commonly does not have `python3`, so we cannot # directly use python in the x.py shebang and have it consistently work. Instead we # have a shell script to look for a python to run x.py. set -eu realpath() { if [ -d "$1" ]; then CDPATH='' command cd "$1" && pwd -P else echo "$(realpath "$(dirname "$1")")/$(basename "$1")" fi } xpy=$(dirname "$(realpath "$0")")/x.py # On Windows, `py -3` sometimes works. We need to try it first because `python3` # sometimes tries to launch the app store on Windows. for SEARCH_PYTHON in py python3 python python2; do if python=$(command -v $SEARCH_PYTHON) && [ -x "$python" ]; then if [ $SEARCH_PYTHON = py ]; then extra_arg="-3" else extra_arg="" fi exec "$python" $extra_arg "$xpy" "$@" fi done echo "$0: error: did not find python installed" >&2 exit 1 </ins>