#! /usr/bin/python2 import os import sys import shlex import re from headerutils import * import Queue file_list = list () usage = False ignore_conditional = False order = [ "system.h", "coretypes.h", "backend.h", "target.h", "rtl.h", "c-family/c-target.h", "c-family/c-target-def.h", "tree.h", "cp/cp-tree.h", "c-family/c-common.h", # these must come before diagnostic.h "c/c-tree.h", "fortran/gfortran.h", "gimple.h", "cfghooks.h", "df.h", "tm_p.h", "gimple-iterators.h", "ssa.h", "expmed.h", "optabs.h", "regs.h", "ira.h", "ira-int.h", "gimple-streamer.h" ] exclude_special = [ "bversion.h", "obstack.h", "insn-codes.h", "hooks.h" ] # includes is a dictionary indexed by a header files basename. # it consists of a 2 element tuple: # [0] - Name of header file which included this header. # [1] - vector of header file names included by this file. includes = { } # when a header is included multiple times, indexing this dictionary will # return a vector of all the headers which included it. dups = { } # When creating the master list, do not descend into these files for what # they include. Simply put the file itself in the list. This is primarily # required because the front end files inlcude orders tend to be at odds with # the order of middle end files, and its impossible to synchronize them.\ # They are ordered such that everything resolves properly. exclude_processing = [ "tree-vectorizer.h" , "c-target.h", "c-target-def.h", "cp-tree.h", "c-common.h", "c-tree.h", "gfortran.h" ] master_list = list () # where include file comes from in src h_from = { } # create the master ordering list... this is the desired order of headers def create_master_list (fn, verbose): if fn not in exclude_processing: for x in includes[fn][1]: create_master_list (x, verbose) if not fn in master_list: # Don't put diagnostic*.h into the ordering list. It is special since # various front ends have to set GCC_DIAG_STYLE before including it. # for each file, we'll tailor where it belongs by looking at the include # list and determine its position appropriately. if fn != "diagnostic.h" and fn != "diagnostic-core.h": master_list.append (fn) if (verbose): print fn + " included by: " + includes[fn][0] def print_dups (): if dups: print "\nduplicated includes" for i in dups: string = "dup : " + i + " : " string += includes[i][0] for i2 in dups[i]: string += ", "+i2 print string def process_known_dups (): # rtl.h gets tagged as a duplicate includer for all of coretypes.h, but that # is really for only generator files rtl_remove = includes["coretypes.h"][1] + ["statistics.h", "vec.h"] if dups: for i in rtl_remove: if dups[i] and "rtl.h" in dups[i]: dups[i].remove("rtl.h") if not dups[i]: dups.pop (i, None) # make sure diagnostic.h is the owner of diagnostic-core.h if includes["diagnostic-core.h"][0] != "diagnostic.h": dups["diagnostic-core.h"].append (includes["diagnostic-core.h"][0]) includes["diagnostic-core.h"] = ("diagnostic.h", includes["diagnostic-core.h"][1]) # This function scans back thorugh the list of headers which included other # headers to determine what file in HEADER_LIST brought 'HEADER' in. def indirectly_included (header, header_list): nm = os.path.basename (header) while nm and includes.get(nm): if includes[nm][0] in header_list: return includes[nm][0] nm = includes[nm][0] # diagnostic.h and diagnostic-core.h may not show up because we removed them # from the header list to manually position in an appropriate place. They have # specific requirements that they need to occur after certain FE files which # may overide the definition of GCC_DIAG_STYLE. # Check the dup list for whete they may have been included from and return # that header. if header == "diagnostic-core.h": if dups.get("diagnostic-core.h"): for f in dups["diagnostic-core.h"]: if f in header_list: return f else: if header in header_list: return header # Now check if diagnostics is included indirectly anywhere header = "diagnostic.h" if header == "diagnostic.h": if dups.get("diagnostic.h"): for f in dups["diagnostic.h"]: if f in header_list: return f else: if header in header_list: return header return "" # This function will take a list of headers from a source file and return # the desired new new order of the canonical headers in DESIRED_ORDER. def get_new_order (src_h, desired_order): new_order = list () for h in desired_order: if h in master_list: # Create the list of nested headers which included this file. iclist = list () ib = includes[h][0] while ib: iclist.insert(0, ib) ib = includes[ib][0] if iclist: for x in iclist: # If header is in the source code, and we are allowed to look inside if x in src_h and x not in exclude_processing: if x not in new_order and x[:10] != "diagnostic" and h not in exclude_special: new_order.append (x) break; else: if h not in new_order: new_order.append (h) f = "" if "diagnostic.h" in src_h: f = "diagnostic.h" elif "diagnostic-core.h" in src_h: f = "diagnostic-core.h" # If either diagnostic header was directly included in the main file, check to # see if its already included indirectly, or whether we need to add it to the # end of the canonically orders headers. if f: ii = indirectly_included (f, src_h) if not ii or ii == f: new_order.append (f) return new_order # stack of files to process process_stack = list () def process_one (info): i = info[0] owner = info[1] name = os.path.basename(i) if os.path.exists (i): if includes.get(name) == None: l = find_unique_include_list (i) # create a list which has just basenames in it new_list = list () for x in l: new_list.append (os.path.basename (x)) process_stack.append((x, name)) includes[name] = (owner, new_list) elif owner: if dups.get(name) == None: dups[name] = [ owner ] else: dups[name].append (owner) else: # seed tm.h with options.h since it is a build file and won't be seen. if not includes.get(name): if name == "tm.h": includes[name] = (owner, [ "options.h" ]) includes["options.h"] = ("tm.h", list ()) else: includes[name] = (owner, list ()) show_master = False for arg in sys.argv[1:]: if arg[0:1] == "-": if arg[0:2] == "-h": usage = True elif arg[0:2] == "-i": ignore_conditional = True elif arg[0:2] == "-v": show_master = True else: print "Error: unrecognized option " + arg elif os.path.exists(arg): file_list.append (arg) else: print "Error: file " + arg + " Does not exist." usage = True if not file_list and not show_master: usage = True if not usage and not os.path.exists ("coretypes.h"): usage = True print "Error: Must run command in main gcc source directory containing coretypes.h\n" # process diagnostic.h first.. it's special since GCC_DIAG_STYLE can be # overridden by languages, but must be done so by a file included BEFORE it. # so make sure it isn't seen as included by one of those files by making it # appear to be included by the src file. process_stack.insert (0, ("diagnostic.h", "")) # Add the list of files in reverse order since it is processed as a stack later for i in order: process_stack.insert (0, (i, "") ) # build up the library of what header files include what other files. while process_stack: info = process_stack.pop () process_one (info) # Now create the master ordering list for i in order: create_master_list (os.path.basename (i), show_master) # handle warts in the duplicate list process_known_dups () desired_order = master_list if show_master: print " Canonical order of gcc include files: " for x in master_list: print x print " " if usage: print "gcc-order-headers [-i] [-v] file1 [filen]" print " Ensures gcc's headers files are included in a normalized form with" print " redundant headers removed. The original files are saved in filename.bak" print " Outputs a list of files which changed." print " -i ignore conditional compilation." print " Use after examining the file to be sure includes within #ifs are safe" print " Any headers within conditional sections will be ignored." print " -v Show the canonical order of known headers" sys.exit(0) didnt_do = list () for fn in file_list: nest = 0 src_h = list () src_line = { } master_list = list () includes = { } dups = { } iinfo = process_ii_src (fn) src = ii_src (iinfo) include_list = ii_include_list (iinfo) if ii_include_list_cond (iinfo): if not ignore_conditional: print fn + ": Cannot process due to conditional compilation of includes" didnt_do.append (fn) src = list () if not src: continue process_stack = list () # prime the stack with headers in the main ordering list so we get them in # this order. for d in order: if d in include_list: process_stack.insert (0, (d, "")) for d in include_list: nm = os.path.basename(d) src_h.append (nm) iname = d iname2 = os.path.dirname (fn) + "/" + d if not os.path.exists (d) and os.path.exists (iname2): iname = iname2 if iname not in process_stack: process_stack.insert (0, (iname, "")) src_line[nm] = ii_src_line(iinfo)[d] if src_line[nm].find("/*") != -1 and src_line[nm].find("*/") == -1: # this means we have a multi line comment, abort!' print fn + ": Cannot process due to a multi-line comment :" print " " + src_line[nm] if fn not in didnt_do: didnt_do.append (fn) src = list () if not src: continue # Now create the list of includes as seen by the source file. while process_stack: info = process_stack.pop () process_one (info) for i in include_list: create_master_list (os.path.basename (i), False) new_src = list () header_added = list () new_order = list () for line in src: d = find_pound_include (line, True, True) if not d or d[-2:] != ".h": new_src.append (line) else: if d == order[0] and not new_order: new_order = get_new_order (src_h, desired_order) for i in new_order: new_src.append (src_line[i]) # if not seen, add it. if i not in header_added: header_added.append (i) else: nm = os.path.basename(d) if nm not in header_added: iby = indirectly_included (nm, src_h) if not iby: new_src.append (line) header_added.append (nm) if src != new_src: os.rename (fn, fn + ".bak") fl = open(fn,"w") for line in new_src: fl.write (line) fl.close () print fn if didnt_do: print "\n\n Did not process the following files due to conditional dependencies:" str = "" for x in didnt_do: str += x + " " print str print "\n" print "Please examine to see if they are safe to process, and re-try with -i. " print "Safeness is determined by checking whether any of the reordered headers are" print "within a conditional and could be hauled out of the conditional, thus changing" print "what the compiler will see." print "Multi-line comments after a #include can also cause failuer, they must be turned" print "into single line comments or removed."