[Python-checkins] bpo-44351: Restore back parse_makefile in distutils.sysconfig (GH-26637)

encukou webhook-mailer at python.org
Fri Jun 11 11:08:20 EDT 2021


https://github.com/python/cpython/commit/fc98266ff627ba0f56f8ae241245b66bc983baa3
commit: fc98266ff627ba0f56f8ae241245b66bc983baa3
branch: main
author: Lumír 'Frenzy' Balhar <lbalhar at redhat.com>
committer: encukou <encukou at gmail.com>
date: 2021-06-11T17:08:00+02:00
summary:

bpo-44351: Restore back parse_makefile in distutils.sysconfig (GH-26637)

The function uses distutils.text_file.TextFile and therefore
behaves differently than _parse_makefile in sysconfig.

files:
A Misc/NEWS.d/next/Library/2021-06-10-07-26-12.bpo-44351.rvyf2v.rst
M Lib/distutils/sysconfig.py

diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py
index aa63093a3f0e6..3414a761e76b9 100644
--- a/Lib/distutils/sysconfig.py
+++ b/Lib/distutils/sysconfig.py
@@ -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,
@@ -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
 
diff --git a/Misc/NEWS.d/next/Library/2021-06-10-07-26-12.bpo-44351.rvyf2v.rst b/Misc/NEWS.d/next/Library/2021-06-10-07-26-12.bpo-44351.rvyf2v.rst
new file mode 100644
index 0000000000000..d731a549632b5
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-06-10-07-26-12.bpo-44351.rvyf2v.rst
@@ -0,0 +1,2 @@
+Restore back :func:`parse_makefile` in :mod:`distutils.sysconfig` because it
+behaves differently than the similar implementation in :mod:`sysconfig`.



More information about the Python-checkins mailing list