Commit ee48c93e authored by Reiner Herrmann's avatar Reiner Herrmann

Merge tag 'upstream/1.3'

Upstream version 1.3

# gpg: Signature made Wed 13 Jan 2016 07:07:50 PM CET using RSA key ID DB0EEAA7
# gpg: Good signature from "Reiner Herrmann <reiner@reiner-h.de>" [ultimate]
# Primary key fingerprint: 2F5D AF3F C1F7 93D9 4F3D  900C A721 DA05 5374 AA4F
#      Subkey fingerprint: D8F6 FA7D EA24 D90D 6EAC  733B CCF0 4928 DB0E EAA7
parents 7a06d86b ee2b82d3
BSD LICENSE
Copyright (c) 2015, Eric S. Raymond
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
modification, are permitted provided that the following conditions are
met:
Redistributions of source code must retain the above copyright
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither name of the this project nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
deheader project news
1.3 @ 2016-01-12
When compilation fails, also try it directly inside subdirectories.
1.2 @ 2015-07-18
Notice preprocessor directives with whitespace after the hash-mark
......
......@@ -29,14 +29,15 @@ on interrupt or after processing with its original timestamp, unless the
The last line of the output is a statistical summary of operations.
"""
# SPDX-License-Identifier: BSD-2-Clause
import sys, os, getopt, time, re, operator, commands
import sys, os, getopt, time, re, operator, commands, subprocess
BATON_DEBUG = 1
PROGRESS_DEBUG = 2
COMMAND_DEBUG = 3
version = "1.2"
version = "1.3"
# Difference in various compiler implementations and OSes mean that for cross-
# platform compatibility you sometimes want to leave "unneeded" headers alone
......@@ -1353,16 +1354,22 @@ def trim(line):
else:
return repr(line)
def testcompile(source, maker, msg="", verbosity=0, showerrs=False):
def testcompile(source, maker, msg="", verbosity=0, showerrs=False, subdir=""):
"Test-compile a sourcefile. Return the status and the compilation time"
(stem, _suffix) = os.path.splitext(source)
derived = stem + ".o"
if os.path.exists(derived):
os.remove(derived)
if os.path.exists(os.path.join(subdir, derived)):
os.remove(os.path.join(subdir, derived))
elif os.path.exists("CMakeList.txt"):
subprocess.call(["make","clean"])
command = maker + " " + derived
olddir = os.getcwd()
if len(subdir) > 0:
os.chdir(subdir)
start = time.time()
(status, output) = commands.getstatusoutput(command)
end = time.time()
os.chdir(olddir)
if verbosity >= COMMAND_DEBUG or (showerrs and os.WIFEXITED(status) and os.WEXITSTATUS(status) != 0):
sys.stdout.write(output + "\n")
if status:
......@@ -1375,9 +1382,11 @@ def testcompile(source, maker, msg="", verbosity=0, showerrs=False):
print "deheader: %s%s %s." % (source, msg, explain)
if os.path.exists(derived):
os.remove(derived)
elif os.path.exists("CMakeList.txt"):
subprocess.call(["make","clean"])
return (status, end - start)
def c_analyze(sourcefile, maker, includes, requires, verbosity):
def c_analyze(sourcefile, maker, includes, requires, verbosity, subdir=""):
"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
......@@ -1386,10 +1395,10 @@ def c_analyze(sourcefile, maker, includes, requires, verbosity):
if verbosity == BATON_DEBUG:
baton = Baton(sourcefile + ": ", "Done")
try:
saveit = SaveForModification(sourcefile)
saveit = SaveForModification(os.path.join(subdir, sourcefile))
while True:
keepgoing = False
for header in includes:
for header in includes[:]:
if verbosity == BATON_DEBUG:
baton.twirl()
retain = 0
......@@ -1397,11 +1406,11 @@ def c_analyze(sourcefile, maker, includes, requires, verbosity):
for required in requirements:
if required in header:
if verbosity >= PROGRESS_DEBUG:
print "deheader: in %s, %s prevents uninclusion of %s" % (sourcefile, trigger, trim(header))
print "deheader: in %s, %s prevents uninclusion of %s" % (os.path.join(subdir, sourcefile), trigger, trim(header))
retain += 1
if not retain:
saveit.remove_headers([header])
(st, _t) = testcompile(sourcefile, maker, " without %s" % trim(header), verbosity, showerrs=False)
saveit.remove_headers(unneeded + [header])
(st, _t) = testcompile(sourcefile, maker, " without %s" % trim(header), verbosity, showerrs=False, subdir=subdir)
if st == 0:
unneeded.append(header)
includes.remove(header)
......@@ -1417,23 +1426,28 @@ def c_analyze(sourcefile, maker, includes, requires, verbosity):
stillhere = map(trim, includes)
for (requirement, trigger) in requires:
if not set(requirement).issubset(stillhere):
print "deheader: in %s, %s portability requires %s." % (sourcefile, trigger, ",".join(requirement))
print "deheader: in %s, %s portability requires %s." % (os.path.join(subdir, sourcefile), trigger, ",".join(requirement))
return unneeded
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, verbosity=max(1, verbose), showerrs=True)
subdir = ""
(st, _t) = testcompile(sourcefile, maker, verbosity=max(1, verbose), showerrs=False)
if st != 0:
subdir = os.path.dirname(sourcefile)
sourcefile = os.path.basename(sourcefile)
(st, _t) = testcompile(sourcefile, maker, verbosity=max(1, verbose), showerrs=True, subdir=subdir)
if st == 0:
# Now do the analysis
if sourcefile.endswith(".c") or sourcefile.endswith(".cpp") or sourcefile.endswith(".cc"):
unneeded = c_analyze(sourcefile, maker,
includes[:], requires, verbose)
includes[:], requires, verbose, subdir=subdir)
if unneeded:
for line in unneeded:
print "deheader: remove %s from %s" % (trim(line), sourcefile)
print "deheader: remove %s from %s" % (trim(line), os.path.join(subdir, sourcefile))
if remove:
remove_it = SaveForModification(sourcefile)
remove_it = SaveForModification(os.path.join(subdir, sourcefile))
remove_it.remove_headers(unneeded)
remove_it.forget()
del remove_it
......
......@@ -2,12 +2,12 @@
.\" Title: deheader
.\" Author: [see the "AUTHOR" section]
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
.\" Date: 01/26/2015
.\" Date: 01/12/2016
.\" Manual: Development Tools
.\" Source: deheader
.\" Language: English
.\"
.TH "DEHEADER" "1" "01/26/2015" "deheader" "Development Tools"
.TH "DEHEADER" "1" "01/12/2016" "deheader" "Development Tools"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
......@@ -34,7 +34,9 @@ deheader \- report which includes in C or C++ compiles can be removed
\fBdeheader\fR [\-h] [\-m\ \fIcommand\fR] [\-i\ \fIpattern\fR] [\-q] [\-r] [\-v] [\-x\ \fIpattern\fR] [\-V] [\fIfile\-or\-dir\fR]
.SH "DESCRIPTION"
.PP
This tool takes a list of C or C++ sourcefiles and generates a report on which #includes can be omitted from them; also, what standard inclusions may be required for portability\&. The test, for each foo\&.c or foo\&.cc or foo\&.cpp, is simply whether \*(Aqrm foo\&.o; make foo\&.o\*(Aq returns a zero status (but the build command may be overridden)\&.
This tool takes a list of C or C++ sourcefiles and generates a report on which #includes can be omitted from them; also, what standard inclusions may be required for portability\&. The test, for each foo\&.c or foo\&.cc or foo\&.cpp, is simply whether "rm foo\&.o; make foo\&.o" returns a zero status (but the build command may be overridden)\&.
.PP
Exception: Under cmake, foo\&.o is a phoney target\&. Therefore, when a "CMakeList\&.txt" is detected, "make clean" is done rather than "rm foo\&.o"\&.
.PP
Optionally, with the
\fB\-r\fR
......@@ -55,6 +57,8 @@ On each test compile, the original sourcefile is moved to a name with an \&.orig
\fB\-r\fR
option was given and headers removed\&.
.PP
If the first test compilation from the top\-level directory fails, deheader descends into the subdirectory of the source file and retries compiling inside there\&.
.PP
At verbosity level 0, only messages indicating removable headers are issued\&. At verbosity 1, test compilations are timed and progess indicated with a twirling\-baton prompt\&. At verbosity level 2, you get verbose progress messages on the analysis\&. At verbosity level 3, you see the output from the make and compilation commands\&.
.PP
If the \-q (\-\-quiet) option flag was not set, the last line of the output will be a statistical summary\&.
......
......@@ -36,10 +36,14 @@
<para>This tool takes a list of C or C++ sourcefiles and generates a
report on which #includes can be omitted from them; also, what
standard inclusions may be required for portability. The test, for
each foo.c or foo.cc or foo.cpp, is simply whether 'rm foo.o; make
foo.o' returns a zero status (but the build command may be
each foo.c or foo.cc or foo.cpp, is simply whether "rm foo.o; make
foo.o" returns a zero status (but the build command may be
overridden).</para>
<para>Exception: Under cmake, foo.o is a phoney target. Therefore,
when a "CMakeList.txt" is detected, "make clean" is done rather than
"rm foo.o".</para>
<para>Optionally, with the <option>-r</option> switch, the
unneeded headers are removed from the sourcefiles. Don't use
this option unless you have your sourcefiles safely under version
......@@ -77,6 +81,10 @@ with an .orig suffix and restored on interrupt or after processing
with its original timestamp, unless the <option>-r</option> option was
given and headers removed.</para>
<para>If the first test compilation from the top-level directory fails,
deheader descends into the subdirectory of the source file and retries
compiling inside there.</para>
<para>At verbosity level 0, only messages indicating removable headers
are issued. At verbosity 1, test compilations are timed and progess
indicated with a twirling-baton prompt. At verbosity level 2, you get
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment