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.
(filename, vars=None, keep_unresolved=True)
| 26 | |
| 27 | |
| 28 | def _parse_makefile(filename, vars=None, keep_unresolved=True): |
| 29 | """Parse a Makefile-style file. |
| 30 | |
| 31 | A dictionary containing name/value pairs is returned. If an |
| 32 | optional dictionary is passed in as the second argument, it is |
| 33 | used instead of a new dictionary. |
| 34 | """ |
| 35 | import re |
| 36 | |
| 37 | if vars is None: |
| 38 | vars = {} |
| 39 | done = {} |
| 40 | notdone = {} |
| 41 | |
| 42 | with open(filename, encoding=sys.getfilesystemencoding(), |
| 43 | errors="surrogateescape") as f: |
| 44 | lines = f.readlines() |
| 45 | |
| 46 | for line in lines: |
| 47 | if line.startswith('#') or line.strip() == '': |
| 48 | continue |
| 49 | m = re.match(_variable_rx, line) |
| 50 | if m: |
| 51 | n, v = m.group(1, 2) |
| 52 | v = v.strip() |
| 53 | # `$$' is a literal `$' in make |
| 54 | tmpv = v.replace('$$', '') |
| 55 | |
| 56 | if "$" in tmpv: |
| 57 | notdone[n] = v |
| 58 | else: |
| 59 | try: |
| 60 | if n in _ALWAYS_STR: |
| 61 | raise ValueError |
| 62 | |
| 63 | v = int(v) |
| 64 | except ValueError: |
| 65 | # insert literal `$' |
| 66 | done[n] = v.replace('$$', '$') |
| 67 | else: |
| 68 | done[n] = v |
| 69 | |
| 70 | # do variable interpolation here |
| 71 | variables = list(notdone.keys()) |
| 72 | |
| 73 | # Variables with a 'PY_' prefix in the makefile. These need to |
| 74 | # be made available without that prefix through sysconfig. |
| 75 | # Special care is needed to ensure that variable expansion works, even |
| 76 | # if the expansion uses the name without a prefix. |
| 77 | renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') |
| 78 | |
| 79 | while len(variables) > 0: |
| 80 | for name in tuple(variables): |
| 81 | value = notdone[name] |
| 82 | m1 = re.search(_findvar1_rx, value) |
| 83 | m2 = re.search(_findvar2_rx, value) |
| 84 | if m1 and m2: |
| 85 | m = m1 if m1.start() < m2.start() else m2 |