From 5330322296bac696af8793287fdbbecc6f755062 Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Fri, 3 Dec 2004 16:06:04 +0000 Subject: Print --debug={tree,dtree,includes} even if the build has an error. --- src/CHANGES.txt | 3 +++ src/engine/SCons/Script/__init__.py | 38 +++++++++++++++---------------- src/engine/SCons/Taskmaster.py | 16 +++++++++++++ src/engine/SCons/TaskmasterTests.py | 14 ++++++++++++ test/option--debug.py | 45 +++++++++++++++++++++++++++++++++---- 5 files changed, 93 insertions(+), 23 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index ebfc13c..021d1d4 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -147,6 +147,9 @@ RELEASE 0.97 - XXX - Add specific exceptions to try:-except: blocks without any listed, so that they won't catch and mask keyboard interrupts. + - Make --debug={tree,dtree,stree} print something even when there's + a build failure. + From Wayne Lee: - Avoid "maximum recursion limit" errors when removing $(-$) pairs diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index 7d139a1..71c2f03 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -121,25 +121,6 @@ class BuildTask(SCons.Taskmaster.Task): else: SCons.Taskmaster.Task.executed(self) - # print the tree here instead of in execute() because - # this method is serialized, but execute isn't: - if print_tree and self.top: - print - SCons.Util.print_tree(self.targets[0], get_all_children) - if print_stree and self.top: - print - SCons.Util.print_tree(self.targets[0], get_all_children, - showtags=2) - if print_dtree and self.top: - print - SCons.Util.print_tree(self.targets[0], get_derived_children) - if print_includes and self.top: - t = self.targets[0] - tree = t.render_include_tree() - if tree: - print - print tree - def failed(self): # Handle the failure of a build task. The primary purpose here # is to display the various types of Errors and Exceptions @@ -182,6 +163,25 @@ class BuildTask(SCons.Taskmaster.Task): self.exc_clear() + def postprocess(self): + if self.top: + t = self.targets[0] + if print_tree: + print + SCons.Util.print_tree(t, get_all_children) + if print_stree: + print + SCons.Util.print_tree(t, get_all_children, showtags=2) + if print_dtree: + print + SCons.Util.print_tree(t, get_derived_children) + if print_includes: + tree = t.render_include_tree() + if tree: + print + print tree + SCons.Taskmaster.Task.postprocess(self) + def make_ready(self): """Make a task ready for execution""" SCons.Taskmaster.Task.make_ready(self) diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index 6bd5e21..b528f44 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -152,8 +152,16 @@ class Task: for t in self.targets: t.set_state(SCons.Node.failed) self.tm.failed(self.node) + next_top = self.tm.next_top_level_candidate() self.tm.stop() + if next_top: + # We're stopping because of a build failure, but give the + # calling Task class a chance to postprocess() the top-level + # target under which the build failure occurred. + self.targets = [next_top] + self.top = 1 + def fail_continue(self): """Explicit continue-the-build failure. @@ -426,6 +434,14 @@ class Taskmaster: return not self.ready and (self.pending or self.executing) + def next_top_level_candidate(self): + candidates = self.candidates[:] + candidates.reverse() + for c in candidates: + if c in self.targets: + return c + return None + def stop(self): """Stop the current build completely.""" self.candidates = [] diff --git a/src/engine/SCons/TaskmasterTests.py b/src/engine/SCons/TaskmasterTests.py index cc4ba0c..a3e4219 100644 --- a/src/engine/SCons/TaskmasterTests.py +++ b/src/engine/SCons/TaskmasterTests.py @@ -625,6 +625,20 @@ class TaskmasterTestCase(unittest.TestCase): tm = MyTM() assert tm.is_blocked() + def test_next_top_level_candidate(self): + """Test the next_top_level_candidate() method + """ + n1 = Node("n1") + n2 = Node("n2", [n1]) + n3 = Node("n3", [n2]) + + tm = SCons.Taskmaster.Taskmaster([n3]) + t = tm.next_task() + assert tm.executing == [n1], tm.executing + t.fail_stop() + assert t.targets == [n3], t.targets + assert t.top == 1, t.top + def test_stop(self): """Test the stop() method diff --git a/test/option--debug.py b/test/option--debug.py index 47bc058..f0114e5 100644 --- a/test/option--debug.py +++ b/test/option--debug.py @@ -126,24 +126,61 @@ test.fail_test(string.find(test.stdout(), stree2) == -1) -tree = """ +dtree = """ +-foo.xxx +-foo.ooo +-bar.ooo """ test.run(arguments = "--debug=dtree foo.xxx") -test.fail_test(string.find(test.stdout(), tree) == -1) +test.fail_test(string.find(test.stdout(), dtree) == -1) -tree = """ +includes = """ +-foo.c +-foo.h +-bar.h """ test.run(arguments = "--debug=includes foo.ooo") +test.fail_test(string.find(test.stdout(), includes) == -1) + +# Make sure we print the debug stuff even if there's a build failure. +test.write('bar.h', """ +#ifndef BAR_H +#define BAR_H +#include "foo.h" +#endif +THIS SHOULD CAUSE A BUILD FAILURE +""") + +test.run(arguments = "--debug=tree foo.xxx", + status = 2, + stderr = None) test.fail_test(string.find(test.stdout(), tree) == -1) -# these shouldn't print out anything in particular, but +test.run(arguments = "--debug=dtree foo.xxx", + status = 2, + stderr = None) +test.fail_test(string.find(test.stdout(), dtree) == -1) + +# In an ideal world, --debug=includes would also work when there's a build +# failure, but this would require even more complicated logic to scan +# all of the intermediate nodes that get skipped when the build failure +# occurs. On the YAGNI theory, we're just not going to worry about this +# until it becomes an issue that someone actually cares enough about. +#test.run(arguments = "--debug=includes foo.xxx", +# status = 2, +# stderr = None) +#test.fail_test(string.find(test.stdout(), includes) == -1) + +# Restore bar.h to something good. +test.write('bar.h', """ +#ifndef BAR_H +#define BAR_H +#include "foo.h" +#endif +""") + +# These shouldn't print out anything in particular, but # they shouldn't crash either: test.run(arguments = "--debug=includes .") test.run(arguments = "--debug=includes foo.c") -- cgit v0.12