summaryrefslogtreecommitdiffstats
path: root/python/makefile.py
blob: fe20945ccccbfee16c8ffbe3f09ae42fffba5f31 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/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
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')
args = argp.parse_args()

with open('Makefile', 'r') as fd:
    before = fd.read()

mv = MakeReVars(before)

clippy_scan = mv['clippy_scan'].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 = []
bcdeps = []
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

    full_line = line
    full_lines = lines[:]
    while full_line.endswith('\\'):
        full_line = full_line[:-1] + full_lines.pop(0)

    m = make_rule_re.match(full_line)
    if m is None:
        out_lines.append(line)
        continue

    line, lines = full_line, full_lines

    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))
    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('')
out_lines.extend(bcdeps)
out_lines.append('')
bc_targets = []
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')]
    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('# }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')