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