| #! /usr/bin/python3 | |
| 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 failure, they must be turned") | |
| print ("into single line comments or removed.") | |