Skip to content

Commit 03772aa

Browse files
committed
pythongh-121103: Put free-threaded libraries in lib/python3.14t
On POSIX systems, excluding macOS framework installs, the lib directory for the free-threaded build now includes a "t" suffix to avoid conflicts with a co-located default build installation.
1 parent 8e8d202 commit 03772aa

File tree

13 files changed

+77
-40
lines changed

13 files changed

+77
-40
lines changed

Lib/site.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ def joinuser(*args):
312312
# Same to sysconfig.get_path('purelib', os.name+'_user')
313313
def _get_path(userbase):
314314
version = sys.version_info
315+
if hasattr(sys, 'abiflags') and 't' in sys.abiflags:
316+
abi_thread = 't'
317+
else:
318+
abi_thread = ''
315319

316320
implementation = _get_implementation()
317321
implementation_lower = implementation.lower()
@@ -322,7 +326,7 @@ def _get_path(userbase):
322326
if sys.platform == 'darwin' and sys._framework:
323327
return f'{userbase}/lib/{implementation_lower}/site-packages'
324328

325-
return f'{userbase}/lib/python{version[0]}.{version[1]}/site-packages'
329+
return f'{userbase}/lib/python{version[0]}.{version[1]}{abi_thread}/site-packages'
326330

327331

328332
def getuserbase():
@@ -390,14 +394,18 @@ def getsitepackages(prefixes=None):
390394

391395
implementation = _get_implementation().lower()
392396
ver = sys.version_info
397+
if hasattr(sys, 'abiflags') and 't' in sys.abiflags:
398+
abi_thread = 't'
399+
else:
400+
abi_thread = ''
393401
if os.sep == '/':
394402
libdirs = [sys.platlibdir]
395403
if sys.platlibdir != "lib":
396404
libdirs.append("lib")
397405

398406
for libdir in libdirs:
399407
path = os.path.join(prefix, libdir,
400-
f"{implementation}{ver[0]}.{ver[1]}",
408+
f"{implementation}{ver[0]}.{ver[1]}{abi_thread}",
401409
"site-packages")
402410
sitepackages.append(path)
403411
else:

Lib/sysconfig/__init__.py

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727

