def parse_compile_commands_json(logfile, parseLogOptions): """ logfile: is a compile command json """ output_path = parseLogOptions.output_path if output_path is not None: remove_file_if_exists( os.path.join(output_path, compiler_includes_dump_file)) remove_file_if_exists( os.path.join(output_path, compiler_target_dump_file)) actions = [] filtered_build_actions = {} data = json.load(logfile) compiler_includes = {} compiler_target = {} counter = 0 for entry in data: sourcefile = entry['file'] if not os.path.isabs(sourcefile): # Newest versions of intercept-build can create the 'file' in the # JSON Compilation Database as a relative path. sourcefile = os.path.join(os.path.abspath(entry['directory']), sourcefile) lang = option_parser.get_language(sourcefile[sourcefile.rfind('.'):]) if not lang: continue action = build_action.BuildAction(counter) if 'command' in entry: command = entry['command'] # Old versions of intercept-build (confirmed to those shipping # with upstream clang-5.0) do escapes in another way: # -DVARIABLE="a b" becomes -DVARIABLE=\"a b\" in the output. # This would be messed up later on by options_parser, so need a # fix here. (Should be removed once we are sure noone uses this # intercept-build anymore!) if r'\"' in command: command = command.replace(r'\"', '"') elif 'arguments' in entry: # Newest versions of intercept-build create an argument vector # instead of a command string. command = ' '.join(entry['arguments']) else: raise KeyError("No valid 'command' or 'arguments' entry found!") results = option_parser.parse_options(command) action.original_command = command # If the original include directory could not be found # in the filesystem, it is possible that it was provided # relative to the working directory in the compile json. compile_opts = results.compile_opts for i, opt in enumerate(compile_opts): if opt.startswith('-I'): inc_dir = opt[2:].strip() if not os.path.isdir(inc_dir): compile_opts[i] = '-I' + \ os.path.join(entry['directory'], inc_dir) action.analyzer_options = compile_opts action.lang = results.lang action.target = results.arch action.output = results.output add_compiler_defaults = True # With gcc-toolchain a non default compiler toolchain can be set. # Clang will search for include paths and libraries based on the # gcc-toolchain parameter. # Detecting extra include paths from the host compiler could # conflict with this. # For example if the compiler in the compile command is clang # and gcc-toolchain is set we will get the include paths # for clang and not for the compiler set in gcc-toolchain. # This can cause missing headers during the analysis. toolchain = gcc_toolchain.toolchain_in_args(action.analyzer_options) if toolchain: add_compiler_defaults = False # Store the compiler built in include paths and defines. if add_compiler_defaults and results.compiler: if not (results.compiler in compiler_includes): # Fetch defaults from the compiler, # make sure we use the correct architecture. extra_opts = [] for regex in COMPILE_OPTS_FWD_TO_DEFAULTS_GETTER: pattern = re.compile(regex) for comp_opt in action.analyzer_options: if re.match(pattern, comp_opt): extra_opts.append(comp_opt) compiler_includes[results.compiler] = \ get_compiler_includes(parseLogOptions, results.compiler, results.lang, results.compile_opts, extra_opts) if not (results.compiler in compiler_target): compiler_target[results.compiler] = \ get_compiler_target(parseLogOptions, results.compiler) action.compiler_includes = compiler_includes[results.compiler] action.target = compiler_target[results.compiler] if results.action != option_parser.ActionType.COMPILE: action.skip = True # TODO: Check arch. action.directory = entry['directory'] action.sources = sourcefile # Filter out duplicate compilation commands. unique_key = action.cmp_key if filtered_build_actions.get(unique_key) is None: filtered_build_actions[unique_key] = action del action counter += 1 for _, ba in filtered_build_actions.items(): actions.append(ba) return actions
def parse_compile_commands_json(logfile, add_compiler_defaults=False): import json LOG.debug('parse_compile_commands_json: ' + str(add_compiler_defaults)) actions = [] filtered_build_actions = {} logfile.seek(0) data = json.load(logfile) compiler_defines = {} compiler_includes = {} counter = 0 for entry in data: sourcefile = entry['file'] if not os.path.isabs(sourcefile): # Newest versions of intercept-build can create the 'file' in the # JSON Compilation Database as a relative path. sourcefile = os.path.join(os.path.abspath(entry['directory']), sourcefile) lang = option_parser.get_language(sourcefile[sourcefile.rfind('.'):]) if not lang: continue action = build_action.BuildAction(counter) if 'command' in entry: command = entry['command'] # Old versions of intercept-build (confirmed to those shipping # with upstream clang-5.0) do escapes in another way: # -DVARIABLE="a b" becomes -DVARIABLE=\"a b\" in the output. # This would be messed up later on by options_parser, so need a # fix here. (Should be removed once we are sure noone uses this # intercept-build anymore!) if r'\"' in command: command = command.replace(r'\"', '"') elif 'arguments' in entry: # Newest versions of intercept-build create an argument vector # instead of a command string. command = ' '.join(entry['arguments']) else: raise KeyError("No valid 'command' or 'arguments' entry found!") results = option_parser.parse_options(command) action.original_command = command action.analyzer_options = results.compile_opts action.lang = results.lang action.target = results.arch # Store the compiler built in include paths and defines. if add_compiler_defaults and results.compiler: if not (results.compiler in compiler_defines): # Fetch defaults from the compiler, # make sure we use the correct architecture. extra_opts = [] for regex in COMPILE_OPTS_FWD_TO_DEFAULTS_GETTER: pattern = re.compile(regex) for comp_opt in action.analyzer_options: if re.match(pattern, comp_opt): extra_opts.append(comp_opt) compiler_defines[results.compiler] = \ get_compiler_defines(results.compiler, extra_opts) compiler_includes[results.compiler] = \ get_compiler_includes(results.compiler, extra_opts) action.compiler_defines = compiler_defines[results.compiler] action.compiler_includes = compiler_includes[results.compiler] if results.action == option_parser.ActionType.COMPILE or \ results.action == option_parser.ActionType.LINK: action.skip = False # TODO: Check arch. action.directory = entry['directory'] action.sources = sourcefile # Filter out duplicate compilation commands. unique_key = action.cmp_key if filtered_build_actions.get(unique_key) is None: filtered_build_actions[unique_key] = action del action counter += 1 for ba_hash, ba in filtered_build_actions.items(): actions.append(ba) return actions
def parse_compile_commands_json(logfile, add_compiler_defaults=False): import json LOG.debug('parse_compile_commands_json: ' + str(add_compiler_defaults)) actions = [] filtered_build_actions = {} logfile.seek(0) data = json.load(logfile) compiler_defines = {} compiler_includes = {} counter = 0 for entry in data: sourcefile = entry['file'] lang = option_parser.get_language(sourcefile[sourcefile.rfind('.'):]) if not lang: continue action = build_action.BuildAction(counter) command = entry['command'] results = option_parser.parse_options(command) action.original_command = command action.analyzer_options = results.compile_opts action.lang = results.lang action.target = results.arch # store the compiler built in include paths # and defines if add_compiler_defaults and results.compiler: if not (results.compiler in compiler_defines): compiler_defines[results.compiler] = \ get_compiler_defines(results.compiler) compiler_includes[results.compiler] = \ get_compiler_includes(results.compiler) action.compiler_defines = compiler_defines[results.compiler] action.compiler_includes = compiler_includes[results.compiler] if results.action == option_parser.ActionType.COMPILE or \ results.action == option_parser.ActionType.LINK: action.skip = False # TODO: check arch. action.directory = entry['directory'] action.sources = sourcefile # Filter out duplicate compilation commands. unique_key = action.cmp_key if filtered_build_actions.get(unique_key) is None: filtered_build_actions[unique_key] = action del action counter += 1 for ba_hash, ba in filtered_build_actions.items(): actions.append(ba) return actions