diff --git a/src/engine/make.c b/src/engine/make.c index e1b4d624e..d6677d952 100644 --- a/src/engine/make.c +++ b/src/engine/make.c @@ -126,7 +126,11 @@ int make( int n_targets, OBJECT * * targets, int anyhow ) { PROFILE_ENTER( MAKE_MAKE0 ); for ( i = 0; i < n_targets; ++i ) - make0( bindtarget( targets[ i ] ), 0, 0, counts, anyhow ); + { + TARGET * t = bindtarget( targets[ i ] ); + if ( t->fate == T_FATE_INIT ) + make0( t, 0, 0, counts, anyhow ); + } PROFILE_EXIT( MAKE_MAKE0 ); } diff --git a/src/engine/make1.c b/src/engine/make1.c index 3c1331e50..1e80b5a74 100644 --- a/src/engine/make1.c +++ b/src/engine/make1.c @@ -281,6 +281,15 @@ static void make1a( state * pState ) ++pState->parent->asynccnt; } + /* + * If the target has been previously updated with -n in + * effect, and we're ignoring -n, update it for real. + */ + if ( !globs.noexec && pState->t->progress == T_MAKE_NOEXEC_DONE ) + { + pState->t->progress = T_MAKE_INIT; + } + /* If this target is already being processed then do nothing. There is no * need to start processing the same target all over again. */ @@ -384,13 +393,21 @@ static void make1b( state * pState ) /* Now ready to build target 't', if dependencies built OK. */ - /* Collect status from dependencies. */ - for ( c = t->depends; c; c = c->next ) - if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) ) - { - failed = c->target; - pState->t->status = c->target->status; - } + /* Collect status from dependencies. If -n was passed then + * act as though all dependencies built correctly. The only + * way they can fail is if UPDATE_NOW was called. If + * the dependencies can't be found or we got an interrupt, + * we can't get here. + */ + if ( !globs.noexec ) + { + for ( c = t->depends; c; c = c->next ) + if ( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ) ) + { + failed = c->target; + pState->t->status = c->target->status; + } + } /* If an internal header node failed to build, we want to output the target * that it failed on. */ @@ -560,7 +577,10 @@ static void make1c( state * pState ) TARGET * t = pState->t; TARGET * additional_includes = NULL; - t->progress = T_MAKE_DONE; + if ( globs.noexec ) + t->progress = T_MAKE_NOEXEC_DONE; + else + t->progress = T_MAKE_DONE; /* Target has been updated so rescan it for dependencies. */ if ( ( t->fate >= T_FATE_MISSING ) && @@ -811,7 +831,7 @@ static void make1d( state * pState ) CMD * cmd = (CMD *)t->cmds; int status = pState->status; - if ( t->flags & T_FLAG_FAIL_EXPECTED ) + if ( t->flags & T_FLAG_FAIL_EXPECTED && !globs.noexec ) { /* Invert execution result when FAIL_EXPECTED has been applied. */ switch ( status ) @@ -918,6 +938,7 @@ static CMD * make1cmds( TARGET * t ) module_t * settings_module = 0; TARGET * settings_target = 0; ACTIONS * a0; + int running_flag = globs.noexec ? A_RUNNING_NOEXEC : A_RUNNING; /* Step through actions. Actions may be shared with other targets or grouped * using RULE_TOGETHER, so actions already seen are skipped. @@ -937,10 +958,10 @@ static CMD * make1cmds( TARGET * t ) /* Only do rules with commands to execute. If this action has already * been executed, use saved status. */ - if ( !actions || a0->action->running ) + if ( !actions || a0->action->running >= running_flag ) continue; - a0->action->running = 1; + a0->action->running = running_flag; /* Make LISTS of targets and sources. If `execute together` has been * specified for this rule, tack on sources from each instance of this @@ -950,10 +971,10 @@ static CMD * make1cmds( TARGET * t ) ns = make1list( L0, a0->action->sources, actions->flags ); if ( actions->flags & RULE_TOGETHER ) for ( a1 = a0->next; a1; a1 = a1->next ) - if ( a1->action->rule == rule && !a1->action->running ) + if ( a1->action->rule == rule && a1->action->running < running_flag ) { ns = make1list( ns, a1->action->sources, actions->flags ); - a1->action->running = 1; + a1->action->running = running_flag; } /* If doing only updated (or existing) sources, but none have been diff --git a/src/engine/rules.h b/src/engine/rules.h index 83e9797c1..345dc06ac 100644 --- a/src/engine/rules.h +++ b/src/engine/rules.h @@ -110,6 +110,9 @@ struct _action TARGETS * targets; TARGETS * sources; /* aka $(>) */ char running; /* has been started */ +#define A_INIT 0 +#define A_RUNNING_NOEXEC 1 +#define A_RUNNING 2 char status; /* see TARGET status */ int refs; }; diff --git a/test/core_option_n.py b/test/core_option_n.py index 5b5410605..3b91d8e63 100755 --- a/test/core_option_n.py +++ b/test/core_option_n.py @@ -25,6 +25,7 @@ echo [$(<:B)] 2 NOTFILE subtest ; .a. subtest_a : subtest ; .a. subtest_b : subtest ; + FAIL_EXPECTED subtest_b ; DEPENDS all : subtest_a subtest_b ; """) @@ -45,4 +46,6 @@ echo [subtest_b] 2 ...updated 2 targets... """) +t.expect_nothing_more() + t.cleanup() diff --git a/test/core_update_now.py b/test/core_update_now.py new file mode 100755 index 000000000..d31a8c560 --- /dev/null +++ b/test/core_update_now.py @@ -0,0 +1,198 @@ +#!/usr/bin/python + +# Copyright 2011 Steven Watanabe +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) + +import BoostBuild +import os + +def basic(): + # Basic test + + t = BoostBuild.Tester(pass_toolset=0, pass_d0=False) + + t.write("file.jam", """ + +actions do-print +{ + echo updating $(<) +} + +NOTFILE target1 ; +ALWAYS target1 ; +do-print target1 ; + +UPDATE_NOW target1 ; + +DEPENDS all : target1 ; +""") + + t.run_build_system("-ffile.jam", stdout="""...found 1 target... +...updating 1 target... +do-print target1 +updating target1 +...updated 1 target... +...found 1 target... +""") + + t.cleanup() + +def ignore_minus_n(): + # ignore-minus-n + + t = BoostBuild.Tester(pass_toolset=0, pass_d0=False) + + t.write("file.jam", """ + +actions do-print +{ + echo updating $(<) +} + +NOTFILE target1 ; +ALWAYS target1 ; +do-print target1 ; + +UPDATE_NOW target1 : : ignore-minus-n ; + +DEPENDS all : target1 ; +""") + + t.run_build_system("-ffile.jam -n", stdout="""...found 1 target... +...updating 1 target... +do-print target1 + + echo updating target1 + +updating target1 +...updated 1 target... +...found 1 target... +""") + + t.cleanup() + +def failed_target(): + + t = BoostBuild.Tester(pass_toolset=0, pass_d0=False) + + t.write("file.jam", """ + +actions fail +{ + exit 1 +} + +NOTFILE target1 ; +ALWAYS target1 ; +fail target1 ; + +actions do-print +{ + echo updating $(<) +} + +NOTFILE target2 ; +do-print target2 ; +DEPENDS target2 : target1 ; + +UPDATE_NOW target1 : : ignore-minus-n ; + +DEPENDS all : target1 target2 ; +""") + + t.run_build_system("-ffile.jam -n", stdout="""...found 1 target... +...updating 1 target... +fail target1 + + exit 1 + +...failed fail target1... +...failed updating 1 target... +...found 2 targets... +...updating 1 target... +do-print target2 + + echo updating target2 + +...updated 1 target... +""") + + t.cleanup() + +def missing_target(): + t = BoostBuild.Tester(pass_toolset=0, pass_d0=False) + + t.write("file.jam", """ + +actions do-print +{ + echo updating $(<) +} + +NOTFILE target2 ; +do-print target2 ; +DEPENDS target2 : target1 ; + +UPDATE_NOW target1 : : ignore-minus-n ; + +DEPENDS all : target1 target2 ; +""") + + t.run_build_system("-ffile.jam -n", status=1, stdout="""don't know how to make target1 +...found 1 target... +...can't find 1 target... +...found 2 targets... +...can't make 1 target... +""") + + t.cleanup() + +# Make sure that if we call UPDATE_NOW with ignore-minus-n, +# the target gets updated exactly once regardless of previous +# calls to UPDATE_NOW with -n in effect. + +def build_once(): + t = BoostBuild.Tester(pass_toolset=0, pass_d0=False) + + t.write("file.jam", """ + +actions do-print +{ + echo updating $(<) +} + +NOTFILE target1 ; +ALWAYS target1 ; +do-print target1 ; + +UPDATE_NOW target1 ; +UPDATE_NOW target1 : : ignore-minus-n ; +UPDATE_NOW target1 : : ignore-minus-n ; + +DEPENDS all : target1 ; +""") + + t.run_build_system("-ffile.jam -n", stdout="""...found 1 target... +...updating 1 target... +do-print target1 + + echo updating target1 + +...updated 1 target... +do-print target1 + + echo updating target1 + +updating target1 +...updated 1 target... +...found 1 target... +""") + + t.cleanup() + +basic() +ignore_minus_n() +failed_target() +missing_target() +build_once() diff --git a/test/test_all.py b/test/test_all.py index 1b2ae3645..761c8ad87 100644 --- a/test/test_all.py +++ b/test/test_all.py @@ -151,6 +151,7 @@ tests = [ "absolute_sources", "core_parallel_actions", "core_parallel_multifile_actions_1", "core_parallel_multifile_actions_2", + "core_update_now", "custom_generator", "default_build", "default_features",