2828
_INSTALL_SCHEMES = {
2929
'posix_prefix': {
30-
'stdlib': '{installed_base}/{platlibdir}/{implementation_lower}{py_version_short}',
31-
'platstdlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}',
32-
'purelib': '{base}/lib/{implementation_lower}{py_version_short}/site-packages',
33-
'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}/site-packages',
30+
'stdlib': '{installed_base}/{platlibdir}/{implementation_lower}{py_version_short_abi}',
31+
'platstdlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short_abi}',
32+
'purelib': '{base}/lib/{implementation_lower}{py_version_short_abi}/site-packages',
33+
'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short_abi}/site-packages',
3434
'include':
3535
'{installed_base}/include/{implementation_lower}{py_version_short}{abiflags}',
3636
'platinclude':
@@ -77,10 +77,10 @@
7777
# Downstream distributors who patch posix_prefix/nt scheme are encouraged to
7878
# leave the following schemes unchanged
7979
'posix_venv': {
80-
'stdlib': '{installed_base}/{platlibdir}/{implementation_lower}{py_version_short}',
81-
'platstdlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}',
82-
'purelib': '{base}/lib/{implementation_lower}{py_version_short}/site-packages',
83-
'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short}/site-packages',
80+
'stdlib': '{installed_base}/{platlibdir}/{implementation_lower}{py_version_short_abi}',
81+
'platstdlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short_abi}',
82+
'purelib': '{base}/lib/{implementation_lower}{py_version_short_abi}/site-packages',
83+
'platlib': '{platbase}/{platlibdir}/{implementation_lower}{py_version_short_abi}/site-packages',
8484
'include':
8585
'{installed_base}/include/{implementation_lower}{py_version_short}{abiflags}',
8686
'platinclude':
@@ -148,11 +148,11 @@ def joinuser(*args):
148148
'data': '{userbase}',
149149
},
150150
'posix_user': {
151-
'stdlib': '{userbase}/{platlibdir}/{implementation_lower}{py_version_short}',
152-
'platstdlib': '{userbase}/{platlibdir}/{implementation_lower}{py_version_short}',
153-
'purelib': '{userbase}/lib/{implementation_lower}{py_version_short}/site-packages',
154-
'platlib': '{userbase}/lib/{implementation_lower}{py_version_short}/site-packages',
155-
'include': '{userbase}/include/{implementation_lower}{py_version_short}',
151+
'stdlib': '{userbase}/{platlibdir}/{implementation_lower}{py_version_short_abi}',
152+
'platstdlib': '{userbase}/{platlibdir}/{implementation_lower}{py_version_short_abi}',
153+
'purelib': '{userbase}/lib/{implementation_lower}{py_version_short_abi}/site-packages',
154+
'platlib': '{userbase}/lib/{implementation_lower}{py_version_short_abi}/site-packages',
155+
'include': '{userbase}/include/{implementation_lower}{py_version_short_abi}',
156156
'scripts': '{userbase}/bin',
157157
'data': '{userbase}',
158158
},
@@ -475,6 +475,8 @@ def _init_config_vars():
475475
_CONFIG_VARS['py_version_nodot_plat'] = sys.winver.replace('.', '')
476476
except AttributeError:
477477
_CONFIG_VARS['py_version_nodot_plat'] = ''
478+
# e.g., 3.14 or 3.14t
479+
_CONFIG_VARS['py_version_short_abi'] = _PY_VERSION_SHORT + _CONFIG_VARS['abiflags'].replace('d', '')
478480

479481
if os.name == 'nt':
480482
_init_non_posix(_CONFIG_VARS)
@@ -655,6 +657,11 @@ def get_python_version():
655657
return _PY_VERSION_SHORT
656658

657659

660+
def _get_python_version_abi():
661+
abi_thread = "t" if _CONFIG_VARS["Py_GIL_DISABLED"] else ""
662+
return _PY_VERSION_SHORT + abi_thread
663+
664+
658665
def expand_makefile_vars(s, vars):
659666
"""Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
660667
'string' according to 'vars' (a dictionary mapping variable names to

Lib/test/test_embed.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@
4848
INIT_LOOPS = 4
4949
MAX_HASH_SEED = 4294967295
5050

51+
ABI_THREAD = 't' if sysconfig.get_config_var('Py_GIL_DISABLED') else ''
52+
5153

5254
# If we are running from a build dir, but the stdlib has been installed,
5355
# some tests need to expect different results.
@@ -1285,11 +1287,11 @@ def module_search_paths(self, prefix=None, exec_prefix=None):
12851287
ver = sys.version_info
12861288
return [
12871289
os.path.join(prefix, sys.platlibdir,
1288-
f'python{ver.major}{ver.minor}.zip'),
1290+
f'python{ver.major}{ver.minor}{ABI_THREAD}.zip'),
12891291
os.path.join(prefix, sys.platlibdir,
1290-
f'python{ver.major}.{ver.minor}'),
1292+
f'python{ver.major}.{ver.minor}{ABI_THREAD}'),
12911293
os.path.join(exec_prefix, sys.platlibdir,
1292-
f'python{ver.major}.{ver.minor}', 'lib-dynload'),
1294+
f'python{ver.major}.{ver.minor}{ABI_THREAD}', 'lib-dynload'),
12931295
]
12941296

12951297
@contextlib.contextmanager
@@ -1343,7 +1345,7 @@ def test_init_setpythonhome(self):
13431345
expected_paths = [paths[0], os.path.join(home, 'DLLs'), stdlib]
13441346
else:
13451347
version = f'{sys.version_info.major}.{sys.version_info.minor}'
1346-
stdlib = os.path.join(home, sys.platlibdir, f'python{version}')
1348+
stdlib = os.path.join(home, sys.platlibdir, f'python{version}{ABI_THREAD}')
13471349
expected_paths = self.module_search_paths(prefix=home, exec_prefix=home)
13481350

13491351
config = {
@@ -1384,7 +1386,7 @@ def test_init_is_python_build_with_home(self):
13841386
expected_paths = [paths[0], os.path.join(home, 'DLLs'), stdlib]
13851387
else:
13861388
version = f'{sys.version_info.major}.{sys.version_info.minor}'
1387-
stdlib = os.path.join(home, sys.platlibdir, f'python{version}')
1389+
stdlib = os.path.join(home, sys.platlibdir, f'python{version}{ABI_THREAD}')
13881390
expected_paths = self.module_search_paths(prefix=home, exec_prefix=home)
13891391

13901392
config = {
@@ -1515,7 +1517,7 @@ def test_init_pyvenv_cfg(self):
15151517
if not MS_WINDOWS:
15161518
lib_dynload = os.path.join(pyvenv_home,
15171519
sys.platlibdir,
1518-
f'python{ver.major}.{ver.minor}',
1520+
f'python{ver.major}.{ver.minor}{ABI_THREAD}',
15191521
'lib-dynload')
15201522
os.makedirs(lib_dynload)
15211523
else:

Lib/test/test_getpath.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,7 @@ def test_explicitly_set_stdlib_dir(self):
844844
PYDEBUGEXT="",
845845
VERSION_MAJOR=9, # fixed version number for ease
846846
VERSION_MINOR=8, # of testing
847+
ABI_THREAD="",
847848
PYWINVER=None,
848849
EXE_SUFFIX=None,
849850

Lib/test/test_site.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,13 @@ def test_getsitepackages(self):
328328
if sys.platlibdir != "lib":
329329
self.assertEqual(len(dirs), 2)
330330
wanted = os.path.join('xoxo', sys.platlibdir,
331-
'python%d.%d' % sys.version_info[:2],
331+
f'python{sysconfig._get_python_version_abi()}',
332332
'site-packages')
333333
self.assertEqual(dirs[0], wanted)
334334
else:
335335
self.assertEqual(len(dirs), 1)
336336
wanted = os.path.join('xoxo', 'lib',
337-
'python%d.%d' % sys.version_info[:2],
337+
f'python{sysconfig._get_python_version_abi()}',
338338
'site-packages')
339339
self.assertEqual(dirs[-1], wanted)
340340
else:

Lib/test/test_sysconfig.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def test_posix_venv_scheme(self):
157157
binpath = 'bin'
158158
incpath = 'include'
159159
libpath = os.path.join('lib',
160-
'python%d.%d' % sys.version_info[:2],
160+
f'python{sysconfig._get_python_version_abi()}',
161161
'site-packages')
162162

163163
# Resolve the paths in an imaginary venv/ directory

Lib/test/test_venv.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def setUp(self):
7575
self.include = 'Include'
7676
else:
7777
self.bindir = 'bin'
78-
self.lib = ('lib', 'python%d.%d' % sys.version_info[:2])
78+
self.lib = ('lib', f'python{sysconfig._get_python_version_abi()}')
7979
self.include = 'include'
8080
executable = sys._base_executable
8181
self.exe = os.path.split(executable)[-1]
@@ -593,7 +593,8 @@ def test_zippath_from_non_installed_posix(self):
593593
libdir = os.path.join(non_installed_dir, platlibdir, self.lib[1])
594594
os.makedirs(libdir)
595595
landmark = os.path.join(libdir, "os.py")
596-
stdlib_zip = "python%d%d.zip" % sys.version_info[:2]
596+
abi_thread = "t" if sysconfig.get_config_var("Py_GIL_DISABLED") else ""
597+
stdlib_zip = f"python{sys.version_info.major}{sys.version_info.minor}{abi_thread}"
597598
zip_landmark = os.path.join(non_installed_dir,
598599
platlibdir,
599600
stdlib_zip)

Makefile.pre.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ AR= @AR@
4141
READELF= @READELF@
4242
SOABI= @SOABI@
4343
ABIFLAGS= @ABIFLAGS@
44+
ABI_THREAD= @ABI_THREAD@
4445
LDVERSION= @LDVERSION@
4546
MODULE_LDFLAGS=@MODULE_LDFLAGS@
4647
GITVERSION= @GITVERSION@
@@ -158,7 +159,7 @@ WHEEL_PKG_DIR= @WHEEL_PKG_DIR@
158159

159160
# Detailed destination directories
160161
BINLIBDEST= @BINLIBDEST@
161-
LIBDEST= $(SCRIPTDIR)/python$(VERSION)
162+
LIBDEST= $(SCRIPTDIR)/python$(VERSION)$(ABI_THREAD)
162163
INCLUDEPY= $(INCLUDEDIR)/python$(LDVERSION)
163164
CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(LDVERSION)
164165

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
On POSIX systems, excluding macOS framework installs, the lib directory
2+
for the free-threaded build now includes a "t" suffix to avoid conflicts
3+
with a co-located default build installation.

Modules/getpath.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -951,6 +951,11 @@ _PyConfig_InitPathConfig(PyConfig *config, int compute_path_config)
951951
!wchar_to_dict(dict, "executable_dir", NULL) ||
952952
!wchar_to_dict(dict, "py_setpath", _PyPathConfig_GetGlobalModuleSearchPath()) ||
953953
!funcs_to_dict(dict, config->pathconfig_warnings) ||
954+
#ifdef Py_GIL_DISABLED
955+
!decode_to_dict(dict, "ABI_THREAD", "t") ||
956+
#else
957+
!decode_to_dict(dict, "ABI_THREAD", "") ||
958+
#endif
954959
#ifndef MS_WINDOWS
955960
PyDict_SetItemString(dict, "winreg", Py_None) < 0 ||
956961
#endif

0 commit comments

Comments
 (0)