xref: /qemu/scripts/check_sparse.py (revision deb62371)
1968b4db3SPaolo Bonzini#! /usr/bin/env python3
2968b4db3SPaolo Bonzini
3*deb62371SPaolo Bonzini# Invoke sparse based on the contents of compile_commands.json,
4*deb62371SPaolo Bonzini# also working around several deficiencies in cgcc's command line
5*deb62371SPaolo Bonzini# parsing
6968b4db3SPaolo Bonzini
7968b4db3SPaolo Bonziniimport json
8968b4db3SPaolo Bonziniimport subprocess
9*deb62371SPaolo Bonziniimport os
10968b4db3SPaolo Bonziniimport sys
11968b4db3SPaolo Bonziniimport shlex
12968b4db3SPaolo Bonzini
13*deb62371SPaolo Bonzinidef cmdline_for_sparse(sparse, cmdline):
14*deb62371SPaolo Bonzini    # Do not include the C compiler executable
15*deb62371SPaolo Bonzini    skip = True
16*deb62371SPaolo Bonzini    arg = False
17*deb62371SPaolo Bonzini    out = sparse + ['-no-compile']
18*deb62371SPaolo Bonzini    for x in cmdline:
19*deb62371SPaolo Bonzini        if arg:
20*deb62371SPaolo Bonzini            out.append(x)
21*deb62371SPaolo Bonzini            arg = False
22*deb62371SPaolo Bonzini            continue
23*deb62371SPaolo Bonzini        if skip:
24*deb62371SPaolo Bonzini            skip = False
25*deb62371SPaolo Bonzini            continue
26*deb62371SPaolo Bonzini        # prevent sparse from treating output files as inputs
27*deb62371SPaolo Bonzini        if x == '-MF' or x == '-MQ' or x == '-o':
28*deb62371SPaolo Bonzini            skip = True
29*deb62371SPaolo Bonzini            continue
30*deb62371SPaolo Bonzini        # cgcc ignores -no-compile if it sees -M or -MM?
31*deb62371SPaolo Bonzini        if x.startswith('-M'):
32*deb62371SPaolo Bonzini            continue
33*deb62371SPaolo Bonzini        # sparse does not understand these!
34*deb62371SPaolo Bonzini        if x == '-iquote' or x == '-isystem':
35*deb62371SPaolo Bonzini            x = '-I'
36*deb62371SPaolo Bonzini        if x == '-I':
37*deb62371SPaolo Bonzini            arg = True
38*deb62371SPaolo Bonzini        out.append(x)
39*deb62371SPaolo Bonzini    return out
40968b4db3SPaolo Bonzini
41*deb62371SPaolo Bonziniroot_path = os.getenv('MESON_BUILD_ROOT')
42*deb62371SPaolo Bonzinidef build_path(s):
43*deb62371SPaolo Bonzini    return s if not root_path else os.path.join(root_path, s)
44*deb62371SPaolo Bonzini
45*deb62371SPaolo Bonziniccjson_path = build_path(sys.argv[1])
46*deb62371SPaolo Bonziniwith open(ccjson_path, 'r') as fd:
47968b4db3SPaolo Bonzini    compile_commands = json.load(fd)
48968b4db3SPaolo Bonzini
49*deb62371SPaolo Bonzinisparse = sys.argv[2:]
50*deb62371SPaolo Bonzinisparse_env = os.environ.copy()
51968b4db3SPaolo Bonzinifor cmd in compile_commands:
52*deb62371SPaolo Bonzini    cmdline = shlex.split(cmd['command'])
53*deb62371SPaolo Bonzini    cmd = cmdline_for_sparse(sparse, cmdline)
54*deb62371SPaolo Bonzini    print('REAL_CC=%s' % shlex.quote(cmdline[0]),
55*deb62371SPaolo Bonzini          ' '.join((shlex.quote(x) for x in cmd)))
56*deb62371SPaolo Bonzini    sparse_env['REAL_CC'] = cmdline[0]
57*deb62371SPaolo Bonzini    r = subprocess.run(cmd, env=sparse_env, cwd=root_path)
58968b4db3SPaolo Bonzini    if r.returncode != 0:
59968b4db3SPaolo Bonzini        sys.exit(r.returncode)
60