Skip to content

Commit 10f950c

Browse files
zoobaencukou
andauthored
gh-148690: Build Windows freethreaded binaries into separate directory and include python3t.dll on GIL-enabled (GH-149218)
Co-authored-by: Petr Viktorin <encukou@gmail.com>
1 parent 9846407 commit 10f950c

32 files changed

Lines changed: 488 additions & 78 deletions

Include/pyabi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
*
5656
* (Don't use Py_TARGET_ABI3T directly. It's currently only used to set these
5757
* 2 macros, and defined for users' convenience.)
58+
*
59+
* This logic is currently partially duplicated in PC/pyconfig.h.
5860
*/
5961
#if defined(Py_LIMITED_API) && defined(Py_GIL_DISABLED) \
6062
&& !defined(Py_TARGET_ABI3T)

Lib/test/test_cext/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import shlex
99
import shutil
1010
import subprocess
11+
import sysconfig
12+
import sys
1113
import unittest
1214
from test import support
1315

@@ -62,6 +64,9 @@ def run_cmd(operation, cmd):
6264
env['CPYTHON_TEST_LIMITED'] = '1'
6365
if abi3t:
6466
env['CPYTHON_TEST_ABI3T'] = '1'
67+
if support.MS_WINDOWS and sysconfig.is_python_build():
68+
env['CPYTHON_EXTRA_INCDIRS'] = os.path.split(sysconfig.get_config_h_filename())[0]
69+
env['CPYTHON_EXTRA_LIBDIRS'] = os.path.split(sys.executable)[0]
6570
env['CPYTHON_TEST_EXT_NAME'] = extension_name
6671
env['TEST_INTERNAL_C_API'] = str(int(self.TEST_INTERNAL_C_API))
6772
if support.verbose:

Lib/test/test_cext/setup.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# gh-91321: Build a basic C test extension to check that the Python C API is
22
# compatible with C and does not emit C compiler warnings.
33
import os
4-
import platform
54
import shlex
65
import sys
76
import sysconfig
@@ -66,6 +65,8 @@ def main():
6665
limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", ""))
6766
abi3t = bool(os.environ.get("CPYTHON_TEST_ABI3T", ""))
6867
internal = bool(int(os.environ.get("TEST_INTERNAL_C_API", "0")))
68+
incdirs = os.environ.get("CPYTHON_EXTRA_INCDIRS", "")
69+
libdirs = os.environ.get("CPYTHON_EXTRA_LIBDIRS", "")
6970

7071
sources = [SOURCE]
7172

@@ -106,19 +107,16 @@ def main():
106107
if internal:
107108
cflags.append('-DTEST_INTERNAL_C_API=1')
108109

109-
# On Windows, add PCbuild\amd64\ to include and library directories
110+
# Add additional include and library directories, typically for in-tree
111+
# testing where not all directories are inferred
110112
include_dirs = []
111113
library_dirs = []
112-
if support.MS_WINDOWS:
113-
srcdir = sysconfig.get_config_var('srcdir')
114-
machine = platform.uname().machine
115-
pcbuild = os.path.join(srcdir, 'PCbuild', machine)
116-
if os.path.exists(pcbuild):
117-
# pyconfig.h is generated in PCbuild\amd64\
118-
include_dirs.append(pcbuild)
119-
# python313.lib is generated in PCbuild\amd64\
120-
library_dirs.append(pcbuild)
121-
print(f"Add PCbuild directory: {pcbuild}")
114+
if incdirs:
115+
print("Add incdirs:", incdirs)
116+
include_dirs.extend(incdirs.split(os.pathsep))
117+
if libdirs:
118+
print("Add libdirs:", libdirs)
119+
library_dirs.extend(libdirs.split(os.pathsep))
122120

123121
# Display information to help debugging
124122
for env_name in ('CC', 'CFLAGS', 'CPPFLAGS'):

Lib/test/test_cppext/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import shutil
77
import subprocess
88
import sys
9+
import sysconfig
910
import unittest
1011
from test import support
1112

@@ -50,6 +51,9 @@ def run_cmd(operation, cmd):
5051
env['CPYTHON_TEST_CPP_STD'] = std
5152
if limited:
5253
env['CPYTHON_TEST_LIMITED'] = '1'
54+
if support.MS_WINDOWS and sysconfig.is_python_build():
55+
env['CPYTHON_EXTRA_INCDIRS'] = os.path.split(sysconfig.get_config_h_filename())[0]
56+
env['CPYTHON_EXTRA_LIBDIRS'] = os.path.split(sys.executable)[0]
5357
env['CPYTHON_TEST_EXT_NAME'] = extension_name
5458
env['TEST_INTERNAL_C_API'] = str(int(self.TEST_INTERNAL_C_API))
5559
if extra_cflags:

Lib/test/test_cppext/setup.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# gh-91321: Build a basic C++ test extension to check that the Python C API is
22
# compatible with C++ and does not emit C++ compiler warnings.
33
import os
4-
import platform
54
import shlex
65
import sys
76
import sysconfig
@@ -48,6 +47,8 @@ def main():
4847
module_name = os.environ["CPYTHON_TEST_EXT_NAME"]
4948
limited = bool(os.environ.get("CPYTHON_TEST_LIMITED", ""))
5049
internal = bool(int(os.environ.get("TEST_INTERNAL_C_API", "0")))
50+
incdirs = os.environ.get("CPYTHON_EXTRA_INCDIRS", "")
51+
libdirs = os.environ.get("CPYTHON_EXTRA_LIBDIRS", "")
5152

5253
cppflags = list(CPPFLAGS)
5354
cppflags.append(f'-DMODULE_NAME={module_name}')
@@ -90,19 +91,16 @@ def main():
9091
if extra_cflags:
9192
cppflags.extend(shlex.split(extra_cflags))
9293

93-
# On Windows, add PCbuild\amd64\ to include and library directories
94+
# Add additional include and library directories, typically for in-tree
95+
# testing where not all directories are inferred
9496
include_dirs = []
9597
library_dirs = []
96-
if support.MS_WINDOWS:
97-
srcdir = sysconfig.get_config_var('srcdir')
98-
machine = platform.uname().machine
99-
pcbuild = os.path.join(srcdir, 'PCbuild', machine)
100-
if os.path.exists(pcbuild):
101-
# pyconfig.h is generated in PCbuild\amd64\
102-
include_dirs.append(pcbuild)
103-
# python313.lib is generated in PCbuild\amd64\
104-
library_dirs.append(pcbuild)
105-
print(f"Add PCbuild directory: {pcbuild}")
98+
if incdirs:
99+
print("Add incdirs:", incdirs)
100+
include_dirs.extend(incdirs.split(os.pathsep))
101+
if libdirs:
102+
print("Add libdirs:", libdirs)
103+
library_dirs.extend(libdirs.split(os.pathsep))
106104

107105
# Display information to help debugging
108106
for env_name in ('CC', 'CXX', 'CFLAGS', 'CPPFLAGS', 'CXXFLAGS'):

Lib/venv/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,9 @@ def setup_python(self, context):
358358
exe_t = f'3.{sys.version_info[1]}t'
359359
python_exe = os.path.join(dirname, f'python{exe_t}{exe_d}.exe')
360360
pythonw_exe = os.path.join(dirname, f'pythonw{exe_t}{exe_d}.exe')
361+
if not os.path.isfile(python_exe):
362+
python_exe = os.path.join(dirname, f'python{exe_d}.exe')
363+
pythonw_exe = os.path.join(dirname, f'pythonw{exe_d}.exe')
361364
link_sources = {
362365
'python.exe': python_exe,
363366
f'python{exe_d}.exe': python_exe,
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Windows free-threaded builds now output to a different default path with
2+
default filenames, for example, ``PCbuild/amd64t/python.exe`` rather than
3+
``PCbuild/amd64/python3.15t.exe``. The ``PC/layout`` script has been updated
4+
to ensure compatibility of generated layouts.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Non-freethreaded builds on Windows now support extensions linked to
2+
``python3t.dll``, and will include a copy of that library in normal installs
3+
that references the non-freethreaded runtime.

PC/layout/main.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,10 @@ def get_tcltk_lib(ns):
127127
def get_layout(ns):
128128
def in_build(f, dest="", new_name=None, no_lib=False):
129129
n, _, x = f.rpartition(".")
130-
n = new_name or n
130+
if new_name and new_name.endswith(f".{x}"):
131+
n = new_name.rpartition(".")[0]
132+
else:
133+
n = new_name or n
131134
src = ns.build / f
132135
if ns.debug and src not in REQUIRED_DLLS:
133136
if not "_d." in src.name:
@@ -161,11 +164,12 @@ def in_build(f, dest="", new_name=None, no_lib=False):
161164
source = "python_uwp.exe"
162165
sourcew = "pythonw_uwp.exe"
163166
elif ns.include_freethreaded:
164-
source = "python{}t.exe".format(VER_DOT)
165-
sourcew = "pythonw{}t.exe".format(VER_DOT)
166167
if not ns.include_alias:
167168
alias = []
168169
aliasw = []
170+
if (VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4) < (3, 15, 0, 0xB0):
171+
source = "python{}t.exe".format(VER_DOT)
172+
sourcew = "pythonw{}t.exe".format(VER_DOT)
169173
alias.extend([
170174
"python{}t".format(VER_DOT),
171175
"python{}t".format(VER_MAJOR) if ns.include_alias3 else None,
@@ -196,6 +200,8 @@ def in_build(f, dest="", new_name=None, no_lib=False):
196200
yield from in_build(FREETHREADED_PYTHON_STABLE_DLL_NAME)
197201
else:
198202
yield from in_build(PYTHON_STABLE_DLL_NAME)
203+
if (VER_MAJOR, VER_MINOR, VER_MICRO, VER_FIELD4) >= (3, 15, 0, 0xB0):
204+
yield from in_build(FREETHREADED_PYTHON_STABLE_DLL_NAME)
199205

200206
found_any = False
201207
for dest, src in rglob(ns.build, "vcruntime*.dll"):

PC/pyconfig.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,14 +331,16 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */
331331
# if defined(Py_GIL_DISABLED)
332332
# if defined(Py_DEBUG)
333333
# pragma comment(lib,"python315t_d.lib")
334-
# elif defined(Py_LIMITED_API)
334+
# elif defined(Py_LIMITED_API) || defined(Py_TARGET_ABI3T)
335335
# pragma comment(lib,"python3t.lib")
336336
# else
337337
# pragma comment(lib,"python315t.lib")
338338
# endif /* Py_DEBUG */
339339
# else /* Py_GIL_DISABLED */
340340
# if defined(Py_DEBUG)
341341
# pragma comment(lib,"python315_d.lib")
342+
# elif defined(Py_TARGET_ABI3T)
343+
# pragma comment(lib,"python3t.lib")
342344
# elif defined(Py_LIMITED_API)
343345
# pragma comment(lib,"python3.lib")
344346
# else

0 commit comments

Comments
 (0)