#!/usr/bin/env python3 import copy import json import glob import os import sys def levenshteinDistance(s1, s2): if len(s1) > len(s2): s1, s2 = s2, s1 distances = range(len(s1) + 1) for i2, c2 in enumerate(s2): distances_ = [i2 + 1] for i1, c1 in enumerate(s1): if c1 == c2: distances_.append(distances[i1]) else: distances_.append( 1 + min((distances[i1], distances[i1 + 1], distances_[-1])) ) distances = distances_ return distances[-1] def Read(): with open("compile_commands.json") as file: return json.load(file) def Write(compile_commands): with open("compile_commands.json", "w") as file: json.dump(compile_commands, file, sort_keys=True, indent=2) def Headers(): # return [f for f in os.listdir('src') if f.endswith('.h')] return glob.glob(os.path.join(os.getcwd(), "src/*.h")) def NeedsConfigH(header): """Returns True if header needs config.h to function""" if header.endswith("/config.h"): return False with open(header) as file: return "INLINE_HEADER_BEGIN" in file.read() def FindSimilarCommand(compile_commands, header): header = os.path.join(os.getcwd(), header) bestDistance = sys.maxsize bestCommand = None for command in compile_commands: distance = levenshteinDistance(header, command["file"]) if distance < bestDistance: bestDistance = distance bestCommand = command return bestCommand def AdaptTemplate(command, header): command = copy.deepcopy(command) if "output" in command: del command["output"] src = os.path.relpath(command["file"], command["directory"]) index = command["arguments"].index(src) new_src = os.path.relpath(header, command["directory"]) command["arguments"][index : index + 1] = [ "-Wno-unused-macros", "-include", "config.h", new_src, ] command["file"] = header return command compile_commands = Read() new_compile_commands = copy.copy(compile_commands) for header in Headers(): if NeedsConfigH(header): similar = FindSimilarCommand(compile_commands, header) if similar["file"] == header: continue adapted = AdaptTemplate(similar, header) new_compile_commands.append(adapted) Write(new_compile_commands)