From 0090f72efafe87139bb327e799e8f0c1152b1b34 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Sat, 28 Apr 2012 22:05:28 +0000 Subject: [PATCH] Detect cycles created by rescanning. [SVN r78249] --- v2/engine/make1.c | 60 ++++++++++++++++++++++++++++++++++++++-- v2/engine/rules.h | 2 ++ v2/test/rescan_header.py | 56 ++++++++++++++++++++++++++++++++++++- 3 files changed, 115 insertions(+), 3 deletions(-) diff --git a/v2/engine/make1.c b/v2/engine/make1.c index 0165a2eca..e4b106ab7 100644 --- a/v2/engine/make1.c +++ b/v2/engine/make1.c @@ -74,6 +74,7 @@ static CMD * make1cmds ( TARGET * ); static LIST * make1list ( LIST *, TARGETS *, int flags ); static SETTINGS * make1settings( struct module_t * module, LIST * vars ); static void make1bind ( TARGET * ); +static int make1findcycle( TARGET * t ); /* Ugly static - it is too hard to carry it through the callbacks. */ @@ -85,6 +86,8 @@ static struct int made; } counts[ 1 ] ; +int handling_rescan; + /* Target state - remove recursive calls by just keeping track of state target * is in. */ @@ -97,7 +100,8 @@ typedef struct _state #define T_STATE_MAKE1ATAIL 1 /* make1atail() should be called */ #define T_STATE_MAKE1B 2 /* make1b() should be called */ #define T_STATE_MAKE1C 3 /* make1c() should be called */ -#define T_STATE_MAKE1D 4 /* make1d() should be called */ +#define T_STATE_MAKE1CTAIL 4 /* make1ctail() should be called */ +#define T_STATE_MAKE1D 5 /* make1d() should be called */ int curstate; /* current state */ int status; } state; @@ -106,6 +110,7 @@ static void make1a ( state * ); static void make1atail ( state * ); static void make1b ( state * ); static void make1c ( state * ); +static void make1ctail ( state * ); static void make1d ( state * ); static void make_closure( void * closure, int status, timing_info *, const char *, const char * ); @@ -227,6 +232,7 @@ int make1( TARGET * t ) case T_STATE_MAKE1ATAIL: make1atail( pState ); break; case T_STATE_MAKE1B : make1b ( pState ); break; case T_STATE_MAKE1C : make1c ( pState ); break; + case T_STATE_MAKE1CTAIL: make1ctail( pState ); break; case T_STATE_MAKE1D : make1d ( pState ); break; } } @@ -273,8 +279,9 @@ static void make1a( state * pState ) if ( pState->parent ) switch ( pState->t->progress ) { - case T_MAKE_INIT: case T_MAKE_ACTIVE: + if ( handling_rescan && make1findcycle( t ) ) break; + case T_MAKE_INIT: case T_MAKE_RUNNING: pState->t->parents = targetentry( pState->t->parents, pState->parent ); @@ -632,8 +639,12 @@ static void make1c( state * pState ) } if ( additional_includes ) + { + ++handling_rescan; for ( c = t->parents; c; c = c->next ) push_state( &temp_stack, additional_includes, c->target, T_STATE_MAKE1A ); + push_state( &temp_stack, additional_includes, NULL, T_STATE_MAKE1CTAIL ); + } for ( c = t->parents; c; c = c->next ) push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B ); @@ -676,6 +687,12 @@ static void make1c( state * pState ) } } +static void make1ctail( state * pState ) +{ + --handling_rescan; + pop_state( &state_stack ); +} + /* * call_timing_rule() - Look up the __TIMING_RULE__ variable on the given @@ -1163,3 +1180,42 @@ static void make1bind( TARGET * t ) t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING; popsettings( root_module(), t->settings ); } + + +static int make1findcycle_impl( TARGET * t ) +{ + TARGETS * c; + + if ( t->progress == T_MAKE_ONSTACK ) + return 1; + else if ( t->progress != T_MAKE_ACTIVE ) + return 0; + + t->progress = T_MAKE_FINDCYCLE; + + for ( c = t->depends; c; c = c->next ) + if ( make1findcycle_impl( c->target ) ) + return 1; + + return 0; +} + +static void make1findcycle_cleanup( TARGET * t ) +{ + TARGETS * c; + + if ( t->progress != T_MAKE_FINDCYCLE ) + return; + + t->progress = T_MAKE_ACTIVE; + + for ( c = t->depends; c; c = c->next ) + make1findcycle_cleanup( c->target ); +} + +static int make1findcycle( TARGET * t ) +{ + int result = make1findcycle_impl( t ); + make1findcycle_cleanup( t ); + return result; +} diff --git a/v2/engine/rules.h b/v2/engine/rules.h index 823fbd1f5..672a68f27 100644 --- a/v2/engine/rules.h +++ b/v2/engine/rules.h @@ -212,6 +212,8 @@ struct _target #define T_MAKE_RUNNING 3 /* make1(target) running commands */ #define T_MAKE_DONE 4 /* make1(target) done */ #define T_MAKE_NOEXEC_DONE 5 /* make1(target) done with -n in effect */ +#define T_MAKE_FINDCYCLE 6 /* make1(target) searching for cyclic includes after + rescanning a generated file. */ #ifdef OPT_SEMAPHORE #define T_MAKE_SEMAPHORE 5 /* Special target type for semaphores */ diff --git a/v2/test/rescan_header.py b/v2/test/rescan_header.py index 19151e6c1..9de70458a 100755 --- a/v2/test/rescan_header.py +++ b/v2/test/rescan_header.py @@ -82,7 +82,7 @@ actions copy { make header1.h : header1.in : @common.copy ; make header2.h : header2.in : @common.copy ; -make header3.h : header2.in : @common.copy ; +make header3.h : header3.in : @common.copy ; obj test : test.cpp : header1.h header2.h @@ -97,4 +97,58 @@ t.expect_addition("bin/$toolset/debug/header3.h") t.expect_addition("bin/$toolset/debug/test.obj") t.expect_nothing_more() +t.rm(".") + +# Test a loop in generated headers. +t.write("test.cpp", """ +#include "header1.h" +""") + +t.write("header1.in", """ +#ifndef HEADER1_H +#define HEADER1_H +#include "header2.h" +#endif +""") + +t.write("header2.in", """ +#ifndef HEADER2_H +#define HEADER2_H +#include "header3.h" +#endif +""") + +t.write("header3.in", """ +#ifndef HEADER2_H +#define HEADER2_H +#include "header1.h" +#endif +""") + +t.write("Jamroot.jam", """ +import common ; + +actions copy { + sleep 1 + cp $(>) $(<) +} + +make header1.h : header1.in : @common.copy ; +make header2.h : header2.in : @common.copy ; +make header3.h : header3.in : @common.copy ; +obj test : test.cpp : + header1.h + header2.h + header3.h + ; +""") + +t.run_build_system("-j2 test") +t.expect_addition("bin/$toolset/debug/header1.h") +t.expect_addition("bin/$toolset/debug/header2.h") +t.expect_addition("bin/$toolset/debug/header3.h") +t.expect_addition("bin/$toolset/debug/test.obj") +t.expect_nothing_more() + + t.cleanup()