Skip to content

Commit 8510f43

Browse files
vstinnerJan Matějekmceplstratakis
authored
bpo-1294959: Add sys.platlibdir attribute (GH-18381)
Add --with-platlibdir option to the configure script: name of the platform-specific library directory, stored in the new sys.platlitdir attribute. It is used to build the path of platform-specific dynamic libraries and the path of the standard library. It is equal to "lib" on most platforms. On Fedora and SuSE, it is equal to "lib64" on 64-bit systems. Co-Authored-By: Jan Matějek <jmatejek@suse.com> Co-Authored-By: Matěj Cepl <mcepl@cepl.eu> Co-Authored-By: Charalampos Stratakis <cstratak@redhat.com>
1 parent 700cb58 commit 8510f43

File tree

16 files changed

+209
-53
lines changed

16 files changed

+209
-53
lines changed

Doc/library/sys.rst

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,27 @@ always available.
11381138
system's identity.
11391139

11401140

1141+
.. data:: platlibdir
1142+
1143+
Name of the platform-specific library directory. It is used to build the
1144+
path of platform-specific dynamic libraries and the path of the standard
1145+
library.
1146+
1147+
It is equal to ``"lib"`` on most platforms. On Fedora and SuSE, it is equal
1148+
to ``"lib64"`` on 64-bit platforms which gives the following ``sys.path``
1149+
paths (where ``X.Y`` is the Python ``major.minor`` version):
1150+
1151+
* ``/usr/lib64/pythonX.Y/``:
1152+
Standard library (like ``os.py`` of the :mod:`os` module)
1153+
* ``/usr/lib64/pythonX.Y/lib-dynload/``:
1154+
C extension modules of the standard library (like the :mod:`errno` module,
1155+
the exact filename is platform specific)
1156+
* ``/usr/lib/pythonX.Y/site-packages`` (always use ``lib``, not
1157+
:data:`sys.platlibdir`): Third-party modules
1158+
1159+
.. versionadded:: 3.9
1160+
1161+
11411162
.. data:: prefix
11421163

11431164
A string giving the site-specific directory prefix where the platform

Doc/whatsnew/3.9.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,17 @@ finalization crashed with a Python fatal error if a daemon thread was still
353353
running.
354354
(Contributed by Victor Stinner in :issue:`37266`.)
355355

356+
sys
357+
---
358+
359+
Add a new :attr:`sys.platlitdir` attribute: name of the platform-specific
360+
library directory. It is used to build the path of platform-specific dynamic
361+
libraries and the path of the standard library. It is equal to ``"lib"`` on
362+
most platforms. On Fedora and SuSE, it is equal to ``"lib64"`` on 64-bit
363+
platforms.
364+
(Contributed by Jan Matějek, Matěj Cepl, Charalampos Stratakis and Victor Stinner in :issue:`1294959`.)
365+
366+
356367
typing
357368
------
358369

@@ -390,6 +401,11 @@ Optimizations
390401
Build and C API Changes
391402
=======================
392403

404+
* Add ``--with-platlibdir`` option to the ``configure`` script: name of the
405+
platform-specific library directory, stored in the new :attr:`sys.platlitdir`
406+
attribute. See :attr:`sys.platlibdir` attribute for more information.
407+
(Contributed by Jan Matějek, Matěj Cepl, Charalampos Stratakis and Victor Stinner in :issue:`1294959`.)
408+
393409
* Add a new public :c:func:`PyObject_CallNoArgs` function to the C API, which
394410
calls a callable Python object without any arguments. It is the most efficient
395411
way to call a callable Python object without any argument.

