Add --debug=tree (print depenency tree) support
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 29 Dec 2001 08:43:48 +0000 (08:43 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 29 Dec 2001 08:43:48 +0000 (08:43 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@179 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Script/__init__.py
src/engine/SCons/Util.py
src/engine/SCons/UtilTests.py
test/option--debug.py [new file with mode: 0644]

index 38b196d057a891cfd6c5e641c971923c36c0c43c..ad8a8349a3e1c3d5448980e3ad9a7c4b3b2b24b6 100644 (file)
@@ -264,14 +264,20 @@ or
 .I sconstruct
 in the specified directory.)
 
-.IP -d
-Display dependencies while building target files.  Useful for
-figuring out why a specific file is being rebuilt, as well as
-general debugging of the build process.
+.\" .IP -d
+.\" Display dependencies while building target files.  Useful for
+.\" figuring out why a specific file is being rebuilt, as well as
+.\" general debugging of the build process.
 
-.\" .TP 
-.\" .RI --debug= flags
-.\"Print debugging information. ???
+.TP
+.RI --debug= type
+Print debugging information durring the build process.
+.I type
+specifies what type of of debugging information to print. Currently the
+only supported type is
+.I tree
+which causes the dependency tree to be printed after each top-level
+target is built.
 
 .IP "-e, --environment-overrides"
 Variables from the execution environment override construction
index c84d0cb4dbd9e2dabab412fff2c09377e5feb008..54dc2ad8e499d84ccb5a44e7d47086f0894148fa 100644 (file)
@@ -20,6 +20,8 @@ RELEASE 0.03 -
   - Add a "duplicate" keyword argument to BuildDir() that can be set
     to prevent linking/copying source files into build directories.
 
+  - Add a "--debug=tree" option to print an ASCII dependency tree.
+
 
 
 RELEASE 0.02 - Sun, 23 Dec 2001 19:05:09 -0600
index bb6799189364633e826558a28c615b44738a2c1f..3b5a79d1f3d17ed58363b7df1ab4feed6b6add9b 100644 (file)
@@ -71,9 +71,15 @@ class BuildTask(SCons.Taskmaster.Task):
         if self.target.get_state() == SCons.Node.up_to_date:
             if self.top:
                 print 'scons: "%s" is up to date.' % str(self.target)
+                if print_tree:
+                    print
+                    print SCons.Util.render_tree(self.target, get_children)
         else:
             try:
                 self.target.build()
+                if self.top and print_tree:
+                    print
+                    print SCons.Util.render_tree(self.target, get_children)
             except BuildError, e:
                 sys.stderr.write("scons: *** [%s] Error %s\n" % (e.node, str(e.stat)))
                 raise
@@ -106,9 +112,12 @@ calc = None
 ignore_errors = 0
 keep_going_on_error = 0
 help_option = None
+print_tree = 0
 
 # utility functions
 
+def get_children(node): return node.children()
+
 def _scons_syntax_error(e):
     """Handle syntax errors. Print out a message and show where the error
     occurred.
@@ -340,9 +349,17 @@ def options_init():
        short = 'd',
        help = "Print file dependency information.")
 
-    Option(func = opt_not_yet, future = 1,
-       long = ['debug'], arg = 'FLAGS',
-       help = "Print various types of debugging information.")
+    def opt_debug(opt, arg):
+        global print_tree
+        if arg == "tree":
+            print_tree = 1
+        else:
+            sys.stderr.write("Warning:  %s is not a valid debug type\n"
+                             % arg)
+
+    Option(func = opt_debug,
+           long = ['debug'], arg='TYPE',
+           help = "Print various types of debugging information.")
 
     Option(func = opt_not_yet, future = 1,
        short = 'e', long = ['environment-overrides'],
index 262762e203acf4b7efbabdd255f40640272f7a67..76872502bb5b735d3c6070e48ccd491f0aee051d 100644 (file)
@@ -360,3 +360,35 @@ def autogenerate(dict, fs = SCons.Node.FS.default_fs, dir = None):
     for interp in AUTO_GEN_VARS:
         interp.instance(dir, fs).generate(dict)
 
+def render_tree(root, child_func, margin=[0], visited={}):
+    """
+    Render a tree of nodes into an ASCII tree view.
+    root - the root node of the tree
+    child_func - the function called to get the children of a node
+    margin - the format of the left margin to use for children of root.
+       1 results in a pipe, and 0 results in no pipe.
+    visited - a dictionart of visited nodes in the current branch
+    """
+
+    if visited.has_key(root):
+        return ""
+
+    children = child_func(root)
+    retval = ""
+    for pipe in margin[:-1]:
+        if pipe:
+            retval = retval + "| "
+        else:
+            retval = retval + "  "
+
+    retval = retval + "+-" + str(root) + "\n"
+    visited = copy.copy(visited)
+    visited[root] = 1
+
+    for i in range(len(children)):
+        margin.append(i<len(children)-1)
+        retval = retval + render_tree(children[i], child_func, margin, visited
+)
+        margin.pop()
+
+    return retval
index a7c9e7004b3b97dc0a1848f45d1b85b2e7055ce7..168896f6ca668c721a18733a98e322a9cf30f6c1 100644 (file)
@@ -207,7 +207,41 @@ class UtilTestCase(unittest.TestCase):
         
         assert dict['_INCFLAGS'][4] == os.path.normpath('fooblatbar'), \
                dict['_INCFLAGS'][4]
-        
+
+    def test_render_tree(self):
+        class Node:
+            def __init__(self, name, children=[]):
+                self.children = children
+                self.name = name
+            def __str__(self):
+                return self.name
+
+        def get_children(node):
+            return node.children
+
+        windows_h = Node("windows.h")
+        stdlib_h = Node("stdlib.h")
+        stdio_h = Node("stdio.h")
+        bar_c = Node("bar.c", [stdlib_h, windows_h])
+        bar_o = Node("bar.o", [bar_c])
+        foo_c = Node("foo.c", [stdio_h])
+        foo_o = Node("foo.o", [foo_c])
+        foo = Node("foo", [foo_o, bar_o])
+
+        expect = """\
++-foo
+  +-foo.o
+  | +-foo.c
+  |   +-stdio.h
+  +-bar.o
+    +-bar.c
+      +-stdlib.h
+      +-windows.h
+"""
+
+        actual = render_tree(foo, get_children)
+        assert expect == actual, (expect, actual)
+
 if __name__ == "__main__":
     suite = unittest.makeSuite(UtilTestCase, 'test_')
     if not unittest.TextTestRunner().run(suite).wasSuccessful():
diff --git a/test/option--debug.py b/test/option--debug.py
new file mode 100644 (file)
index 0000000..b44c5f6
--- /dev/null
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2001 Steven Knight
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+
+__revision__ = "test/option--test.py __REVISION__ __DATE__ __DEVELOPER__"
+
+import TestSCons
+import sys
+import string
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+env = Environment()
+env.Program('foo', 'foo.c bar.c')
+""")
+
+test.write('foo.c', """
+#include "foo.h"
+int main(int argc, char *argv[])
+{
+       argv[argc++] = "--";
+       printf("f1.c\n");
+       exit (0);
+}
+""")
+
+test.write('bar.c', """
+#include "bar.h"
+""")
+
+test.write('foo.h', """
+#ifndef FOO_H
+#define FOO_H
+#include "bar.h"
+#endif
+""")
+
+test.write('bar.h', """
+#ifndef BAR_H
+#define BAR_H
+#include "foo.h"
+#endif
+""")
+
+
+if sys.platform == 'win32':
+    foo = 'foo.exe'
+else:
+    foo = 'foo'
+
+test.run(arguments = "--debug=tree " + foo)
+
+tree = """
++-foo
+  +-foo.o
+  | +-foo.c
+  |   +-foo.h
+  |   +-bar.h
+  +-bar.o
+    +-bar.c
+      +-bar.h
+      +-foo.h
+"""
+
+assert string.find(test.stdout(), tree) != -1
+
+test.run(arguments = "--debug=tree " + foo)
+assert string.find(test.stdout(), tree) != -1
+
+test.pass_test()
+