LIST * builtin_depends( PARSE *parse, LOL *args, int *jmp ) { int curindex = 0; while ( 1 ) { LIST *targets = lol_get( args, curindex ); LIST *sources = lol_get( args, curindex + 1 ); LIST *l; if ( !sources ) break; for( l = targets; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); /* If doing INCLUDES, switch to the TARGET's include */ /* TARGET, creating it if needed. The internal include */ /* TARGET shares the name of its parent. */ #ifdef OPT_BUILTIN_NEEDS_EXT if( parse->num==1 ) #else if( parse->num ) #endif { if( !t->includes ) t->includes = copytarget( t ); t = t->includes; } #ifdef OPT_BUILTIN_NEEDS_EXT t->depends = targetlist( t->depends, sources, (char)(parse->num==2) ); #else t->depends = targetlist( t->depends, sources ); #endif } ++curindex; } return L0; }
LIST * builtin_depends( PARSE *parse, FRAME *frame ) { LIST *targets = lol_get( frame->args, 0 ); LIST *sources = lol_get( frame->args, 1 ); LIST *l; for( l = targets; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); /* If doing INCLUDES, switch to the TARGET's include */ /* TARGET, creating it if needed. The internal include */ /* TARGET shares the name of its parent. */ if( parse->num ) { if( !t->includes ) { t->includes = copytarget( t ); t->includes->original_target = t; } t = t->includes; } t->depends = targetlist( t->depends, sources ); } /* Enter reverse links */ for( l = sources; l; l = list_next( l ) ) { TARGET *s = bindtarget( l->string ); s->dependents = targetlist( s->dependents, targets ); } return L0; }
LIST * builtin_rebuilds( PARSE *parse, FRAME *frame ) { LIST *targets = lol_get( frame->args, 0 ); LIST *rebuilds = lol_get( frame->args, 1 ); LIST *l; for( l = targets; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); t->rebuilds = targetlist( t->rebuilds, rebuilds ); } return L0; }
void make0( TARGET *t, TARGET *p, /* parent */ int depth, /* for display purposes */ COUNTS *counts, /* for reporting */ int anyhow ) /* forcibly touch all (real) targets */ { TARGETS *c, *d, *incs; TARGET *ptime = t; time_t last, leaf, hlast; int fate; const char *flag = ""; SETTINGS *s; #ifdef OPT_GRAPH_DEBUG_EXT int savedFate, oldTimeStamp; #endif if( DEBUG_MAKEPROG ) printf( "make\t--\t%s%s\n", spaces( depth ), t->name ); /* * Step 1: initialize */ if( DEBUG_MAKEPROG ) printf( "make\t--\t%s%s\n", spaces( depth ), t->name ); t->fate = T_FATE_MAKING; /* * Step 2: under the influence of "on target" variables, * bind the target and search for headers. */ /* Step 2a: set "on target" variables. */ s = copysettings( t->settings ); pushsettings( s ); /* Step 2b: find and timestamp the target file (if it's a file). */ if( t->binding == T_BIND_UNBOUND && !( t->flags & T_FLAG_NOTFILE ) ) { char* another_target; t->boundname = search( t->name, &t->time, &another_target ); /* If it was detected that this target refers to an already existing and bound one, we add include dependency, so that every target which depends on us will depend on that other target. */ if( another_target ) { TARGET* includes; if (!t->includes) { t->includes = copytarget(t); t->includes->original_target = t; } includes = t->includes; includes->depends = targetlist( includes->depends, list_new( L0, another_target ) ); } t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING; } /* INTERNAL, NOTFILE header nodes have the time of their parents */ if( p && t->flags & T_FLAG_INTERNAL ) ptime = p; /* If temp file doesn't exist but parent does, use parent */ if( p && t->flags & T_FLAG_TEMP && t->binding == T_BIND_MISSING && p->binding != T_BIND_MISSING ) { t->binding = T_BIND_PARENTS; ptime = p; } #ifdef OPT_SEMAPHORE { LIST *var = var_get( "JAM_SEMAPHORE" ); if( var ) { TARGET *semaphore = bindtarget( var->string ); semaphore->progress = T_MAKE_SEMAPHORE; t->semaphore = semaphore; } } #endif /* Step 2c: If its a file, search for headers. */ if( t->binding == T_BIND_EXISTS ) headers( t ); /* Step 2d: reset "on target" variables */ popsettings( s ); freesettings( s ); /* * Pause for a little progress reporting */ if( DEBUG_BIND ) { if( strcmp( t->name, t->boundname ) ) { printf( "bind\t--\t%s%s: %s\n", spaces( depth ), t->name, t->boundname ); } switch( t->binding ) { case T_BIND_UNBOUND: case T_BIND_MISSING: case T_BIND_PARENTS: printf( "time\t--\t%s%s: %s\n", spaces( depth ), t->name, target_bind[ t->binding ] ); break; case T_BIND_EXISTS: printf( "time\t--\t%s%s: %s", spaces( depth ), t->name, ctime( &t->time ) ); break; } } /* * Step 3: recursively make0() dependents & headers */ /* Step 3a: recursively make0() dependents */ for( c = t->depends; c; c = c->next ) { int internal = t->flags & T_FLAG_INTERNAL; /* Seems like it's not relevant for us.... if( DEBUG_DEPENDS ) printf( "%s \"%s\" : \"%s\" ;\n", internal ? "Includes" : "Depends", t->name, c->target->name ); */ /* Warn about circular deps, except for includes, */ /* which include each other alot. */ if( c->target->fate == T_FATE_INIT ) make0( c->target, ptime, depth + 1, counts, anyhow ); else if( c->target->fate == T_FATE_MAKING && !internal ) printf( "warning: %s depends on itself\n", c->target->name ); } /* Step 3b: recursively make0() internal includes node */ if( t->includes ) make0( t->includes, p, depth + 1, counts, anyhow ); /* Step 3c: add dependents' includes to our direct dependencies */ incs = 0; for( c = t->depends; c; c = c->next ) if( c->target->includes ) incs = targetentry( incs, c->target->includes ); t->depends = targetchain( t->depends, incs ); /* * Step 4: compute time & fate */ /* Step 4a: pick up dependents' time and fate */ last = 0; leaf = 0; fate = T_FATE_STABLE; for( c = t->depends; c; c = c->next ) { /* If LEAVES has been applied, we only heed the timestamps of */ /* the leaf source nodes. */ leaf = max( leaf, c->target->leaf ); if( t->flags & T_FLAG_LEAVES ) { last = leaf; continue; } last = max( last, c->target->time ); fate = max( fate, c->target->fate ); #ifdef OPT_GRAPH_DEBUG_EXT if( DEBUG_FATE ) if( fate < c->target->fate ) printf( "fate change %s from %s to %s by dependency %s\n", t->name, target_fate[fate], target_fate[c->target->fate], c->target->name); #endif } /* Step 4b: pick up included headers time */ /* * If a header is newer than a temp source that includes it, * the temp source will need building. */ hlast = t->includes ? t->includes->time : 0; /* Step 4c: handle NOUPDATE oddity */ /* * If a NOUPDATE file exists, make dependents eternally old. * Don't inherit our fate from our dependents. Decide fate * based only upon other flags and our binding (done later). */ if( t->flags & T_FLAG_NOUPDATE ) { #ifdef OPT_GRAPH_DEBUG_EXT if( DEBUG_FATE ) if( fate != T_FATE_STABLE ) printf( "fate change %s back to stable, NOUPDATE.\n", t->name); #endif last = 0; t->time = 0; /* * Don't inherit our fate from our dependents. Decide fate * based only upon other flags and our binding (done later). */ fate = T_FATE_STABLE; } /* Step 4d: determine fate: rebuild target or what? */ /* In English: If can't find or make child, can't make target. If children changed, make target. If target missing, make it. If children newer, make target. If temp's children newer than parent, make temp. If temp's headers newer than parent, make temp. If deliberately touched, make it. If up-to-date temp file present, use it. If target newer than non-notfile parent, mark target newer. Otherwise, stable! Note this block runs from least to most stable: as we make it further down the list, the target's fate is getting stabler. */ #ifdef OPT_GRAPH_DEBUG_EXT savedFate = fate; oldTimeStamp = 0; #endif if( fate >= T_FATE_BROKEN ) { fate = T_FATE_CANTMAKE; } else if( fate >= T_FATE_SPOIL ) { fate = T_FATE_UPDATE; } else if( t->binding == T_BIND_MISSING ) { fate = T_FATE_MISSING; } else if( t->binding == T_BIND_EXISTS && last > t->time ) { #ifdef OPT_GRAPH_DEBUG_EXT oldTimeStamp = 1; #endif fate = T_FATE_OUTDATED; } else if( t->binding == T_BIND_PARENTS && last > p->time ) { #ifdef OPT_GRAPH_DEBUG_EXT oldTimeStamp = 1; #endif fate = T_FATE_NEEDTMP; } else if( t->binding == T_BIND_PARENTS && hlast > p->time ) { fate = T_FATE_NEEDTMP; } else if( t->flags & T_FLAG_TOUCHED ) { fate = T_FATE_TOUCHED; } else if( anyhow && !( t->flags & T_FLAG_NOUPDATE ) ) { fate = T_FATE_TOUCHED; } else if( t->binding == T_BIND_EXISTS && t->flags & T_FLAG_TEMP ) { fate = T_FATE_ISTMP; } else if( t->binding == T_BIND_EXISTS && p && p->binding != T_BIND_UNBOUND && t->time > p->time ) { #ifdef OPT_GRAPH_DEBUG_EXT oldTimeStamp = 1; #endif fate = T_FATE_NEWER; } else { fate = T_FATE_STABLE; } #ifdef OPT_GRAPH_DEBUG_EXT if( DEBUG_FATE && fate != savedFate ) if( savedFate == T_FATE_STABLE ) printf( "fate change %s set to %s%s\n", t->name, target_fate[fate], oldTimeStamp ? " (by timestamp)" : "" ); else printf( "fate change %s from %s to %s%s\n", t->name, target_fate[savedFate], target_fate[fate], oldTimeStamp ? " (by timestamp)" : "" ); #endif /* Step 4e: handle missing files */ /* If it's missing and there are no actions to create it, boom. */ /* If we can't make a target we don't care about, 'sokay */ /* We could insist that there are updating actions for all missing */ /* files, but if they have dependents we just pretend it's NOTFILE. */ if( fate == T_FATE_MISSING && !t->actions && !t->depends ) { if( t->flags & T_FLAG_NOCARE ) { #ifdef OPT_GRAPH_DEBUG_EXT if( DEBUG_FATE ) printf( "fate change %s to STABLE from %s, " "no actions, no dependents and don't care\n", t->name, target_fate[fate]); #endif fate = T_FATE_STABLE; } else { printf( "don't know how to make %s\n", t->name ); fate = T_FATE_CANTFIND; } } /* Step 4f: propagate dependents' time & fate. */ /* Set leaf time to be our time only if this is a leaf. */ t->time = max( t->time, last ); t->leaf = leaf ? leaf : t->time ; /* This target's fate may have been updated by virtue of following * some target's rebuilds list, so only allow it to be increased * to the fate we've calculated. Otherwise, grab its new fate. */ if (fate > t->fate) t->fate = fate; else fate = t->fate; /* Step 4g: if this target needs to be built, force rebuild * everything in this target's rebuilds list */ if (fate >= T_FATE_BUILD && fate < T_FATE_BROKEN) force_rebuilds(t); /* * Step 5: sort dependents by their update time. */ if( globs.newestfirst ) t->depends = make0sort( t->depends ); /* * Step 6: a little harmless tabulating for tracing purposes */ /* Don't count or report interal includes nodes. */ if( t->flags & T_FLAG_INTERNAL ) return; if (counts) { #ifdef OPT_IMPROVED_PATIENCE_EXT ++counts->targets; #else if( !( ++counts->targets % 1000 ) && DEBUG_MAKE ) printf( "...patience...\n" ); #endif if( fate == T_FATE_ISTMP ) counts->temp++; else if( fate == T_FATE_CANTFIND ) counts->cantfind++; else if( fate == T_FATE_CANTMAKE && t->actions ) counts->cantmake++; else if( fate >= T_FATE_BUILD && fate < T_FATE_BROKEN && t->actions ) counts->updating++; } if( !( t->flags & T_FLAG_NOTFILE ) && fate >= T_FATE_SPOIL ) flag = "+"; else if( t->binding == T_BIND_EXISTS && p && t->time > p->time ) flag = "*"; if( DEBUG_MAKEPROG ) printf( "made%s\t%s\t%s%s\n", flag, target_fate[ t->fate ], spaces( depth ), t->name ); /* We don't have DEBUG_CAUSES. if( DEBUG_CAUSES && t->fate >= T_FATE_NEWER && t->fate <= T_FATE_MISSING ) printf( "%s %s\n", target_fate[ t->fate ], t->name ); */ }
LIST * evaluate_rule( char * rulename, FRAME * frame ) { LIST * result = L0; RULE * rule; profile_frame prof[1]; module_t * prev_module = frame->module; LIST * l; { LOL arg_context_, * arg_context = &arg_context_; if ( !frame->prev ) lol_init(arg_context); else arg_context = frame->prev->args; l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 ); } if ( !l ) { backtrace_line( frame->prev ); printf( "warning: rulename %s expands to empty string\n", rulename ); backtrace( frame->prev ); return result; } rulename = l->string; rule = bindrule( l->string, frame->module ); #ifdef HAVE_PYTHON if ( rule->python_function ) { /* The below messing with modules is due to the way modules are * implemented in Jam. Suppose we are in module M1 now. The global * variable map actually holds 'M1' variables, and M1->variables hold * global variables. * * If we call Python right away, Python calls back Jam and then Jam * does 'module M1 { }' then Jam will try to swap the current global * variables with M1->variables. The result will be that global * variables map will hold global variables, and any variable settings * we do will go to the global module, not M1. * * By restoring basic state, where the global variable map holds global * variable, we make sure any future 'module M1' entry will work OK. */ LIST * result; module_t * m = python_module(); frame->module = m; exit_module( prev_module ); enter_module( m ); result = call_python_function( rule, frame ); exit_module( m ); enter_module ( prev_module ); return result; } #endif /* Drop the rule name. */ l = list_pop_front( l ); /* Tack the rest of the expansion onto the front of the first argument. */ frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) ); if ( DEBUG_COMPILE ) { /* Try hard to indicate in which module the rule is going to execute. */ if ( rule->module != frame->module && rule->procedure != 0 && strcmp( rulename, rule->procedure->rulename ) ) { char buf[256] = ""; strncat( buf, rule->module->name, sizeof( buf ) - 1 ); strncat( buf, rule->name, sizeof( buf ) - 1 ); debug_compile( 1, buf, frame ); } else { debug_compile( 1, rulename, frame ); } lol_print( frame->args ); printf( "\n" ); } if ( rule->procedure && rule->module != prev_module ) { /* Propagate current module to nested rule invocations. */ frame->module = rule->module; /* Swap variables. */ exit_module( prev_module ); enter_module( rule->module ); } /* Record current rule name in frame. */ if ( rule->procedure ) { frame->rulename = rulename; /* And enter record profile info. */ if ( DEBUG_PROFILE ) profile_enter( rule->procedure->rulename, prof ); } /* Check traditional targets $(<) and sources $(>). */ if ( !rule->actions && !rule->procedure ) { backtrace_line( frame->prev ); printf( "rule %s unknown in module %s\n", rule->name, frame->module->name ); backtrace( frame->prev ); exit( 1 ); } /* If this rule will be executed for updating the targets then construct the * action for make(). */ if ( rule->actions ) { TARGETS * t; ACTION * action; /* The action is associated with this instance of this rule. */ action = (ACTION *)BJAM_MALLOC( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) ); /* If we have a group of targets all being built using the same action * then we must not allow any of them to be used as sources unless they * had all already been built in the first place or their joined action * has had a chance to finish its work and build all of them anew. * * Without this it might be possible, in case of a multi-process build, * for their action, triggered by buiding one of the targets, to still * be running when another target in the group reports as done in order * to avoid triggering the same action again and gets used prematurely. * * As a quick-fix to achieve this effect we make all the targets list * each other as 'included targets'. More precisely, we mark the first * listed target as including all the other targets in the list and vice * versa. This makes anyone depending on any of those targets implicitly * depend on all of them, thus making sure none of those targets can be * used as sources until all of them have been built. Note that direct * dependencies could not have been used due to the 'circular * dependency' issue. * * TODO: Although the current implementation solves the problem of one * of the targets getting used before its action completes its work it * also forces the action to run whenever any of the targets in the * group is not up to date even though some of them might not actually * be used by the targets being built. We should see how we can * correctly recognize such cases and use that to avoid running the * action if possible and not rebuild targets not actually depending on * targets that are not up to date. * * TODO: Using the 'include' feature might have side-effects due to * interaction with the actual 'inclusion scanning' system. This should * be checked. */ if ( action->targets ) { TARGET * t0 = action->targets->target; for ( t = action->targets->next; t; t = t->next ) { target_include( t->target, t0 ); target_include( t0, t->target ); } } /* Append this action to the actions of each target. */ for ( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule. * parse_refer()/parse_free() call pair added to ensure rule not freed * during use. */ if ( rule->procedure ) { SETTINGS * local_args = collect_arguments( rule, frame ); PARSE * parse = rule->procedure; parse_refer( parse ); pushsettings( local_args ); result = parse_evaluate( parse, frame ); popsettings( local_args ); freesettings( local_args ); parse_free( parse ); } if ( frame->module != prev_module ) { exit_module( frame->module ); enter_module( prev_module ); } if ( DEBUG_PROFILE && rule->procedure ) profile_exit( prof ); if ( DEBUG_COMPILE ) debug_compile( -1, 0, frame); return result; }
LIST * evaluate_rule( const char *rulename, LOL *args, LIST *result ) { #ifdef OPT_EXPAND_RULE_NAMES_EXT RULE *rule; char *expanded; char *c; int i; BUFFER buff; buffer_init( &buff ); if( (i = var_string( rulename, &buff, 0, args, ' ' )) < 0 ) { printf( "Failed to expand rule %s -- expansion too long\n", rulename ); exit( EXITBAD ); } expanded = buffer_ptr( &buff ); while ( expanded[0] == ' ' ) expanded++; while ( (c = strrchr(expanded, ' ')) ) *c = '\0'; if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); if ( strcmp(rulename, expanded) ) printf( "-> %s ", expanded ); lol_print( args ); printf( "\n" ); } rule = bindrule( expanded ); #else RULE *rule = bindrule( rulename ); if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); lol_print( args ); printf( "\n" ); } #endif #ifdef OPT_LOAD_MISSING_RULE_EXT if( !rule->actions && !rule->procedure ) { if( ruleexists( "FindMissingRule" ) ) { LOL lol; LIST *args = list_append( L0, expanded, 0 ); LIST *result; lol_init( &lol ); lol_add( &lol, args ); result = evaluate_rule( "FindMissingRule", &lol, L0 ); lol_free( &lol ); if( list_first( result ) ) { rule = bindrule( list_value( list_first( result ) ) ); } list_free( result ); } } #endif /* OPT_LOAD_MISSING_RULE_EXT */ /* Check traditional targets $(<) and sources $(>) */ #ifdef OPT_IMPROVED_WARNINGS_EXT if( !rule->actions && !rule->procedure && !globs.silence ) printf( "warning: unknown rule %s %s\n", rule->name, file_and_line()); #else if( !rule->actions && !rule->procedure ) printf( "warning: unknown rule %s\n", rule->name ); #endif /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; #ifdef OPT_BUILTIN_NEEDS_EXT action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ), 0 ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ), 0 ); action->autosettings = targetlist( (TARGETS *)0, lol_get( args, 2 ), 0 ); #else action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) ); #endif #ifdef OPT_USE_CHECKSUMS_EXT action->extratargets = targetlist( (TARGETS *)0, lol_get( args, 3 ), 0 ); #endif /* OPT_USE_CHECKSUMS_EXT */ #ifdef OPT_CLEAN_GLOBS_EXT { TARGETS* targets; for ( targets = action->targets; targets; targets = targets->next ) { if ( !( targets->target->flags & T_FLAG_NOTFILE ) ) add_used_target_to_hash( targets->target ); } } #endif /* OPT_CLEAN_GLOBS_EXT */ /* Append this action to the actions of each target */ #ifdef OPT_MULTIPASS_EXT action->pass = actionpass; for( t = action->targets; t; t = t->next ) { t->target->progress = T_MAKE_INIT; t->target->actions = actionlist( t->target->actions, action ); } #else for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); #endif } /* Now recursively compile any parse tree associated with this rule */ if( rule->procedure ) { PARSE *parse = rule->procedure; SETTINGS *s = 0; int jmp = JMP_NONE; LISTITEM *l; int i; /* build parameters as local vars */ for( l = list_first(rule->params), i = 0; l; l = list_next(l), i++ ) s = addsettings( s, 0, list_value(l), list_copy( L0, lol_get( args, i ) ) ); /* Run rule. */ /* Bring in local params. */ /* refer/free to ensure rule not freed during use. */ parse_refer( parse ); pushsettings( s ); result = list_appendList( result, (*parse->func)( parse, args, &jmp ) ); popsettings( s ); freesettings( s ); parse_free( parse ); } if( DEBUG_COMPILE ) debug_compile( -1, 0 ); #ifdef OPT_EXPAND_RULE_NAMES_EXT buffer_free( &buff ); #endif return result; }
LIST * evaluate_rule( const char *rulename, LOL *args, LIST *result, int *jmp ) { RULE *rule = bindrule( rulename ); if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); lol_print( args ); printf( "\n" ); } /* Check traditional targets $(<) and sources $(>) */ if( !rule->actions && !rule->procedure ) printf( "warning: unknown rule %s\n", rule->name ); /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) ); /* Append this action to the actions of each target */ for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule */ if( rule->procedure ) { PARSE *parse = rule->procedure; SETTINGS *s = 0; LIST *l; int i; # ifdef OPT_RULE_PROFILING_EXT struct timeval startTime, endTime; if ( DEBUG_PROFILE_RULES ) gettimeofday(&startTime, 0); # endif /* build parameters as local vars */ for( l = rule->params, i = 0; l; l = l->next, i++ ) s = addsettings( s, 0, l->string, list_copy( L0, lol_get( args, i ) ) ); /* Run rule. */ /* Bring in local params. */ /* refer/free to ensure rule not freed during use. */ parse_refer( parse ); pushsettings( s ); result = list_append( result, (*parse->func)( parse, args, jmp ) ); popsettings( s ); freesettings( s ); parse_free( parse ); # ifdef OPT_RULE_PROFILING_EXT if ( DEBUG_PROFILE_RULES ) { gettimeofday(&endTime, 0); rule->invocations++; rule->invocation_time += (endTime.tv_sec - startTime.tv_sec) * (int64_t)1000000 + (endTime.tv_usec - startTime.tv_usec); } # endif } if( DEBUG_COMPILE ) debug_compile( -1, 0 ); return result; }
LIST * evaluate_rule( char *rulename, FRAME *frame ) { LIST *result = L0; RULE *rule; profile_frame prof[1]; module_t *prev_module = frame->module; LIST *l; { LOL arg_context_, *arg_context = &arg_context_; if ( !frame->prev ) lol_init(arg_context); else arg_context = frame->prev->args; l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 ); } if ( !l ) { backtrace_line( frame->prev ); printf( "warning: rulename %s expands to empty string\n", rulename ); backtrace( frame->prev ); return result; } rulename = l->string; rule = bindrule( l->string, frame->module ); #ifdef HAVE_PYTHON if (rule->python_function) { return call_python_function(rule, frame); } #endif /* drop the rule name */ l = list_pop_front( l ); /* tack the rest of the expansion onto the front of the first argument */ frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) ); if ( DEBUG_COMPILE ) { /* Try hard to indicate in which module the rule is going to execute */ if ( rule->module != frame->module && rule->procedure != 0 && strcmp(rulename, rule->procedure->rulename) ) { char buf[256] = ""; strncat( buf, rule->module->name, sizeof(buf) - 1 ); strncat( buf, rule->name, sizeof(buf) - 1 ); debug_compile( 1, buf, frame); } else { debug_compile( 1, rulename, frame); } lol_print( frame->args ); printf( "\n" ); } if ( rule->procedure && rule->module != prev_module ) { /* propagate current module to nested rule invocations */ frame->module = rule->module; /* swap variables */ exit_module( prev_module ); enter_module( rule->module ); } /* record current rule name in frame */ if ( rule->procedure ) { frame->rulename = rulename; /* and enter record profile info */ if ( DEBUG_PROFILE ) profile_enter( rule->procedure->rulename, prof ); } /* Check traditional targets $(<) and sources $(>) */ if( !rule->actions && !rule->procedure ) { backtrace_line( frame->prev ); printf( "rule %s unknown in module %s\n", rule->name, frame->module->name ); backtrace( frame->prev ); exit(1); } /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) ); /* Append this action to the actions of each target */ for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule */ /* refer/free to ensure rule not freed during use */ if( rule->procedure ) { SETTINGS *local_args = collect_arguments( rule, frame ); PARSE *parse = rule->procedure; parse_refer( parse ); pushsettings( local_args ); result = parse_evaluate( parse, frame ); popsettings( local_args ); freesettings( local_args ); parse_free( parse ); } if ( frame->module != prev_module ) { exit_module( frame->module ); enter_module( prev_module ); } if ( DEBUG_PROFILE && rule->procedure ) profile_exit( prof ); if( DEBUG_COMPILE ) debug_compile( -1, 0, frame); return result; }