summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2010-12-09 12:01:52 -0500
committerEric S. Raymond <esr@thyrsus.com>2010-12-09 12:01:52 -0500
commite59590bbfaff0fc973236eb5f069bc1e157106a5 (patch)
tree0a73df46ce7cd0455e49507298ae84f3075f1f6c
parentebf834d064115e67b6d1050b2cd3d6532201227a (diff)
downloaddeheader-e59590bbfaff0fc973236eb5f069bc1e157106a5.tar.gz
deheader-e59590bbfaff0fc973236eb5f069bc1e157106a5.tar.bz2
deheader-e59590bbfaff0fc973236eb5f069bc1e157106a5.tar.xz
deheader-e59590bbfaff0fc973236eb5f069bc1e157106a5.zip
Infrastructure for dependency rules.
-rwxr-xr-xdeheader40
1 files changed, 31 insertions, 9 deletions
diff --git a/deheader b/deheader
index 243b868..3a05778 100755
--- a/deheader
+++ b/deheader
@@ -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