summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2020-05-01 15:22:05 +0200
committerDavid Lamparter <equinox@diac24.net>2020-05-05 14:06:42 +0200
commit599943954969adb2b69618b943e44c62ae3ce4d2 (patch)
treea6344db264ac0215afbfb97acafb5650fcb53c1a /python
parent15e9c561b2a10e90b1370e7a8d43d02ffde9e61a (diff)
build: rework Makefile var extraction... again
*sigh* I can't seem to catch a break on this. Add a regex variant. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'python')
-rw-r--r--python/makefile.py9
-rw-r--r--python/makevars.py60
2 files changed, 53 insertions, 16 deletions
diff --git a/python/makefile.py b/python/makefile.py
index 9af397d373..e60c8aadbc 100644
--- a/python/makefile.py
+++ b/python/makefile.py
@@ -11,6 +11,7 @@ import subprocess
import re
import argparse
from string import Template
+from makevars import MakeReVars
argp = argparse.ArgumentParser(description = 'FRR Makefile extensions')
argp.add_argument('--dev-build', action = 'store_const', const = True,
@@ -20,13 +21,9 @@ args = argp.parse_args()
with open('Makefile', 'r') as fd:
before = fd.read()
-nolinecont = before.replace('\\\n', '')
-m = re.search('^clippy_scan\s*=([^#]*)(?:#.*)?$', nolinecont, flags=re.MULTILINE)
-if m is None:
- sys.stderr.write('failed to parse Makefile.in\n')
- sys.exit(2)
+mv = MakeReVars(before)
-clippy_scan = m.group(1).strip().split()
+clippy_scan = mv['clippy_scan'].strip().split()
for clippy_file in clippy_scan:
assert clippy_file.endswith('.c')
diff --git a/python/makevars.py b/python/makevars.py
index e0e2031a0d..1a85fbd6f5 100644
--- a/python/makevars.py
+++ b/python/makevars.py
@@ -4,14 +4,33 @@
import os
import subprocess
+import re
-class MakeVars(object):
+class MakeVarsBase(object):
'''
- makevars['FOO_CFLAGS'] gets you "FOO_CFLAGS" from Makefile
+ common code between MakeVars and MakeReVars
'''
def __init__(self):
self._data = dict()
+ def __getitem__(self, k):
+ if k not in self._data:
+ self.getvars([k])
+ return self._data[k]
+
+ def get(self, k, defval = None):
+ if k not in self._data:
+ self.getvars([k])
+ return self._data.get(k) or defval
+
+class MakeVars(MakeVarsBase):
+ '''
+ makevars['FOO_CFLAGS'] gets you "FOO_CFLAGS" from Makefile
+
+ This variant works by invoking make as a subprocess, i.e. Makefile must
+ be valid and working. (This is sometimes a problem if depfiles have not
+ been generated.)
+ '''
def getvars(self, varlist):
'''
get a batch list of variables from make. faster than individual calls.
@@ -39,12 +58,33 @@ class MakeVars(object):
v = v[1:-1]
self._data[k] = v
- def __getitem__(self, k):
- if k not in self._data:
- self.getvars([k])
- return self._data[k]
+class MakeReVars(MakeVarsBase):
+ '''
+ makevars['FOO_CFLAGS'] gets you "FOO_CFLAGS" from Makefile
- def get(self, k, defval = None):
- if k not in self._data:
- self.getvars([k])
- return self._data[k] or defval
+ This variant works by regexing through Makefile. This means the Makefile
+ does not need to be fully working, but on the other hand it doesn't support
+ fancy complicated make expressions.
+ '''
+ var_re = re.compile(r'^([^=#\n\s]+)[ \t]*=[ \t]*([^#\n]*)(?:#.*)?$', flags=re.MULTILINE)
+ repl_re = re.compile(r'\$(?:([A-Za-z])|\(([^\)]+)\))')
+
+ def __init__(self, maketext):
+ super().__init__()
+ self._vars = dict(self.var_re.findall(maketext.replace('\\\n', '')))
+
+ def replacevar(self, match):
+ varname = match.group(1) or match.group(2)
+ return self._vars.get(varname, '')
+
+ def getvars(self, varlist):
+ for varname in varlist:
+ if varname not in self._vars:
+ continue
+
+ val, prevval = self._vars[varname], None
+ while val != prevval:
+ prevval = val
+ val = self.repl_re.sub(self.replacevar, val)
+
+ self._data[varname] = val