Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Lib/_osx_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS',
'PY_CORE_EXE_LDFLAGS')

# configuration variables that may contain compiler calls
_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
Expand Down
24 changes: 17 additions & 7 deletions Lib/sysconfig/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,13 @@ def _init_non_posix(vars):
vars['EXE'] = '.exe'
vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT
vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable))
vars['TZPATH'] = ''
# No standard path exists on Windows for this, but we'll check
# whether someone is imitating a POSIX-like layout
check_tzpath = os.path.join(vars['prefix'], 'share', 'zoneinfo')
if os.path.exists(check_tzpath):
vars['TZPATH'] = check_tzpath
else:
vars['TZPATH'] = ''

#
# public APIs
Expand All @@ -431,6 +437,7 @@ def parse_config_h(fp, vars=None):
import re
define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
quoted_re = re.compile('^"(.*)"$')

while True:
line = fp.readline()
Expand All @@ -439,6 +446,8 @@ def parse_config_h(fp, vars=None):
m = define_rx.match(line)
if m:
n, v = m.group(1, 2)
if mq := quoted_re.match(v):
v = mq.group(1)
try:
if n in _ALWAYS_STR:
raise ValueError
Expand Down Expand Up @@ -639,6 +648,9 @@ def get_platform():
isn't particularly important.

Examples of returned values:
linux-x86_64
linux-aarch64
solaris-2.6-sun4u


Windows:
Expand All @@ -656,12 +668,10 @@ def get_platform():

For other non-POSIX platforms, currently just returns :data:`sys.platform`."""
if os.name == 'nt':
if 'amd64' in sys.version.lower():
return 'win-amd64'
if '(arm)' in sys.version.lower():
return 'win-arm32'
if '(arm64)' in sys.version.lower():
return 'win-arm64'
import _sysconfig
platform = _sysconfig.get_platform()
if platform:
return platform
return sys.platform

if os.name != "posix" or not hasattr(os, 'uname'):
Expand Down
146 changes: 60 additions & 86 deletions Lib/sysconfig/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
# Regexes needed for parsing Makefile (and similar syntaxes,
# like old-style Setup files).
_variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)"
_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"
_findvar_rx = (r"\$(\([A-Za-z][A-Za-z0-9_]*\)"
r"|\{[A-Za-z][A-Za-z0-9_]*\}"
r"|\$?)")


def _parse_makefile(filename, vars=None, keep_unresolved=True):
Expand All @@ -49,99 +50,72 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True):
m = re.match(_variable_rx, line)
if m:
n, v = m.group(1, 2)
v = v.strip()
# `$$' is a literal `$' in make
tmpv = v.replace('$$', '')

if "$" in tmpv:
notdone[n] = v
else:
try:
if n in _ALWAYS_STR:
raise ValueError

v = int(v)
except ValueError:
# insert literal `$'
done[n] = v.replace('$$', '$')
else:
done[n] = v

# do variable interpolation here
variables = list(notdone.keys())
notdone[n] = v.strip()

# Variables with a 'PY_' prefix in the makefile. These need to
# be made available without that prefix through sysconfig.
# Special care is needed to ensure that variable expansion works, even
# if the expansion uses the name without a prefix.
renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')

while len(variables) > 0:
for name in tuple(variables):
value = notdone[name]
m1 = re.search(_findvar1_rx, value)
m2 = re.search(_findvar2_rx, value)
if m1 and m2:
m = m1 if m1.start() < m2.start() else m2
else:
m = m1 if m1 else m2
if m is not None:
n = m.group(1)
found = True
if n in done:
item = str(done[n])
elif n in notdone:
# get it on a subsequent round
found = False
elif n in os.environ:
# do it like make: fall back to environment
item = os.environ[n]

elif n in renamed_variables:
if (name.startswith('PY_') and
name[3:] in renamed_variables):
item = ""

elif 'PY_' + n in notdone:
found = False

else:
item = str(done['PY_' + n])

def resolve_var(name):
def repl(m):
n = m[1]
if n == '$':
return '$'
elif n == '':
# bogus variable reference (e.g. "prefix=$/opt/python")
if keep_unresolved:
return m[0]
raise ValueError
elif n[0] == '(' and n[-1] == ')':
n = n[1:-1]
elif n[0] == '{' and n[-1] == '}':
n = n[1:-1]

if n in done:
return str(done[n])
elif n in notdone:
return str(resolve_var(n))
elif n in os.environ:
# do it like make: fall back to environment
return os.environ[n]
elif n in renamed_variables:
if name.startswith('PY_') and name[3:] in renamed_variables:
return ""
n = 'PY_' + n
if n in notdone:
return str(resolve_var(n))
else:
done[n] = item = ""

if found:
after = value[m.end():]
value = value[:m.start()] + item + after
if "$" in after:
notdone[name] = value
else:
try:
if name in _ALWAYS_STR:
raise ValueError
value = int(value)
except ValueError:
done[name] = value.strip()
else:
done[name] = value
variables.remove(name)

if name.startswith('PY_') \
and name[3:] in renamed_variables:

name = name[3:]
if name not in done:
done[name] = value

assert n not in done
return ""
else:
# Adds unresolved variables to the done dict.
# This is disabled when called from distutils.sysconfig
if keep_unresolved:
done[name] = value
# bogus variable reference (e.g. "prefix=$/opt/python");
# just drop it since we can't deal
variables.remove(name)
done[n] = ""
return ""

assert name not in done
done[name] = ""
try:
value = re.sub(_findvar_rx, repl, notdone[name])
except ValueError:
del done[name]
return ""
value = value.strip()
if name not in _ALWAYS_STR:
try:
value = int(value)
except ValueError:
pass
done[name] = value
if name.startswith('PY_') and name[3:] in renamed_variables:
name = name[3:]
if name not in done:
done[name] = value
return value

for n in notdone:
if n not in done:
resolve_var(n)

# strip spurious spaces
for k, v in done.items():
Expand Down
6 changes: 5 additions & 1 deletion Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1652,8 +1652,12 @@ def _platform_specific(self):
))

self._env = {k.upper(): os.getenv(k) for k in os.environ}
self._env["PYTHONHOME"] = os.path.dirname(self.real)
home = os.path.dirname(self.real)
if sysconfig.is_python_build():
home = os.path.join(home, sysconfig.get_config_var('VPATH'))
self._env["PYTHONHOME"] = home
# TODO: RUSTPYTHON; Cargo builds do not use CPython's Modules/Setup.
if sys.implementation.name == 'rustpython':
self._env["PYTHONPATH"] = STDLIB_DIR
else:
def _platform_specific(self):
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test__osx_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def setUp(self):
'CFLAGS', 'LDFLAGS', 'CPPFLAGS',
'BASECFLAGS', 'BLDSHARED', 'LDSHARED', 'CC',
'CXX', 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS'
'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS', 'PY_CORE_EXE_LDFLAGS'
)

def add_expected_saved_initial_values(self, config_vars, expected_vars):
Expand Down
Loading
Loading