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)
| 27 | |
| 28 | |
| 29 | def _parse_makefile(filename, vars=None, keep_unresolved=True): |
| 30 | """Parse a Makefile-style file. |
| 31 | |
| 32 | A dictionary containing name/value pairs is returned. If an |
| 33 | optional dictionary is passed in as the second argument, it is |
| 34 | used instead of a new dictionary. |
| 35 | """ |
| 36 | import re |
| 37 | |
| 38 | if vars is None: |
| 39 | vars = {} |
| 40 | done = {} |
| 41 | notdone = {} |
| 42 | |
| 43 | with open(filename, encoding=sys.getfilesystemencoding(), |
| 44 | errors="surrogateescape") as f: |
| 45 | lines = f.readlines() |
| 46 | |
| 47 | for line in lines: |
| 48 | if line.startswith('#') or line.strip() == '': |
| 49 | continue |
| 50 | m = re.match(_variable_rx, line) |
| 51 | if m: |
| 52 | n, v = m.group(1, 2) |
| 53 | notdone[n] = v.strip() |
| 54 | |
| 55 | # Variables with a 'PY_' prefix in the makefile. These need to |
| 56 | # be made available without that prefix through sysconfig. |
| 57 | # Special care is needed to ensure that variable expansion works, even |
| 58 | # if the expansion uses the name without a prefix. |
| 59 | renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') |
| 60 | |
| 61 | def resolve_var(name): |
| 62 | def repl(m): |
| 63 | n = m[1] |
| 64 | if n == '$': |
| 65 | return '$' |
| 66 | elif n == '': |
| 67 | # bogus variable reference (e.g. "prefix=$/opt/python") |
| 68 | if keep_unresolved: |
| 69 | return m[0] |
| 70 | raise ValueError |
| 71 | elif n[0] == '(' and n[-1] == ')': |
| 72 | n = n[1:-1] |
| 73 | elif n[0] == '{' and n[-1] == '}': |
| 74 | n = n[1:-1] |
| 75 | |
| 76 | if n in done: |
| 77 | return str(done[n]) |
| 78 | elif n in notdone: |
| 79 | return str(resolve_var(n)) |
| 80 | elif n in os.environ: |
| 81 | # do it like make: fall back to environment |
| 82 | return os.environ[n] |
| 83 | elif n in renamed_variables: |
| 84 | if name.startswith('PY_') and name[3:] in renamed_variables: |
| 85 | return "" |
| 86 | n = 'PY_' + n |
searching dependent graphs…