Lib/distutils/command/install.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@
3030
INSTALL_SCHEMES = {
3131
'unix_prefix': {
3232
'purelib': '$base/lib/python$py_version_short/site-packages',
33-
'platlib': '$platbase/lib/python$py_version_short/site-packages',
33+
'platlib': '$platbase/$platlibdir/python$py_version_short/site-packages',
3434
'headers': '$base/include/python$py_version_short$abiflags/$dist_name',
3535
'scripts': '$base/bin',
3636
'data' : '$base',
3737
},
3838
'unix_home': {
3939
'purelib': '$base/lib/python',
40-
'platlib': '$base/lib/python',
40+
'platlib': '$base/$platlibdir/python',
4141
'headers': '$base/include/python/$dist_name',
4242
'scripts': '$base/bin',
4343
'data' : '$base',
@@ -298,6 +298,7 @@ def finalize_options(self):
298298
'sys_exec_prefix': exec_prefix,
299299
'exec_prefix': exec_prefix,
300300
'abiflags': abiflags,
301+
'platlibdir': sys.platlibdir,
301302
}
302303

303304
if HAS_USER_SITE:

Lib/distutils/sysconfig.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,15 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
146146
prefix = plat_specific and EXEC_PREFIX or PREFIX
147147

148148
if os.name == "posix":
149-
libpython = os.path.join(prefix,
150-
"lib", "python" + get_python_version())
149+
if plat_specific or standard_lib:
150+
# Platform-specific modules (any module from a non-pure-Python
151+
# module distribution) or standard Python library modules.
152+
libdir = sys.platlibdir
153+
else:
154+
# Pure Python
155+
libdir = "lib"
156+
libpython = os.path.join(prefix, libdir,
157+
"python" + get_python_version())
151158
if standard_lib:
152159
return libpython
153160
else:

Lib/distutils/tests/test_install.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ def check_path(got, expected):
5858

5959
libdir = os.path.join(destination, "lib", "python")
6060
check_path(cmd.install_lib, libdir)
61-
check_path(cmd.install_platlib, libdir)
61+
platlibdir = os.path.join(destination, sys.platlibdir, "python")
62+
check_path(cmd.install_platlib, platlibdir)
6263
check_path(cmd.install_purelib, libdir)
6364
check_path(cmd.install_headers,
6465
os.path.join(destination, "include", "python", "foopkg"))

Lib/site.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,13 +334,22 @@ def getsitepackages(prefixes=None):
334334
continue
335335
seen.add(prefix)
336336

337+
libdirs = [sys.platlibdir]
338+
if sys.platlibdir != "lib":
339+
libdirs.append("lib")
340+
337341
if os.sep == '/':
338-
sitepackages.append(os.path.join(prefix, "lib",
339-
"python%d.%d" % sys.version_info[:2],
340-
"site-packages"))
342+
for libdir in libdirs:
343+
path = os.path.join(prefix, libdir,
344+
"python%d.%d" % sys.version_info[:2],
345+
"site-packages")
346+
sitepackages.append(path)
341347
else:
342348
sitepackages.append(prefix)
343-
sitepackages.append(os.path.join(prefix, "lib", "site-packages"))
349+
350+
for libdir in libdirs:
351+
path = os.path.join(prefix, libdir, "site-packages")
352+
sitepackages.append(path)
344353
return sitepackages
345354

346355
def addsitepackages(known_paths, prefixes=None):

Lib/sysconfig.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020

2121
_INSTALL_SCHEMES = {
2222
'posix_prefix': {
23-
'stdlib': '{installed_base}/lib/python{py_version_short}',
24-
'platstdlib': '{platbase}/lib/python{py_version_short}',
23+
'stdlib': '{installed_base}/{platlibdir}/python{py_version_short}',
24+
'platstdlib': '{platbase}/{platlibdir}/python{py_version_short}',
2525
'purelib': '{base}/lib/python{py_version_short}/site-packages',
26-
'platlib': '{platbase}/lib/python{py_version_short}/site-packages',
26+
'platlib': '{platbase}/{platlibdir}/python{py_version_short}/site-packages',
2727
'include':
2828
'{installed_base}/include/python{py_version_short}{abiflags}',
2929
'platinclude':
@@ -62,10 +62,10 @@
6262
'data': '{userbase}',
6363
},
6464
'posix_user': {
65-
'stdlib': '{userbase}/lib/python{py_version_short}',
66-
'platstdlib': '{userbase}/lib/python{py_version_short}',
65+
'stdlib': '{userbase}/{platlibdir}/python{py_version_short}',
66+
'platstdlib': '{userbase}/{platlibdir}/python{py_version_short}',
6767
'purelib': '{userbase}/lib/python{py_version_short}/site-packages',
68-
'platlib': '{userbase}/lib/python{py_version_short}/site-packages',
68+
'platlib': '{userbase}/{platlibdir}/python{py_version_short}/site-packages',
6969
'include': '{userbase}/include/python{py_version_short}',
7070
'scripts': '{userbase}/bin',
7171
'data': '{userbase}',
@@ -539,6 +539,7 @@ def get_config_vars(*args):
539539
_CONFIG_VARS['installed_platbase'] = _BASE_EXEC_PREFIX
540540
_CONFIG_VARS['platbase'] = _EXEC_PREFIX
541541
_CONFIG_VARS['projectbase'] = _PROJECT_BASE
542+
_CONFIG_VARS['platlibdir'] = sys.platlibdir
542543
try:
543544
_CONFIG_VARS['abiflags'] = sys.abiflags
544545
except AttributeError:

Lib/test/test_embed.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,11 +1068,11 @@ def module_search_paths(self, prefix=None, exec_prefix=None):
10681068
else:
10691069
ver = sys.version_info
10701070
return [
1071-
os.path.join(prefix, 'lib',
1071+
os.path.join(prefix, sys.platlibdir,
10721072
f'python{ver.major}{ver.minor}.zip'),
1073-
os.path.join(prefix, 'lib',
1073+
os.path.join(prefix, sys.platlibdir,
10741074
f'python{ver.major}.{ver.minor}'),
1075-
os.path.join(exec_prefix, 'lib',
1075+
os.path.join(exec_prefix, sys.platlibdir,
10761076
f'python{ver.major}.{ver.minor}', 'lib-dynload'),
10771077
]
10781078

@@ -1183,7 +1183,7 @@ def test_init_pyvenv_cfg(self):
11831183

11841184
if not MS_WINDOWS:
11851185
lib_dynload = os.path.join(pyvenv_home,
1186-
'lib',
1186+
sys.platlibdir,
11871187
f'python{ver.major}.{ver.minor}',
11881188
'lib-dynload')
11891189
os.makedirs(lib_dynload)

Lib/test/test_site.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,11 +266,18 @@ def test_getsitepackages(self):
266266
dirs = site.getsitepackages()
267267
if os.sep == '/':
268268
# OS X, Linux, FreeBSD, etc
269-
self.assertEqual(len(dirs), 1)
269+
if sys.platlibdir != "lib":
270+
self.assertEqual(len(dirs), 2)
271+
wanted = os.path.join('xoxo', sys.platlibdir,
272+
'python%d.%d' % sys.version_info[:2],
273+
'site-packages')
274+
self.assertEqual(dirs[0], wanted)
275+
else:
276+
self.assertEqual(len(dirs), 1)
270277
wanted = os.path.join('xoxo', 'lib',
271278
'python%d.%d' % sys.version_info[:2],
272279
'site-packages')
273-
self.assertEqual(dirs[0], wanted)
280+
self.assertEqual(dirs[-1], wanted)
274281
else:
275282
# other platforms
276283
self.assertEqual(len(dirs), 2)

Makefile.pre.in

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ LIBDIR= @libdir@
143143
MANDIR= @mandir@
144144
INCLUDEDIR= @includedir@
145145
CONFINCLUDEDIR= $(exec_prefix)/include
146-
SCRIPTDIR= $(prefix)/lib
146+
PLATLIBDIR= @PLATLIBDIR@
147+
SCRIPTDIR= $(prefix)/$(PLATLIBDIR)
147148
ABIFLAGS= @ABIFLAGS@
148149

149150
# Detailed destination directories
@@ -754,6 +755,7 @@ Modules/getpath.o: $(srcdir)/Modules/getpath.c Makefile
754755
-DEXEC_PREFIX='"$(exec_prefix)"' \
755756
-DVERSION='"$(VERSION)"' \
756757
-DVPATH='"$(VPATH)"' \
758+
-DPLATLIBDIR='"$(PLATLIBDIR)"' \
757759
-o $@ $(srcdir)/Modules/getpath.c
758760

759761
Programs/python.o: $(srcdir)/Programs/python.c
@@ -785,6 +787,7 @@ Python/dynload_hpux.o: $(srcdir)/Python/dynload_hpux.c Makefile
785787
Python/sysmodule.o: $(srcdir)/Python/sysmodule.c Makefile $(srcdir)/Include/pydtrace.h
786788
$(CC) -c $(PY_CORE_CFLAGS) \
787789
-DABIFLAGS='"$(ABIFLAGS)"' \
790+
-DPLATLIBDIR='"$(PLATLIBDIR)"' \
788791
$(MULTIARCH_CPPFLAGS) \
789792
-o $@ $(srcdir)/Python/sysmodule.c
790793

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Add ``--with-platlibdir`` option to the configure script: name of the
2+
platform-specific library directory, stored in the new :attr:`sys.platlitdir`
3+
attribute. It is used to build the path of platform-specific dynamic libraries
4+
and the path of the standard library. It is equal to ``"lib"`` on most
5+
platforms. On Fedora and SuSE, it is equal to ``"lib64"`` on 64-bit platforms.
6+
Patch by Jan Matějek, Matěj Cepl, Charalampos Stratakis and Victor Stinner.

Modules/getpath.c

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,9 @@ extern "C" {
105105
#endif
106106

107107

108-
#if !defined(PREFIX) || !defined(EXEC_PREFIX) || !defined(VERSION) || !defined(VPATH)
109-
#error "PREFIX, EXEC_PREFIX, VERSION, and VPATH must be constant defined"
108+
#if (!defined(PREFIX) || !defined(EXEC_PREFIX) \
109+
|| !defined(VERSION) || !defined(VPATH) || !defined(PLATLIBDIR))
110+
#error "PREFIX, EXEC_PREFIX, VERSION, VPATH and PLATLIBDIR macros must be defined"
110111
#endif
111112

112113
#ifndef LANDMARK
@@ -128,6 +129,7 @@ typedef struct {
128129
wchar_t *pythonpath_macro; /* PYTHONPATH macro */
129130
wchar_t *prefix_macro; /* PREFIX macro */
130131
wchar_t *exec_prefix_macro; /* EXEC_PREFIX macro */
132+
wchar_t *platlibdir_macro; /* PLATLIBDIR macro */
131133
wchar_t *vpath_macro; /* VPATH macro */
132134

133135
wchar_t *lib_python; /* "lib/pythonX.Y" */
@@ -809,8 +811,17 @@ calculate_exec_prefix(PyCalculatePath *calculate, _PyPathConfig *pathconfig)
809811
"Could not find platform dependent libraries <exec_prefix>\n");
810812
}
811813

814+
/* <PLATLIBDIR> / "lib-dynload" */
815+
wchar_t *lib_dynload = joinpath2(calculate->platlibdir_macro,
816+
L"lib-dynload");
817+
if (lib_dynload == NULL) {
818+
return _PyStatus_NO_MEMORY();
819+
}
820+
812821
calculate->exec_prefix = joinpath2(calculate->exec_prefix_macro,
813-
L"lib/lib-dynload");
822+
lib_dynload);
823+
PyMem_RawFree(lib_dynload);
824+
814825
if (calculate->exec_prefix == NULL) {
815826
return _PyStatus_NO_MEMORY();
816827
}
@@ -1284,35 +1295,47 @@ calculate_read_pyenv(PyCalculatePath *calculate)
12841295
static PyStatus
12851296
calculate_zip_path(PyCalculatePath *calculate)
12861297
{
1287-
const wchar_t *lib_python = L"lib/python00.zip";
1298+
PyStatus res;
1299+
1300+
/* Path: <PLATLIBDIR> / "python00.zip" */
1301+
wchar_t *path = joinpath2(calculate->platlibdir_macro, L"python00.zip");
1302+
if (path == NULL) {
1303+
return _PyStatus_NO_MEMORY();
1304+
}
12881305

12891306
if (calculate->prefix_found > 0) {
12901307
/* Use the reduced prefix returned by Py_GetPrefix()
12911308
1292-
Path: <basename(basename(prefix))> / <lib_python> */
1309+
Path: <basename(basename(prefix))> / <PLATLIBDIR> / "python00.zip" */
12931310
wchar_t *parent = _PyMem_RawWcsdup(calculate->prefix);
12941311
if (parent == NULL) {
1295-
return _PyStatus_NO_MEMORY();
1312+
res = _PyStatus_NO_MEMORY();
1313+
goto done;
12961314
}
12971315
reduce(parent);
12981316
reduce(parent);
1299-
calculate->zip_path = joinpath2(parent, lib_python);
1317+
calculate->zip_path = joinpath2(parent, path);
13001318
PyMem_RawFree(parent);
13011319
}
13021320
else {
1303-
calculate->zip_path = joinpath2(calculate->prefix_macro, lib_python);
1321+
calculate->zip_path = joinpath2(calculate->prefix_macro, path);
13041322
}
13051323

13061324
if (calculate->zip_path == NULL) {
1307-
return _PyStatus_NO_MEMORY();
1325+
res = _PyStatus_NO_MEMORY();
1326+
goto done;
13081327
}
13091328

13101329
/* Replace "00" with version */
13111330
size_t len = wcslen(calculate->zip_path);
13121331
calculate->zip_path[len - 6] = VERSION[0];
13131332
calculate->zip_path[len - 5] = VERSION[2];
13141333

1315-
return _PyStatus_OK();
1334+
res = _PyStatus_OK();
1335+
1336+
done:
1337+
PyMem_RawFree(path);
1338+
return res;
13161339
}
13171340

13181341

@@ -1434,10 +1457,14 @@ calculate_init(PyCalculatePath *calculate, const PyConfig *config)
14341457
if (!calculate->vpath_macro) {
14351458
return DECODE_LOCALE_ERR("VPATH macro", len);
14361459
}
1460+
calculate->platlibdir_macro = Py_DecodeLocale(PLATLIBDIR, &len);
1461+
if (!calculate->platlibdir_macro) {
1462+
return DECODE_LOCALE_ERR("PLATLIBDIR macro", len);
1463+
}
14371464

1438-
calculate->lib_python = Py_DecodeLocale("lib/python" VERSION, &len);
1465+
calculate->lib_python = Py_DecodeLocale(PLATLIBDIR "/python" VERSION, &len);
14391466
if (!calculate->lib_python) {
1440-
return DECODE_LOCALE_ERR("EXEC_PREFIX macro", len);
1467+
return DECODE_LOCALE_ERR("VERSION macro", len);
14411468
}
14421469

14431470
calculate->warnings = config->pathconfig_warnings;
@@ -1454,6 +1481,7 @@ calculate_free(PyCalculatePath *calculate)
14541481
PyMem_RawFree(calculate->prefix_macro);
14551482
PyMem_RawFree(calculate->exec_prefix_macro);
14561483
PyMem_RawFree(calculate->vpath_macro);
1484+
PyMem_RawFree(calculate->platlibdir_macro);
14571485
PyMem_RawFree(calculate->lib_python);
14581486
PyMem_RawFree(calculate->path_env);
14591487
PyMem_RawFree(calculate->zip_path);

PC/pyconfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,4 +683,6 @@ Py_NO_ENABLE_SHARED to find out. Also support MS_NO_COREDLL for b/w compat */
683683
/* Define if libssl has X509_VERIFY_PARAM_set1_host and related function */
684684
#define HAVE_X509_VERIFY_PARAM_SET1_HOST 1
685685

686+
#define PLATLIBDIR "lib"
687+
686688
#endif /* !Py_CONFIG_H */

0 commit comments

Comments
 (0)