diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2010-12-09 12:01:52 -0500 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2010-12-09 12:01:52 -0500 |
commit | e59590bbfaff0fc973236eb5f069bc1e157106a5 (patch) | |
tree | 0a73df46ce7cd0455e49507298ae84f3075f1f6c | |
parent | ebf834d064115e67b6d1050b2cd3d6532201227a (diff) | |
download | deheader-e59590bbfaff0fc973236eb5f069bc1e157106a5.tar.gz deheader-e59590bbfaff0fc973236eb5f069bc1e157106a5.tar.bz2 deheader-e59590bbfaff0fc973236eb5f069bc1e157106a5.tar.xz deheader-e59590bbfaff0fc973236eb5f069bc1e157106a5.zip |
Infrastructure for dependency rules.
-rwxr-xr-x | deheader | 40 |
1 files changed, 31 insertions, 9 deletions
@@ -34,6 +34,16 @@ COMMAND_DEBUG = 3 version = "0.2" +# Difference in various compiler implementations and OSes mean that for cross- +# platform compatibility you sometimes wabt to leave "unneeded" headers alone +# because they're required in order to satify dependencies on other platforms. +# We list those here. Home port is Linux; these are mostly extracted from +# observing compiles on BSD systems. +requirements = map(lambda (r, h): (re.compile(r), h), ( + (r"umask\s*\(", ["<sys/stat.h>", "<sys/types.h>"]), + (r"<sys/socket.h>", ["<sys/stat.h>"]), + )) + class Baton: "Ship progress indications to stderr." def __init__(self, prompt, endmsg=None): @@ -91,8 +101,10 @@ class InclusionMap: if InclusionMap.c_source(path): self.files.append(path) self.depends_on = {} + self.requires = {} for sourcefile in self.files: includes = [] + requires = [] ifdepth = 0 for line in open(sourcefile): if line.startswith("#if") or line.startswith("#ifndef"): @@ -111,7 +123,11 @@ class InclusionMap: includes.append(line) elif verbose > 1: print "deheader: ignoring %s (conditional inclusion)" % name + for (r, h) in requirements: + if r.search(line): + requires += line self.depends_on[sourcefile] = includes + self.requires[sourcefile] = requires def forget(self, sourcefile, header): "Forget a header dependency." self.depends_on[sourcefile].remove(header) @@ -125,11 +141,11 @@ class SaveForModification: self.filename = filename self.original = filename + "-orig" os.rename(self.filename, self.original) - def remove_headers(self, headers): + def remove_headers(self, removables): "Prepare a version with specified headers deleted." ofp = open(self.filename, "w") for line in open(self.original): - if line not in headers: + if line not in removables: ofp.write(line) ofp.close() def forget(self): @@ -177,7 +193,7 @@ def testcompile(source, maker, msg="", verbosity=0): % (sourcefile, msg, explain, end-start) return (status, end - start) -def c_analyze(sourcefile, maker, includes, verbosity): +def c_analyze(sourcefile, maker, includes, requires, verbosity): "Given a C file and a list of includes, return those that can be omitted." # We'll remove headers in reverse order, because later unnecessary # headers might depend on earlier ones @@ -190,14 +206,16 @@ def c_analyze(sourcefile, maker, includes, verbosity): while True: keepgoing = False for header in includes: + if verbosity == BATON_DEBUG: + baton.twirl() + if header in requires: + continue saveit.remove_headers([header]) (st, t) = testcompile(sourcefile, maker, " without %s" % trim(header), verbosity) if st == 0: unneeded.append(header) includes.remove(header) keepgoing = True - if verbosity == BATON_DEBUG: - baton.twirl() if not keepgoing: break finally: @@ -206,20 +224,21 @@ def c_analyze(sourcefile, maker, includes, verbosity): baton.end() return unneeded -def deheader(sourcefile, maker, includes, remove, verbose): +def deheader(sourcefile, maker, includes, requires, remove, verbose): # Sanity check against broken sourcefiles; we want this to # complain visibly if the sourcefile won't build at all. (st, t) = testcompile(sourcefile, maker, min(1, verbose)) if st == 0: # Now do the analysis if sourcefile.endswith(".c") or sourcefile.endswith(".cpp"): - unneeded = c_analyze(sourcefile, maker, includes[:], verbose) + unneeded = c_analyze(sourcefile, maker, + includes[:], requires[:], verbose) if unneeded: for line in unneeded: print "deheader: remove %s from %s" % (trim(line), sourcefile) if remove: remove_it = SaveForModification(sourcefile) - remove_it.remove_headers(unneeded) + remove_it.remove_headers(unneeded, requires) remove_it.forget() del remove_it return Summary([sourcefile], includes, unneeded) @@ -277,7 +296,10 @@ if __name__ == "__main__": inclusion_map = InclusionMap(arguments, ignore, verbose) summaries = [] for sourcefile in inclusion_map.depends_on: - summaries.append(deheader(sourcefile, maker, inclusion_map.depends_on[sourcefile], remove, verbose)) + summaries.append(deheader(sourcefile, maker, + inclusion_map.depends_on[sourcefile], + inclusion_map.requires[sourcefile], + remove, verbose)) stats = Summary() for summary in summaries: stats = stats + summary |