]> git.proxmox.com Git - mirror_frr.git/blob - python/makefile.py
Merge pull request #11158 from cyberstormdotmu/master
[mirror_frr.git] / python / makefile.py
1 #!/usr/bin/python3
2 #
3 # FRR extended automake/Makefile functionality helper
4 #
5 # This script is executed on/after generating Makefile to add some pieces for
6 # clippy.
7
8 import sys
9 import os
10 import subprocess
11 import re
12 import argparse
13 from string import Template
14 from makevars import MakeReVars
15
16 argp = argparse.ArgumentParser(description="FRR Makefile extensions")
17 argp.add_argument(
18 "--dev-build",
19 action="store_const",
20 const=True,
21 help="run additional developer checks",
22 )
23 args = argp.parse_args()
24
25 with open("Makefile", "r") as fd:
26 before = fd.read()
27
28 mv = MakeReVars(before)
29
30 clippy_scan = mv["clippy_scan"].strip().split()
31 for clippy_file in clippy_scan:
32 assert clippy_file.endswith(".c")
33
34 xref_targets = []
35 for varname in [
36 "bin_PROGRAMS",
37 "sbin_PROGRAMS",
38 "lib_LTLIBRARIES",
39 "module_LTLIBRARIES",
40 ]:
41 xref_targets.extend(mv[varname].strip().split())
42
43 # check for files using clippy but not listed in clippy_scan
44 if args.dev_build:
45 basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
46 if os.path.exists(os.path.join(basepath, ".git")):
47 clippy_ref = subprocess.check_output(
48 [
49 "git",
50 "-C",
51 basepath,
52 "grep",
53 "-l",
54 "-P",
55 "^#\s*include.*_clippy.c",
56 "--",
57 "**.c",
58 ]
59 ).decode("US-ASCII")
60
61 clippy_ref = set(clippy_ref.splitlines())
62 missing = clippy_ref - set(clippy_scan)
63
64 if len(missing) > 0:
65 sys.stderr.write(
66 'error: files seem to be using clippy, but not listed in "clippy_scan" in subdir.am:\n\t%s\n'
67 % ("\n\t".join(sorted(missing)))
68 )
69 sys.exit(1)
70
71 # this additional-dependency rule is stuck onto all compile targets that
72 # compile a file which uses clippy-generated input, so it has a dependency to
73 # make that first.
74 clippydep = Template(
75 """
76 ${clippybase}.$$(OBJEXT): ${clippybase}_clippy.c
77 ${clippybase}.lo: ${clippybase}_clippy.c
78 ${clippybase}_clippy.c: $$(CLIPPY_DEPS)"""
79 )
80
81 # this one is used when one .c file is built multiple times with different
82 # CFLAGS
83 clippyauxdep = Template(
84 """# clippy{
85 # auxiliary clippy target
86 ${target}: ${clippybase}_clippy.c
87 # }clippy"""
88 )
89
90 lines = before.splitlines()
91 autoderp = "#AUTODERP# "
92 out_lines = []
93 bcdeps = []
94 make_rule_re = re.compile("^([^:\s]+):\s*([^:\s]+)\s*($|\n)")
95
96 while lines:
97 line = lines.pop(0)
98 if line.startswith(autoderp):
99 line = line[len(autoderp) :]
100
101 # allow rerunning on already-clippified Makefile
102 if line == "# clippy{":
103 while lines:
104 line = lines.pop(0)
105 if line == "# }clippy":
106 break
107 continue
108
109 if line.startswith("#"):
110 out_lines.append(line)
111 continue
112
113 full_line = line
114 full_lines = lines[:]
115 while full_line.endswith("\\"):
116 full_line = full_line[:-1] + full_lines.pop(0)
117
118 m = make_rule_re.match(full_line)
119 if m is None:
120 out_lines.append(line)
121 continue
122
123 line, lines = full_line, full_lines
124
125 target, dep = m.group(1), m.group(2)
126
127 filename = os.path.basename(target)
128 if "-" in filename:
129 # dashes in output filename = building same .c with different CFLAGS
130 am_name, _ = filename.split("-", 1)
131 am_name = os.path.join(os.path.dirname(target), am_name)
132 am_name = am_name.replace("/", "_")
133 extraflags = " $(%s_CFLAGS)" % (am_name,)
134 else:
135 # this path isn't really triggered because automake is using a generic
136 # .c => .o rule unless CFLAGS are customized for a target
137 extraflags = ""
138
139 if target.endswith(".lo") or target.endswith(".o"):
140 if not dep.endswith(".h"):
141 # LLVM bitcode targets for analysis tools
142 bcdeps.append("%s.bc: %s" % (target, target))
143 bcdeps.append(
144 "\t$(AM_V_LLVM_BC)$(COMPILE)%s -emit-llvm -c -o $@ %s"
145 % (extraflags, dep)
146 )
147 if m.group(2) in clippy_scan:
148 # again - this is only hit for targets with custom CFLAGS, because
149 # automake uses a generic .c -> .o rule for standard CFLAGS
150 out_lines.append(
151 clippyauxdep.substitute(target=m.group(1), clippybase=m.group(2)[:-2])
152 )
153
154 out_lines.append(line)
155
156 # now, cover all the .c files that don't have special build rules
157 out_lines.append("# clippy{\n# main clippy targets")
158 for clippy_file in clippy_scan:
159 out_lines.append(clippydep.substitute(clippybase=clippy_file[:-2]))
160
161 # combine daemon .xref files into frr.xref
162 out_lines.append("")
163 out_lines.append(
164 "xrefs = %s" % (" ".join(["%s.xref" % target for target in xref_targets]))
165 )
166 out_lines.append("frr.xref: $(xrefs)")
167 out_lines.append("")
168
169 # analog but slower way to get the same frr.xref
170 # frr.xref: $(bin_PROGRAMS) $(sbin_PROGRAMS) $(lib_LTLIBRARIES) $(module_LTLIBRARIES)
171 # $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^
172
173 # LLVM bitcode link targets creating a .bc file for whole daemon or lib
174 out_lines.append("")
175 out_lines.extend(bcdeps)
176 out_lines.append("")
177 bc_targets = []
178 for varname in [
179 "bin_PROGRAMS",
180 "sbin_PROGRAMS",
181 "lib_LTLIBRARIES",
182 "module_LTLIBRARIES",
183 "noinst_LIBRARIES",
184 ]:
185 bc_targets.extend(mv[varname].strip().split())
186 for target in bc_targets:
187 amtgt = target.replace("/", "_").replace(".", "_").replace("-", "_")
188 objs = mv[amtgt + "_OBJECTS"].strip().split()
189 objs = [obj + ".bc" for obj in objs]
190 deps = mv.get(amtgt + "_DEPENDENCIES", "").strip().split()
191 deps = [d + ".bc" for d in deps if d.endswith(".a")]
192 objs.extend(deps)
193 out_lines.append("%s.bc: %s" % (target, " ".join(objs)))
194 out_lines.append("\t$(AM_V_LLVM_LD)$(LLVM_LINK) -o $@ $^")
195 out_lines.append("")
196
197 out_lines.append("# }clippy")
198 out_lines.append("")
199
200 after = "\n".join(out_lines)
201 if after == before:
202 sys.exit(0)
203
204 with open("Makefile.pyout", "w") as fd:
205 fd.write(after)
206 os.rename("Makefile.pyout", "Makefile")