]> git.proxmox.com Git - mirror_frr.git/blame - python/makevars.py
Merge pull request #12959 from leonshaw/fix/zif-link-nsid
[mirror_frr.git] / python / makevars.py
CommitLineData
879a9dc5
DL
1#
2# helper class to grab variables from FRR's Makefile
3#
4
5import os
6import subprocess
59994395 7import re
879a9dc5 8
701a0192 9
59994395 10class MakeVarsBase(object):
701a0192 11 """
59994395 12 common code between MakeVars and MakeReVars
701a0192 13 """
14
879a9dc5
DL
15 def __init__(self):
16 self._data = dict()
17
59994395
DL
18 def __getitem__(self, k):
19 if k not in self._data:
20 self.getvars([k])
21 return self._data[k]
22
701a0192 23 def get(self, k, defval=None):
59994395
DL
24 if k not in self._data:
25 self.getvars([k])
26 return self._data.get(k) or defval
27
701a0192 28
59994395 29class MakeVars(MakeVarsBase):
701a0192 30 """
59994395
DL
31 makevars['FOO_CFLAGS'] gets you "FOO_CFLAGS" from Makefile
32
33 This variant works by invoking make as a subprocess, i.e. Makefile must
34 be valid and working. (This is sometimes a problem if depfiles have not
35 been generated.)
701a0192 36 """
37
879a9dc5 38 def getvars(self, varlist):
701a0192 39 """
879a9dc5 40 get a batch list of variables from make. faster than individual calls.
701a0192 41 """
879a9dc5
DL
42 rdfd, wrfd = os.pipe()
43
701a0192 44 shvars = ["shvar-%s" % s for s in varlist]
45 make = subprocess.Popen(
46 ["make", "-s", "VARFD=%d" % wrfd] + shvars, pass_fds=[wrfd]
47 )
879a9dc5 48 os.close(wrfd)
701a0192 49 data = b""
879a9dc5 50
701a0192 51 rdf = os.fdopen(rdfd, "rb")
879a9dc5
DL
52 while True:
53 rdata = rdf.read()
54 if len(rdata) == 0:
55 break
56 data += rdata
57
58 del rdf
59 make.wait()
60
701a0192 61 data = data.decode("US-ASCII").strip().split("\n")
879a9dc5 62 for row in data:
701a0192 63 k, v = row.split("=", 1)
879a9dc5
DL
64 v = v[1:-1]
65 self._data[k] = v
66
701a0192 67
59994395 68class MakeReVars(MakeVarsBase):
701a0192 69 """
59994395 70 makevars['FOO_CFLAGS'] gets you "FOO_CFLAGS" from Makefile
879a9dc5 71
59994395
DL
72 This variant works by regexing through Makefile. This means the Makefile
73 does not need to be fully working, but on the other hand it doesn't support
74 fancy complicated make expressions.
701a0192 75 """
76
77 var_re = re.compile(
78 r"^([^=#\n\s]+)[ \t]*=[ \t]*([^#\n]*)(?:#.*)?$", flags=re.MULTILINE
79 )
80 repl_re = re.compile(r"\$(?:([A-Za-z])|\(([^\)]+)\))")
59994395
DL
81
82 def __init__(self, maketext):
c4006e05 83 super(MakeReVars, self).__init__()
701a0192 84 self._vars = dict(self.var_re.findall(maketext.replace("\\\n", "")))
59994395
DL
85
86 def replacevar(self, match):
87 varname = match.group(1) or match.group(2)
701a0192 88 return self._vars.get(varname, "")
59994395
DL
89
90 def getvars(self, varlist):
91 for varname in varlist:
92 if varname not in self._vars:
93 continue
94
95 val, prevval = self._vars[varname], None
96 while val != prevval:
97 prevval = val
98 val = self.repl_re.sub(self.replacevar, val)
99
100 self._data[varname] = val