Skip to content

Commit

Permalink
bpo-44351: Restore back parse_makefile in distutils.sysconfig (python…
Browse files Browse the repository at this point in the history
…GH-26637)

The function uses distutils.text_file.TextFile and therefore
behaves differently than _parse_makefile in sysconfig.
  • Loading branch information
frenzymadness authored Jun 11, 2021
1 parent c956734 commit fc98266
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 4 deletions.
111 changes: 107 additions & 4 deletions Lib/distutils/sysconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
_PYTHON_BUILD as python_build,
_init_posix as sysconfig_init_posix,
parse_config_h as sysconfig_parse_config_h,
_parse_makefile as sysconfig_parse_makefile,

_init_non_posix,
_is_python_source_dir,
Expand Down Expand Up @@ -68,14 +67,118 @@ def parse_config_h(fp, g=None):
return sysconfig_parse_config_h(fp, vars=g)


def parse_makefile(fn, g=None):
return sysconfig_parse_makefile(fn, vars=g, keep_unresolved=False)

_python_build = partial(is_python_build, check_home=True)
_init_posix = partial(sysconfig_init_posix, _config_vars)
_init_nt = partial(_init_non_posix, _config_vars)


# Similar function is also implemented in sysconfig as _parse_makefile
# but without the parsing capabilities of distutils.text_file.TextFile.
def parse_makefile(fn, g=None):
"""Parse a Makefile-style file.
A dictionary containing name/value pairs is returned. If an
optional dictionary is passed in as the second argument, it is
used instead of a new dictionary.
"""
from distutils.text_file import TextFile
fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1, errors="surrogateescape")

if g is None:
g = {}
done = {}
notdone = {}

while True:
line = fp.readline()
if line is None: # eof
break
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:
v = int(v)
except ValueError:
# insert literal `$'
done[n] = v.replace('$$', '$')
else:
done[n] = v

# 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')

# do variable interpolation here
while notdone:
for name in list(notdone):
value = notdone[name]
m = re.search(_findvar1_rx, value) or re.search(_findvar2_rx, value)
if m:
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])
else:
done[n] = item = ""
if found:
after = value[m.end():]
value = value[:m.start()] + item + after
if "$" in after:
notdone[name] = value
else:
try: value = int(value)
except ValueError:
done[name] = value.strip()
else:
done[name] = value
del notdone[name]

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

name = name[3:]
if name not in done:
done[name] = value
else:
# bogus variable reference; just drop it since we can't deal
del notdone[name]

fp.close()

# strip spurious spaces
for k, v in done.items():
if isinstance(v, str):
done[k] = v.strip()

# save the results in the global dictionary
g.update(done)
return g


# Following functions are deprecated together with this module and they
# have no direct replacement

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Restore back :func:`parse_makefile` in :mod:`distutils.sysconfig` because it
behaves differently than the similar implementation in :mod:`sysconfig`.

0 comments on commit fc98266

Please sign in to comment.