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,
- help = 'run additional developer checks')
+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:
+with open("Makefile", "r") as fd:
before = fd.read()
mv = MakeReVars(before)
-clippy_scan = mv['clippy_scan'].strip().split()
+clippy_scan = mv["clippy_scan"].strip().split()
for clippy_file in clippy_scan:
- assert clippy_file.endswith('.c')
+ assert clippy_file.endswith(".c")
+
+xref_targets = []
+for varname in [
+ "bin_PROGRAMS",
+ "sbin_PROGRAMS",
+ "lib_LTLIBRARIES",
+ "module_LTLIBRARIES",
+]:
+ xref_targets.extend(mv[varname].strip().split())
# 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')
+ 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.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('''
+# this additional-dependency rule is stuck onto all compile targets that
+# compile a file which uses clippy-generated input, so it has a dependency to
+# make that first.
+clippydep = Template(
+ """
${clippybase}.$$(OBJEXT): ${clippybase}_clippy.c
${clippybase}.lo: ${clippybase}_clippy.c
-${clippybase}_clippy.c: $$(CLIPPY_DEPS)''')
+${clippybase}_clippy.c: $$(CLIPPY_DEPS)"""
+)
-clippyauxdep = Template('''# clippy{
+# this one is used when one .c file is built multiple times with different
+# CFLAGS
+clippyauxdep = Template(
+ """# clippy{
# auxiliary clippy target
${target}: ${clippybase}_clippy.c
-# }clippy''')
+# }clippy"""
+)
lines = before.splitlines()
-autoderp = '#AUTODERP# '
+autoderp = "#AUTODERP# "
out_lines = []
bcdeps = []
-make_rule_re = re.compile('^([^:\s]+):\s*([^:\s]+)\s*($|\n)')
+make_rule_re = re.compile("^([^:\s]+):\s*([^:\s]+)\s*($|\n)")
while lines:
line = lines.pop(0)
if line.startswith(autoderp):
- line = line[len(autoderp):]
+ line = line[len(autoderp) :]
- if line == '# clippy{':
+ # allow rerunning on already-clippified Makefile
+ if line == "# clippy{":
while lines:
line = lines.pop(0)
- if line == '# }clippy':
+ if line == "# }clippy":
break
continue
- if line.startswith('#'):
+ if line.startswith("#"):
out_lines.append(line)
continue
full_line = line
full_lines = lines[:]
- while full_line.endswith('\\'):
+ while full_line.endswith("\\"):
full_line = full_line[:-1] + full_lines.pop(0)
m = make_rule_re.match(full_line)
target, dep = m.group(1), m.group(2)
- if target.endswith('.lo') or target.endswith('.o'):
- if not dep.endswith('.h'):
- bcdeps.append('%s.bc: %s' % (target, target))
- bcdeps.append('\t$(AM_V_LLVM_BC)$(COMPILE) -emit-llvm -c -o $@ %s' % (dep))
+ filename = os.path.basename(target)
+ if "-" in filename:
+ # dashes in output filename = building same .c with different CFLAGS
+ am_name, _ = filename.split("-", 1)
+ am_name = os.path.join(os.path.dirname(target), am_name)
+ am_name = am_name.replace("/", "_")
+ extraflags = " $(%s_CFLAGS)" % (am_name,)
+ else:
+ # this path isn't really triggered because automake is using a generic
+ # .c => .o rule unless CFLAGS are customized for a target
+ extraflags = ""
+
+ if target.endswith(".lo") or target.endswith(".o"):
+ if not dep.endswith(".h"):
+ # LLVM bitcode targets for analysis tools
+ bcdeps.append("%s.bc: %s" % (target, target))
+ bcdeps.append(
+ "\t$(AM_V_LLVM_BC)$(COMPILE)%s -emit-llvm -c -o $@ %s"
+ % (extraflags, dep)
+ )
if m.group(2) in clippy_scan:
- out_lines.append(clippyauxdep.substitute(target=m.group(1), clippybase=m.group(2)[:-2]))
+ # again - this is only hit for targets with custom CFLAGS, because
+ # automake uses a generic .c -> .o rule for standard CFLAGS
+ 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')
+# now, cover all the .c files that don't have special build rules
+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('')
+ out_lines.append(clippydep.substitute(clippybase=clippy_file[:-2]))
+
+# combine daemon .xref files into frr.xref
+out_lines.append("")
+xref_targets = [
+ target
+ for target in xref_targets
+ if target
+ not in [
+ "bgpd/rfp-example/rfptest/rfptest",
+ "pimd/mtracebis",
+ "tools/ssd",
+ "vtysh/vtysh",
+ ]
+]
+out_lines.append(
+ "xrefs = %s" % (" ".join(["%s.xref" % target for target in xref_targets]))
+)
+out_lines.append("frr.xref: $(xrefs)")
+out_lines.append("")
+
+# analog but slower way to get the same frr.xref
+# frr.xref: $(bin_PROGRAMS) $(sbin_PROGRAMS) $(lib_LTLIBRARIES) $(module_LTLIBRARIES)
+# $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^
+
+# LLVM bitcode link targets creating a .bc file for whole daemon or lib
+out_lines.append("")
out_lines.extend(bcdeps)
-out_lines.append('')
+out_lines.append("")
bc_targets = []
-for varname in ['bin_PROGRAMS', 'sbin_PROGRAMS', 'lib_LTLIBRARIES', 'module_LTLIBRARIES', 'noinst_LIBRARIES']:
+for varname in [
+ "bin_PROGRAMS",
+ "sbin_PROGRAMS",
+ "lib_LTLIBRARIES",
+ "module_LTLIBRARIES",
+ "noinst_LIBRARIES",
+]:
bc_targets.extend(mv[varname].strip().split())
for target in bc_targets:
- amtgt = target.replace('/', '_').replace('.', '_').replace('-', '_')
- objs = mv[amtgt + '_OBJECTS'].strip().split()
- objs = [obj + '.bc' for obj in objs]
- deps = mv.get(amtgt + '_DEPENDENCIES', '').strip().split()
- deps = [d + '.bc' for d in deps if d.endswith('.a')]
+ amtgt = target.replace("/", "_").replace(".", "_").replace("-", "_")
+ objs = mv[amtgt + "_OBJECTS"].strip().split()
+ objs = [obj + ".bc" for obj in objs]
+ deps = mv.get(amtgt + "_DEPENDENCIES", "").strip().split()
+ deps = [d + ".bc" for d in deps if d.endswith(".a")]
objs.extend(deps)
- out_lines.append('%s.bc: %s' % (target, ' '.join(objs)))
- out_lines.append('\t$(AM_V_LLVM_LD)$(LLVM_LINK) -o $@ $^')
- out_lines.append('')
+ out_lines.append("%s.bc: %s" % (target, " ".join(objs)))
+ out_lines.append("\t$(AM_V_LLVM_LD)$(LLVM_LINK) -o $@ $^")
+ out_lines.append("")
-out_lines.append('# }clippy')
-out_lines.append('')
+out_lines.append("# }clippy")
+out_lines.append("")
-after = '\n'.join(out_lines)
+after = "\n".join(out_lines)
if after == before:
sys.exit(0)
-with open('Makefile.pyout', 'w') as fd:
+with open("Makefile.pyout", "w") as fd:
fd.write(after)
-os.rename('Makefile.pyout', 'Makefile')
+os.rename("Makefile.pyout", "Makefile")