summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2020-04-15 10:27:49 +0200
committerDavid Lamparter <equinox@diac24.net>2020-04-27 09:52:41 +0200
commit94cfb0692e0499e7ba40908db5259cd19c0e3d5e (patch)
tree21dea4bef030b2e9170029235fe2385bda5cf90f /python
parentec8f987e91678b50a4136459bd2351e623c6915d (diff)
build: make clippy Makefile rules nicer
These are easy to get subtly wrong, and doing so can cause nondeterministic failures when racing in parallel builds. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'python')
-rw-r--r--python/makefile.py100
1 files changed, 100 insertions, 0 deletions
diff --git a/python/makefile.py b/python/makefile.py
new file mode 100644
index 0000000000..9af397d373
--- /dev/null
+++ b/python/makefile.py
@@ -0,0 +1,100 @@
+#!/usr/bin/python3
+#
+# FRR extended automake/Makefile functionality helper
+#
+# This script is executed on/after generating Makefile to add some pieces for
+# clippy.
+
+import sys
+import os
+import subprocess
+import re
+import argparse
+from string import Template
+
+argp = argparse.ArgumentParser(description = 'FRR Makefile extensions')
+argp.add_argument('--dev-build', action = 'store_const', const = True,
+ help = 'run additional developer checks')
+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)
+
+clippy_scan = m.group(1).strip().split()
+for clippy_file in clippy_scan:
+ assert clippy_file.endswith('.c')
+
+# check for files using clippy but not listed in clippy_scan
+if args.dev_build:
+ basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+ if os.path.exists(os.path.join(basepath, '.git')):
+ clippy_ref = subprocess.check_output([
+ 'git', '-C', basepath, 'grep', '-l', '-P', '^#\s*include.*_clippy.c', '--', '**.c']).decode('US-ASCII')
+
+ clippy_ref = set(clippy_ref.splitlines())
+ missing = clippy_ref - set(clippy_scan)
+
+ if len(missing) > 0:
+ sys.stderr.write('error: files seem to be using clippy, but not listed in "clippy_scan" in subdir.am:\n\t%s\n' % ('\n\t'.join(sorted(missing))))
+ sys.exit(1)
+
+clippydep = Template('''
+${clippybase}.$$(OBJEXT): ${clippybase}_clippy.c
+${clippybase}.lo: ${clippybase}_clippy.c
+${clippybase}_clippy.c: $$(CLIPPY_DEPS)''')
+
+clippyauxdep = Template('''# clippy{
+# auxiliary clippy target
+${target}: ${clippybase}_clippy.c
+# }clippy''')
+
+lines = before.splitlines()
+autoderp = '#AUTODERP# '
+out_lines = []
+make_rule_re = re.compile('^([^:\s]+):\s*([^:\s]+)\s*($|\n)')
+
+while lines:
+ line = lines.pop(0)
+ if line.startswith(autoderp):
+ line = line[len(autoderp):]
+
+ if line == '# clippy{':
+ while lines:
+ line = lines.pop(0)
+ if line == '# }clippy':
+ break
+ continue
+
+ if line.startswith('#'):
+ out_lines.append(line)
+ continue
+
+ m = make_rule_re.match(line)
+ if m is None:
+ out_lines.append(line)
+ continue
+
+ if m.group(2) in clippy_scan:
+ out_lines.append(clippyauxdep.substitute(target=m.group(1), clippybase=m.group(2)[:-2]))
+
+ out_lines.append(line)
+
+out_lines.append('# clippy{\n# main clippy targets')
+for clippy_file in clippy_scan:
+ out_lines.append(clippydep.substitute(clippybase = clippy_file[:-2]))
+out_lines.append('# }clippy')
+out_lines.append('')
+
+after = '\n'.join(out_lines)
+if after == before:
+ sys.exit(0)
+
+with open('Makefile.pyout', 'w') as fd:
+ fd.write(after)
+os.rename('Makefile.pyout', 'Makefile')