1*f9a78e0eSmrg#! /usr/bin/python2 2*f9a78e0eSmrgimport os 3*f9a78e0eSmrgimport sys 4*f9a78e0eSmrgimport shlex 5*f9a78e0eSmrgimport re 6*f9a78e0eSmrg 7*f9a78e0eSmrgfrom headerutils import * 8*f9a78e0eSmrgimport Queue 9*f9a78e0eSmrg 10*f9a78e0eSmrgfile_list = list () 11*f9a78e0eSmrgusage = False 12*f9a78e0eSmrg 13*f9a78e0eSmrgignore_conditional = False 14*f9a78e0eSmrg 15*f9a78e0eSmrgorder = [ 16*f9a78e0eSmrg "system.h", 17*f9a78e0eSmrg "coretypes.h", 18*f9a78e0eSmrg "backend.h", 19*f9a78e0eSmrg "target.h", 20*f9a78e0eSmrg "rtl.h", 21*f9a78e0eSmrg "c-family/c-target.h", 22*f9a78e0eSmrg "c-family/c-target-def.h", 23*f9a78e0eSmrg "tree.h", 24*f9a78e0eSmrg "cp/cp-tree.h", 25*f9a78e0eSmrg "c-family/c-common.h", # these must come before diagnostic.h 26*f9a78e0eSmrg "c/c-tree.h", 27*f9a78e0eSmrg "fortran/gfortran.h", 28*f9a78e0eSmrg "gimple.h", 29*f9a78e0eSmrg "cfghooks.h", 30*f9a78e0eSmrg "df.h", 31*f9a78e0eSmrg "tm_p.h", 32*f9a78e0eSmrg "gimple-iterators.h", 33*f9a78e0eSmrg "ssa.h", 34*f9a78e0eSmrg "expmed.h", 35*f9a78e0eSmrg "optabs.h", 36*f9a78e0eSmrg "regs.h", 37*f9a78e0eSmrg "ira.h", 38*f9a78e0eSmrg "ira-int.h", 39*f9a78e0eSmrg "gimple-streamer.h" 40*f9a78e0eSmrg 41*f9a78e0eSmrg] 42*f9a78e0eSmrg 43*f9a78e0eSmrgexclude_special = [ "bversion.h", "obstack.h", "insn-codes.h", "hooks.h" ] 44*f9a78e0eSmrg 45*f9a78e0eSmrg# includes is a dictionary indexed by a header files basename. 46*f9a78e0eSmrg# it consists of a 2 element tuple: 47*f9a78e0eSmrg# [0] - Name of header file which included this header. 48*f9a78e0eSmrg# [1] - vector of header file names included by this file. 49*f9a78e0eSmrg 50*f9a78e0eSmrgincludes = { } 51*f9a78e0eSmrg 52*f9a78e0eSmrg# when a header is included multiple times, indexing this dictionary will 53*f9a78e0eSmrg# return a vector of all the headers which included it. 54*f9a78e0eSmrgdups = { } 55*f9a78e0eSmrg 56*f9a78e0eSmrg# When creating the master list, do not descend into these files for what 57*f9a78e0eSmrg# they include. Simply put the file itself in the list. This is primarily 58*f9a78e0eSmrg# required because the front end files inlcude orders tend to be at odds with 59*f9a78e0eSmrg# the order of middle end files, and its impossible to synchronize them.\ 60*f9a78e0eSmrg# They are ordered such that everything resolves properly. 61*f9a78e0eSmrgexclude_processing = [ "tree-vectorizer.h" , "c-target.h", "c-target-def.h", "cp-tree.h", "c-common.h", "c-tree.h", "gfortran.h" ] 62*f9a78e0eSmrg 63*f9a78e0eSmrgmaster_list = list () 64*f9a78e0eSmrg# where include file comes from in src 65*f9a78e0eSmrgh_from = { } 66*f9a78e0eSmrg 67*f9a78e0eSmrg# create the master ordering list... this is the desired order of headers 68*f9a78e0eSmrgdef create_master_list (fn, verbose): 69*f9a78e0eSmrg if fn not in exclude_processing: 70*f9a78e0eSmrg for x in includes[fn][1]: 71*f9a78e0eSmrg create_master_list (x, verbose) 72*f9a78e0eSmrg if not fn in master_list: 73*f9a78e0eSmrg # Don't put diagnostic*.h into the ordering list. It is special since 74*f9a78e0eSmrg # various front ends have to set GCC_DIAG_STYLE before including it. 75*f9a78e0eSmrg # for each file, we'll tailor where it belongs by looking at the include 76*f9a78e0eSmrg # list and determine its position appropriately. 77*f9a78e0eSmrg if fn != "diagnostic.h" and fn != "diagnostic-core.h": 78*f9a78e0eSmrg master_list.append (fn) 79*f9a78e0eSmrg if (verbose): 80*f9a78e0eSmrg print fn + " included by: " + includes[fn][0] 81*f9a78e0eSmrg 82*f9a78e0eSmrg 83*f9a78e0eSmrg 84*f9a78e0eSmrgdef print_dups (): 85*f9a78e0eSmrg if dups: 86*f9a78e0eSmrg print "\nduplicated includes" 87*f9a78e0eSmrg for i in dups: 88*f9a78e0eSmrg string = "dup : " + i + " : " 89*f9a78e0eSmrg string += includes[i][0] 90*f9a78e0eSmrg for i2 in dups[i]: 91*f9a78e0eSmrg string += ", "+i2 92*f9a78e0eSmrg print string 93*f9a78e0eSmrg 94*f9a78e0eSmrg 95*f9a78e0eSmrgdef process_known_dups (): 96*f9a78e0eSmrg # rtl.h gets tagged as a duplicate includer for all of coretypes.h, but that 97*f9a78e0eSmrg # is really for only generator files 98*f9a78e0eSmrg rtl_remove = includes["coretypes.h"][1] + ["statistics.h", "vec.h"] 99*f9a78e0eSmrg if dups: 100*f9a78e0eSmrg for i in rtl_remove: 101*f9a78e0eSmrg if dups[i] and "rtl.h" in dups[i]: 102*f9a78e0eSmrg dups[i].remove("rtl.h") 103*f9a78e0eSmrg if not dups[i]: 104*f9a78e0eSmrg dups.pop (i, None) 105*f9a78e0eSmrg 106*f9a78e0eSmrg # make sure diagnostic.h is the owner of diagnostic-core.h 107*f9a78e0eSmrg if includes["diagnostic-core.h"][0] != "diagnostic.h": 108*f9a78e0eSmrg dups["diagnostic-core.h"].append (includes["diagnostic-core.h"][0]) 109*f9a78e0eSmrg includes["diagnostic-core.h"] = ("diagnostic.h", includes["diagnostic-core.h"][1]) 110*f9a78e0eSmrg 111*f9a78e0eSmrg# This function scans back thorugh the list of headers which included other 112*f9a78e0eSmrg# headers to determine what file in HEADER_LIST brought 'HEADER' in. 113*f9a78e0eSmrgdef indirectly_included (header, header_list): 114*f9a78e0eSmrg nm = os.path.basename (header) 115*f9a78e0eSmrg while nm and includes.get(nm): 116*f9a78e0eSmrg if includes[nm][0] in header_list: 117*f9a78e0eSmrg return includes[nm][0] 118*f9a78e0eSmrg nm = includes[nm][0] 119*f9a78e0eSmrg 120*f9a78e0eSmrg # diagnostic.h and diagnostic-core.h may not show up because we removed them 121*f9a78e0eSmrg # from the header list to manually position in an appropriate place. They have 122*f9a78e0eSmrg # specific requirements that they need to occur after certain FE files which 123*f9a78e0eSmrg # may overide the definition of GCC_DIAG_STYLE. 124*f9a78e0eSmrg # Check the dup list for whete they may have been included from and return 125*f9a78e0eSmrg # that header. 126*f9a78e0eSmrg if header == "diagnostic-core.h": 127*f9a78e0eSmrg if dups.get("diagnostic-core.h"): 128*f9a78e0eSmrg for f in dups["diagnostic-core.h"]: 129*f9a78e0eSmrg if f in header_list: 130*f9a78e0eSmrg return f 131*f9a78e0eSmrg else: 132*f9a78e0eSmrg if header in header_list: 133*f9a78e0eSmrg return header 134*f9a78e0eSmrg # Now check if diagnostics is included indirectly anywhere 135*f9a78e0eSmrg header = "diagnostic.h" 136*f9a78e0eSmrg 137*f9a78e0eSmrg if header == "diagnostic.h": 138*f9a78e0eSmrg if dups.get("diagnostic.h"): 139*f9a78e0eSmrg for f in dups["diagnostic.h"]: 140*f9a78e0eSmrg if f in header_list: 141*f9a78e0eSmrg return f 142*f9a78e0eSmrg else: 143*f9a78e0eSmrg if header in header_list: 144*f9a78e0eSmrg return header 145*f9a78e0eSmrg 146*f9a78e0eSmrg return "" 147*f9a78e0eSmrg 148*f9a78e0eSmrg 149*f9a78e0eSmrg# This function will take a list of headers from a source file and return 150*f9a78e0eSmrg# the desired new new order of the canonical headers in DESIRED_ORDER. 151*f9a78e0eSmrgdef get_new_order (src_h, desired_order): 152*f9a78e0eSmrg new_order = list () 153*f9a78e0eSmrg for h in desired_order: 154*f9a78e0eSmrg if h in master_list: 155*f9a78e0eSmrg # Create the list of nested headers which included this file. 156*f9a78e0eSmrg iclist = list () 157*f9a78e0eSmrg ib = includes[h][0] 158*f9a78e0eSmrg while ib: 159*f9a78e0eSmrg iclist.insert(0, ib) 160*f9a78e0eSmrg ib = includes[ib][0] 161*f9a78e0eSmrg if iclist: 162*f9a78e0eSmrg for x in iclist: 163*f9a78e0eSmrg # If header is in the source code, and we are allowed to look inside 164*f9a78e0eSmrg if x in src_h and x not in exclude_processing: 165*f9a78e0eSmrg if x not in new_order and x[:10] != "diagnostic" and h not in exclude_special: 166*f9a78e0eSmrg new_order.append (x) 167*f9a78e0eSmrg break; 168*f9a78e0eSmrg else: 169*f9a78e0eSmrg if h not in new_order: 170*f9a78e0eSmrg new_order.append (h) 171*f9a78e0eSmrg 172*f9a78e0eSmrg f = "" 173*f9a78e0eSmrg if "diagnostic.h" in src_h: 174*f9a78e0eSmrg f = "diagnostic.h" 175*f9a78e0eSmrg elif "diagnostic-core.h" in src_h: 176*f9a78e0eSmrg f = "diagnostic-core.h" 177*f9a78e0eSmrg 178*f9a78e0eSmrg 179*f9a78e0eSmrg # If either diagnostic header was directly included in the main file, check to 180*f9a78e0eSmrg # see if its already included indirectly, or whether we need to add it to the 181*f9a78e0eSmrg # end of the canonically orders headers. 182*f9a78e0eSmrg if f: 183*f9a78e0eSmrg ii = indirectly_included (f, src_h) 184*f9a78e0eSmrg if not ii or ii == f: 185*f9a78e0eSmrg new_order.append (f) 186*f9a78e0eSmrg 187*f9a78e0eSmrg return new_order 188*f9a78e0eSmrg 189*f9a78e0eSmrg 190*f9a78e0eSmrg 191*f9a78e0eSmrg# stack of files to process 192*f9a78e0eSmrgprocess_stack = list () 193*f9a78e0eSmrg 194*f9a78e0eSmrgdef process_one (info): 195*f9a78e0eSmrg i = info[0] 196*f9a78e0eSmrg owner = info[1] 197*f9a78e0eSmrg name = os.path.basename(i) 198*f9a78e0eSmrg if os.path.exists (i): 199*f9a78e0eSmrg if includes.get(name) == None: 200*f9a78e0eSmrg l = find_unique_include_list (i) 201*f9a78e0eSmrg # create a list which has just basenames in it 202*f9a78e0eSmrg new_list = list () 203*f9a78e0eSmrg for x in l: 204*f9a78e0eSmrg new_list.append (os.path.basename (x)) 205*f9a78e0eSmrg process_stack.append((x, name)) 206*f9a78e0eSmrg includes[name] = (owner, new_list) 207*f9a78e0eSmrg elif owner: 208*f9a78e0eSmrg if dups.get(name) == None: 209*f9a78e0eSmrg dups[name] = [ owner ] 210*f9a78e0eSmrg else: 211*f9a78e0eSmrg dups[name].append (owner) 212*f9a78e0eSmrg else: 213*f9a78e0eSmrg # seed tm.h with options.h since it is a build file and won't be seen. 214*f9a78e0eSmrg if not includes.get(name): 215*f9a78e0eSmrg if name == "tm.h": 216*f9a78e0eSmrg includes[name] = (owner, [ "options.h" ]) 217*f9a78e0eSmrg includes["options.h"] = ("tm.h", list ()) 218*f9a78e0eSmrg else: 219*f9a78e0eSmrg includes[name] = (owner, list ()) 220*f9a78e0eSmrg 221*f9a78e0eSmrg 222*f9a78e0eSmrgshow_master = False 223*f9a78e0eSmrg 224*f9a78e0eSmrgfor arg in sys.argv[1:]: 225*f9a78e0eSmrg if arg[0:1] == "-": 226*f9a78e0eSmrg if arg[0:2] == "-h": 227*f9a78e0eSmrg usage = True 228*f9a78e0eSmrg elif arg[0:2] == "-i": 229*f9a78e0eSmrg ignore_conditional = True 230*f9a78e0eSmrg elif arg[0:2] == "-v": 231*f9a78e0eSmrg show_master = True 232*f9a78e0eSmrg else: 233*f9a78e0eSmrg print "Error: unrecognized option " + arg 234*f9a78e0eSmrg elif os.path.exists(arg): 235*f9a78e0eSmrg file_list.append (arg) 236*f9a78e0eSmrg else: 237*f9a78e0eSmrg print "Error: file " + arg + " Does not exist." 238*f9a78e0eSmrg usage = True 239*f9a78e0eSmrg 240*f9a78e0eSmrgif not file_list and not show_master: 241*f9a78e0eSmrg usage = True 242*f9a78e0eSmrg 243*f9a78e0eSmrgif not usage and not os.path.exists ("coretypes.h"): 244*f9a78e0eSmrg usage = True 245*f9a78e0eSmrg print "Error: Must run command in main gcc source directory containing coretypes.h\n" 246*f9a78e0eSmrg 247*f9a78e0eSmrg# process diagnostic.h first.. it's special since GCC_DIAG_STYLE can be 248*f9a78e0eSmrg# overridden by languages, but must be done so by a file included BEFORE it. 249*f9a78e0eSmrg# so make sure it isn't seen as included by one of those files by making it 250*f9a78e0eSmrg# appear to be included by the src file. 251*f9a78e0eSmrgprocess_stack.insert (0, ("diagnostic.h", "")) 252*f9a78e0eSmrg 253*f9a78e0eSmrg# Add the list of files in reverse order since it is processed as a stack later 254*f9a78e0eSmrgfor i in order: 255*f9a78e0eSmrg process_stack.insert (0, (i, "") ) 256*f9a78e0eSmrg 257*f9a78e0eSmrg# build up the library of what header files include what other files. 258*f9a78e0eSmrgwhile process_stack: 259*f9a78e0eSmrg info = process_stack.pop () 260*f9a78e0eSmrg process_one (info) 261*f9a78e0eSmrg 262*f9a78e0eSmrg# Now create the master ordering list 263*f9a78e0eSmrgfor i in order: 264*f9a78e0eSmrg create_master_list (os.path.basename (i), show_master) 265*f9a78e0eSmrg 266*f9a78e0eSmrg# handle warts in the duplicate list 267*f9a78e0eSmrgprocess_known_dups () 268*f9a78e0eSmrgdesired_order = master_list 269*f9a78e0eSmrg 270*f9a78e0eSmrgif show_master: 271*f9a78e0eSmrg print " Canonical order of gcc include files: " 272*f9a78e0eSmrg for x in master_list: 273*f9a78e0eSmrg print x 274*f9a78e0eSmrg print " " 275*f9a78e0eSmrg 276*f9a78e0eSmrgif usage: 277*f9a78e0eSmrg print "gcc-order-headers [-i] [-v] file1 [filen]" 278*f9a78e0eSmrg print " Ensures gcc's headers files are included in a normalized form with" 279*f9a78e0eSmrg print " redundant headers removed. The original files are saved in filename.bak" 280*f9a78e0eSmrg print " Outputs a list of files which changed." 281*f9a78e0eSmrg print " -i ignore conditional compilation." 282*f9a78e0eSmrg print " Use after examining the file to be sure includes within #ifs are safe" 283*f9a78e0eSmrg print " Any headers within conditional sections will be ignored." 284*f9a78e0eSmrg print " -v Show the canonical order of known headers" 285*f9a78e0eSmrg sys.exit(0) 286*f9a78e0eSmrg 287*f9a78e0eSmrg 288*f9a78e0eSmrgdidnt_do = list () 289*f9a78e0eSmrg 290*f9a78e0eSmrgfor fn in file_list: 291*f9a78e0eSmrg nest = 0 292*f9a78e0eSmrg src_h = list () 293*f9a78e0eSmrg src_line = { } 294*f9a78e0eSmrg 295*f9a78e0eSmrg master_list = list () 296*f9a78e0eSmrg 297*f9a78e0eSmrg includes = { } 298*f9a78e0eSmrg dups = { } 299*f9a78e0eSmrg 300*f9a78e0eSmrg iinfo = process_ii_src (fn) 301*f9a78e0eSmrg src = ii_src (iinfo) 302*f9a78e0eSmrg include_list = ii_include_list (iinfo) 303*f9a78e0eSmrg 304*f9a78e0eSmrg if ii_include_list_cond (iinfo): 305*f9a78e0eSmrg if not ignore_conditional: 306*f9a78e0eSmrg print fn + ": Cannot process due to conditional compilation of includes" 307*f9a78e0eSmrg didnt_do.append (fn) 308*f9a78e0eSmrg src = list () 309*f9a78e0eSmrg 310*f9a78e0eSmrg if not src: 311*f9a78e0eSmrg continue 312*f9a78e0eSmrg 313*f9a78e0eSmrg process_stack = list () 314*f9a78e0eSmrg # prime the stack with headers in the main ordering list so we get them in 315*f9a78e0eSmrg # this order. 316*f9a78e0eSmrg for d in order: 317*f9a78e0eSmrg if d in include_list: 318*f9a78e0eSmrg process_stack.insert (0, (d, "")) 319*f9a78e0eSmrg 320*f9a78e0eSmrg for d in include_list: 321*f9a78e0eSmrg nm = os.path.basename(d) 322*f9a78e0eSmrg src_h.append (nm) 323*f9a78e0eSmrg iname = d 324*f9a78e0eSmrg iname2 = os.path.dirname (fn) + "/" + d 325*f9a78e0eSmrg if not os.path.exists (d) and os.path.exists (iname2): 326*f9a78e0eSmrg iname = iname2 327*f9a78e0eSmrg if iname not in process_stack: 328*f9a78e0eSmrg process_stack.insert (0, (iname, "")) 329*f9a78e0eSmrg src_line[nm] = ii_src_line(iinfo)[d] 330*f9a78e0eSmrg if src_line[nm].find("/*") != -1 and src_line[nm].find("*/") == -1: 331*f9a78e0eSmrg # this means we have a multi line comment, abort!' 332*f9a78e0eSmrg print fn + ": Cannot process due to a multi-line comment :" 333*f9a78e0eSmrg print " " + src_line[nm] 334*f9a78e0eSmrg if fn not in didnt_do: 335*f9a78e0eSmrg didnt_do.append (fn) 336*f9a78e0eSmrg src = list () 337*f9a78e0eSmrg 338*f9a78e0eSmrg if not src: 339*f9a78e0eSmrg continue 340*f9a78e0eSmrg 341*f9a78e0eSmrg # Now create the list of includes as seen by the source file. 342*f9a78e0eSmrg while process_stack: 343*f9a78e0eSmrg info = process_stack.pop () 344*f9a78e0eSmrg process_one (info) 345*f9a78e0eSmrg 346*f9a78e0eSmrg for i in include_list: 347*f9a78e0eSmrg create_master_list (os.path.basename (i), False) 348*f9a78e0eSmrg 349*f9a78e0eSmrg new_src = list () 350*f9a78e0eSmrg header_added = list () 351*f9a78e0eSmrg new_order = list () 352*f9a78e0eSmrg for line in src: 353*f9a78e0eSmrg d = find_pound_include (line, True, True) 354*f9a78e0eSmrg if not d or d[-2:] != ".h": 355*f9a78e0eSmrg new_src.append (line) 356*f9a78e0eSmrg else: 357*f9a78e0eSmrg if d == order[0] and not new_order: 358*f9a78e0eSmrg new_order = get_new_order (src_h, desired_order) 359*f9a78e0eSmrg for i in new_order: 360*f9a78e0eSmrg new_src.append (src_line[i]) 361*f9a78e0eSmrg # if not seen, add it. 362*f9a78e0eSmrg if i not in header_added: 363*f9a78e0eSmrg header_added.append (i) 364*f9a78e0eSmrg else: 365*f9a78e0eSmrg nm = os.path.basename(d) 366*f9a78e0eSmrg if nm not in header_added: 367*f9a78e0eSmrg iby = indirectly_included (nm, src_h) 368*f9a78e0eSmrg if not iby: 369*f9a78e0eSmrg new_src.append (line) 370*f9a78e0eSmrg header_added.append (nm) 371*f9a78e0eSmrg 372*f9a78e0eSmrg if src != new_src: 373*f9a78e0eSmrg os.rename (fn, fn + ".bak") 374*f9a78e0eSmrg fl = open(fn,"w") 375*f9a78e0eSmrg for line in new_src: 376*f9a78e0eSmrg fl.write (line) 377*f9a78e0eSmrg fl.close () 378*f9a78e0eSmrg print fn 379*f9a78e0eSmrg 380*f9a78e0eSmrg 381*f9a78e0eSmrgif didnt_do: 382*f9a78e0eSmrg print "\n\n Did not process the following files due to conditional dependencies:" 383*f9a78e0eSmrg str = "" 384*f9a78e0eSmrg for x in didnt_do: 385*f9a78e0eSmrg str += x + " " 386*f9a78e0eSmrg print str 387*f9a78e0eSmrg print "\n" 388*f9a78e0eSmrg print "Please examine to see if they are safe to process, and re-try with -i. " 389*f9a78e0eSmrg print "Safeness is determined by checking whether any of the reordered headers are" 390*f9a78e0eSmrg print "within a conditional and could be hauled out of the conditional, thus changing" 391*f9a78e0eSmrg print "what the compiler will see." 392*f9a78e0eSmrg print "Multi-line comments after a #include can also cause failuer, they must be turned" 393*f9a78e0eSmrg print "into single line comments or removed." 394*f9a78e0eSmrg 395*f9a78e0eSmrg 396*f9a78e0eSmrg 397*f9a78e0eSmrg 398