https://github.com/python/cpython/commit/1c5fe21eb2a65190c04bb3f4c0931d76f5ccf415
commit: 1c5fe21eb2a65190c04bb3f4c0931d76f5ccf415
branch: main
author: Steve Dower <[email protected]>
committer: zooba <[email protected]>
date: 2026-05-15T14:43:41+01:00
summary:
gh-149786: Fixes venvlauncher builds on Windows free-threaded (GH-149847)
files:
A Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst
M Lib/test/test_venv.py
M PC/layout/support/options.py
M PC/layout/support/pymanager.py
M PCbuild/python.vcxproj
M PCbuild/pythonw.vcxproj
M PCbuild/venvlauncher.vcxproj
M PCbuild/venvwlauncher.vcxproj
diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py
index a42787f261bfe8..9d2960664abfad 100644
--- a/Lib/test/test_venv.py
+++ b/Lib/test/test_venv.py
@@ -301,9 +301,9 @@ def test_sysconfig(self):
self.assertEqual(out.strip(), expected, err)
for attr, expected in (
('executable', self.envpy()),
- # Usually compare to sys.executable, but if we're running in our
own
- # venv then we really need to compare to our base executable
- ('_base_executable', sys._base_executable),
+ # Usually compare to sys.prefix, but if we're running in our own
+ # venv then we really need to compare to our base prefix
+ ('base_prefix', sys.base_prefix),
):
with self.subTest(attr):
cmd[2] = f'import sys; print(sys.{attr})'
@@ -916,10 +916,10 @@ def test_venvwlauncher(self):
exename = exename.replace("python", "pythonw")
envpyw = os.path.join(self.env_dir, self.bindir, exename)
try:
- subprocess.check_call([envpyw, "-c", "import sys; "
- "assert sys._base_executable.endswith('%s')" % exename])
+ subprocess.check_call([envpyw, "-c", "import fnmatch, sys; "
+ "assert fnmatch.fnmatch(sys._base_executable,
'**/pythonw*.exe')"])
except subprocess.CalledProcessError:
- self.fail("venvwlauncher.exe did not run %s" % exename)
+ self.fail("venvwlauncher.exe did not run pythonw.exe")
@requireVenvCreate
diff --git
a/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst
b/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst
new file mode 100644
index 00000000000000..64ca91a01f41af
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2026-05-14-22-09-46.gh-issue-149786.UI-HZM.rst
@@ -0,0 +1 @@
+Fixes virtual environment launchers on Windows free-threaded builds.
diff --git a/PC/layout/support/options.py b/PC/layout/support/options.py
index 3a6e00f720f01f..f67d8ba04d9070 100644
--- a/PC/layout/support/options.py
+++ b/PC/layout/support/options.py
@@ -112,6 +112,7 @@ def public(f):
"venv",
"dev",
"html-doc",
+ "alias",
"install-json",
"builddetails-json",
],
@@ -128,6 +129,7 @@ def public(f):
"html-doc",
"symbols",
"tests",
+ "alias",
"install-test-json",
"builddetails-json",
],
diff --git a/PC/layout/support/pymanager.py b/PC/layout/support/pymanager.py
index 831d49ea3f9b46..f6316e0295c74a 100644
--- a/PC/layout/support/pymanager.py
+++ b/PC/layout/support/pymanager.py
@@ -66,8 +66,9 @@ def calculate_install_json(ns, *, for_embed=False,
for_test=False):
if ns.include_freethreaded:
# Free-threaded distro comes with a tag suffix
TAG_SUFFIX = "t"
- TARGET = f"python{VER_MAJOR}.{VER_MINOR}t.exe"
- TARGETW = f"pythonw{VER_MAJOR}.{VER_MINOR}t.exe"
+ if not ns.include_alias:
+ TARGET = f"python{VER_MAJOR}.{VER_MINOR}t.exe"
+ TARGETW = f"pythonw{VER_MAJOR}.{VER_MINOR}t.exe"
DISPLAY_TAGS.append("free-threaded")
FILE_SUFFIX = f"t-{ns.arch}"
diff --git a/PCbuild/python.vcxproj b/PCbuild/python.vcxproj
index 70dabaa3c8bc02..417ede34c54af3 100644
--- a/PCbuild/python.vcxproj
+++ b/PCbuild/python.vcxproj
@@ -135,6 +135,14 @@
set PYTHONPATH=$(PySourcePath)Lib
"$(OutDir)$(PyExeName)$(PyDebugExt).exe"
"$(PySourcePath)PC\validate_ucrtbase.py" $(UcrtName)' ContinueOnError="true" />
</Target>
+ <Target Name="CopyFreethreadedBinary" AfterTargets="AfterBuild"
+ Condition="$(DisableGil) == 'true' and $(Configuration) !=
'PGInstrument'">
+ <Message Text="Duplicating $(TargetPath) to
$(PyExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe for
free-threaded compatibility" />
+ <Copy SourceFiles="$(TargetPath)"
+
DestinationFiles="$(OutDir)\$(PyExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe"
+ SkipUnchangedFiles="true"
+ UseHardLinksIfPossible="true" />
+ </Target>
<Target Name="GeneratePythonBat" AfterTargets="AfterBuild">
<PropertyGroup>
<_Content>@rem This script invokes the most recently built Python with
all arguments
diff --git a/PCbuild/pythonw.vcxproj b/PCbuild/pythonw.vcxproj
index c6a5b8ce90a0d9..244cdf622ad915 100644
--- a/PCbuild/pythonw.vcxproj
+++ b/PCbuild/pythonw.vcxproj
@@ -115,4 +115,12 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
+ <Target Name="CopyFreethreadedBinary" AfterTargets="AfterBuild"
+ Condition="$(DisableGil) == 'true' and $(Configuration) !=
'PGInstrument'">
+ <Message Text="Duplicating $(TargetPath) to
$(PyWExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe for
free-threaded compatibility" />
+ <Copy SourceFiles="$(TargetPath)"
+
DestinationFiles="$(OutDir)\$(PyWExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe"
+ SkipUnchangedFiles="true"
+ UseHardLinksIfPossible="true" />
+ </Target>
</Project>
\ No newline at end of file
diff --git a/PCbuild/venvlauncher.vcxproj b/PCbuild/venvlauncher.vcxproj
index abaf3a979af268..a2e8ffa82b10eb 100644
--- a/PCbuild/venvlauncher.vcxproj
+++ b/PCbuild/venvlauncher.vcxproj
@@ -89,10 +89,13 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"
Label="LocalAppDataPlatform" />
<Import Project="pyproject.props" />
</ImportGroup>
- <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Label="UserMacros">
+ <ExeName>$(PyExeName)$(PyDebugExt).exe</ExeName>
+ <ExeName Condition="$(DisableGil) ==
'true'">$(PyExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe</ExeName>
+ </PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
-
<PreprocessorDefinitions>EXENAME=L"$(PyExeName)$(PyDebugExt).exe";_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+
<PreprocessorDefinitions>EXENAME=L"$(ExeName)";_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<ResourceCompile>
diff --git a/PCbuild/venvwlauncher.vcxproj b/PCbuild/venvwlauncher.vcxproj
index c58280deb8abeb..f2aaf83fe2b378 100644
--- a/PCbuild/venvwlauncher.vcxproj
+++ b/PCbuild/venvwlauncher.vcxproj
@@ -89,10 +89,13 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"
Label="LocalAppDataPlatform" />
<Import Project="pyproject.props" />
</ImportGroup>
- <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Label="UserMacros">
+ <ExeName>$(PyWExeName)$(PyDebugExt).exe</ExeName>
+ <ExeName Condition="$(DisableGil) ==
'true'">$(PyWExeName)$(MajorVersionNumber).$(MinorVersionNumber)t$(PyDebugExt).exe</ExeName>
+ </PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
-
<PreprocessorDefinitions>EXENAME=L"$(PyWExeName)$(PyDebugExt).exe";_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+
<PreprocessorDefinitions>EXENAME=L"$(ExeName)";_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
</ClCompile>
<ResourceCompile>
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]