summaryrefslogtreecommitdiffstats
path: root/python/makevars.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:16:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-09 13:16:35 +0000
commite2bbf175a2184bd76f6c54ccf8456babeb1a46fc (patch)
treef0b76550d6e6f500ada964a3a4ee933a45e5a6f1 /python/makevars.py
parentInitial commit. (diff)
downloadfrr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.tar.xz
frr-e2bbf175a2184bd76f6c54ccf8456babeb1a46fc.zip
Adding upstream version 9.1.upstream/9.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'python/makevars.py')
-rw-r--r--python/makevars.py100
1 files changed, 100 insertions, 0 deletions
diff --git a/python/makevars.py b/python/makevars.py
new file mode 100644
index 0000000..951cd34
--- /dev/null
+++ b/python/makevars.py
@@ -0,0 +1,100 @@
+#
+# helper class to grab variables from FRR's Makefile
+#
+
+import os
+import subprocess
+import re
+
+
+class MakeVarsBase(object):
+ """
+ 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.
+ """
+ rdfd, wrfd = os.pipe()
+
+ shvars = ["shvar-%s" % s for s in varlist]
+ make = subprocess.Popen(
+ ["make", "-s", "VARFD=%d" % wrfd] + shvars, pass_fds=[wrfd]
+ )
+ os.close(wrfd)
+ data = b""
+
+ rdf = os.fdopen(rdfd, "rb")
+ while True:
+ rdata = rdf.read()
+ if len(rdata) == 0:
+ break
+ data += rdata
+
+ del rdf
+ make.wait()
+
+ data = data.decode("US-ASCII").strip().split("\n")
+ for row in data:
+ k, v = row.split("=", 1)
+ v = v[1:-1]
+ self._data[k] = v
+
+
+class MakeReVars(MakeVarsBase):
+ """
+ makevars['FOO_CFLAGS'] gets you "FOO_CFLAGS" from Makefile
+
+ 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(MakeReVars, self).__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