| #! /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." |
| |
| |
| |
| |