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