LIST * compile_setexec( PARSE *parse, LOL *args, int *jmp ) { RULE *rule = bindrule( parse->string ); LIST *bindlist = (*parse->left->func)( parse->left, args, jmp ); /* Free old one, if present */ if( rule->actions ) { freestr( rule->actions ); list_free( rule->bindlist ); } rule->actions = copystr( parse->string1 ); rule->bindlist = bindlist; rule->flags = parse->num; /* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */ rule->maxline = parse->num2; rule->maxtargets = parse->num3; /* commented out so jamgram.y can compile #endif */ return L0; }
void call_bind_rule( OBJECT * target_, OBJECT * boundname_ ) { LIST * const bind_rule = var_get( root_module(), constant_BINDRULE ); if ( !list_empty( bind_rule ) ) { OBJECT * target = object_copy( target_ ); OBJECT * boundname = object_copy( boundname_ ); if ( boundname && target ) { /* Prepare the argument list. */ FRAME frame[ 1 ]; frame_init( frame ); /* First argument is the target name. */ lol_add( frame->args, list_new( target ) ); lol_add( frame->args, list_new( boundname ) ); if ( lol_get( frame->args, 1 ) ) { OBJECT * rulename = list_front( bind_rule ); list_free( evaluate_rule( bindrule( rulename, root_module() ), rulename, frame ) ); } /* Clean up */ frame_free( frame ); } else { if ( boundname ) object_free( boundname ); if ( target ) object_free( target ); } } }
static void call_action_rule ( TARGET * target, int status, timing_info const * time, char const * executed_command, char const * command_output ) { LIST * action_rule; pushsettings( root_module(), target->settings ); action_rule = var_get( root_module(), constant_ACTION_RULE ); popsettings( root_module(), target->settings ); if ( !list_empty( action_rule ) ) { /* rule action-rule ( args * : target : command status start end user system : output ? ) */ /* Prepare the argument list. */ FRAME frame[ 1 ]; OBJECT * rulename = list_front( action_rule ); frame_init( frame ); /* args * :: $(__ACTION_RULE__[2-]) */ lol_add( frame->args, list_copy_range( action_rule, list_next( list_begin( action_rule ) ), list_end( action_rule ) ) ); /* target :: the name of the target */ lol_add( frame->args, list_new( object_copy( target->name ) ) ); /* command status start end user system :: info about the action command */ lol_add( frame->args, list_push_back( list_push_back( list_push_back( list_push_back( list_push_back( list_new( object_new( executed_command ) ), outf_int( status ) ), outf_time( &time->start ) ), outf_time( &time->end ) ), outf_double( time->user ) ), outf_double( time->system ) ) ); /* output ? :: the output of the action command */ if ( command_output ) lol_add( frame->args, list_new( object_new( command_output ) ) ); else lol_add( frame->args, L0 ); /* Call the rule. */ evaluate_rule( bindrule( rulename, root_module() ), rulename, frame ); /* Clean up. */ frame_free( frame ); } }
void headers( TARGET * t ) { LIST * hdrscan; LIST * hdrrule; #ifndef OPT_HEADER_CACHE_EXT LIST * headlist = L0; #endif regexp * re[ MAXINC ]; int rec = 0; LISTITER iter; LISTITER end; hdrscan = var_get( root_module(), constant_HDRSCAN ); if ( list_empty( hdrscan ) ) return; hdrrule = var_get( root_module(), constant_HDRRULE ); if ( list_empty( hdrrule ) ) return; if ( DEBUG_HEADER ) out_printf( "header scan %s\n", object_str( t->name ) ); /* Compile all regular expressions in HDRSCAN */ iter = list_begin( hdrscan ); end = list_end( hdrscan ); for ( ; ( rec < MAXINC ) && iter != end; iter = list_next( iter ) ) { re[ rec++ ] = regex_compile( list_item( iter ) ); } /* Doctor up call to HDRRULE rule */ /* Call headers1() to get LIST of included files. */ { FRAME frame[ 1 ]; frame_init( frame ); lol_add( frame->args, list_new( object_copy( t->name ) ) ); #ifdef OPT_HEADER_CACHE_EXT lol_add( frame->args, hcache( t, rec, re, hdrscan ) ); #else lol_add( frame->args, headers1( headlist, t->boundname, rec, re ) ); #endif if ( lol_get( frame->args, 1 ) ) { OBJECT * rulename = list_front( hdrrule ); /* The third argument to HDRRULE is the bound name of $(<). */ lol_add( frame->args, list_new( object_copy( t->boundname ) ) ); list_free( evaluate_rule( bindrule( rulename, frame->module ), rulename, frame ) ); } /* Clean up. */ frame_free( frame ); } }
LIST * compile_setcomp( PARSE *parse, LOL *args, int *jmp ) { RULE *rule = bindrule( parse->string ); LIST *params = 0; PARSE *p; /* Build param list */ for( p = parse->left; p; p = p->left ) params = list_append( params, p->string, 1 ); if( DEBUG_COMPILE ) { debug_compile( 0, "rule" ); printf( "%s ", parse->string ); list_print( params ); printf( "\n" ); } /* Free old one, if present */ if( rule->procedure ) parse_free( rule->procedure ); if( rule->params ) list_free( rule->params ); rule->procedure = parse->right; rule->params = params; /* we now own this parse tree */ /* don't let parse_free() release it */ parse_refer( parse->right ); return L0; }
static void call_timing_rule( TARGET * target, timing_info const * const time ) { LIST * timing_rule; pushsettings( root_module(), target->settings ); timing_rule = var_get( root_module(), constant_TIMING_RULE ); popsettings( root_module(), target->settings ); if ( !list_empty( timing_rule ) ) { /* rule timing-rule ( args * : target : start end user system ) */ /* Prepare the argument list. */ FRAME frame[ 1 ]; OBJECT * rulename = list_front( timing_rule ); frame_init( frame ); /* args * :: $(__TIMING_RULE__[2-]) */ lol_add( frame->args, list_copy_range( timing_rule, list_next( list_begin( timing_rule ) ), list_end( timing_rule ) ) ); /* target :: the name of the target */ lol_add( frame->args, list_new( object_copy( target->name ) ) ); /* start end user system :: info about the action command */ lol_add( frame->args, list_push_back( list_push_back( list_push_back( list_new( outf_time( &time->start ) ), outf_time( &time->end ) ), outf_double( time->user ) ), outf_double( time->system ) ) ); /* Call the rule. */ evaluate_rule( bindrule( rulename , root_module() ), rulename, frame ); /* Clean up. */ frame_free( frame ); } }
LIST * compile_setexec( PARSE *parse, LOL *args, int *jmp ) { RULE *rule = bindrule( parse->string ); LIST *bindlist = (*parse->left->func)( parse->left, args, jmp ); /* Free old one, if present */ if( rule->actions ) { freestr( rule->actions ); list_free( rule->bindlist ); } rule->actions = copystr( parse->string1 ); rule->bindlist = bindlist; rule->flags = parse->num; return L0; }
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; }
// jam_action(name, function, {options}) int LS_jam_action(ls_lua_State *L) { RULE* rule; const char* name; int paramIndex = 2; int numParams = ls_lua_gettop(L); if (numParams < 2) { //ls_luaL_error return 0; } if (!ls_lua_isstring(L, 1)) return 0; name = ls_lua_tostring(L, 1); rule = bindrule(name); if (rule->actions) { freestr(rule->actions); rule->actions = NULL; } if (rule->bindlist) { list_free(rule->bindlist); rule->bindlist = L0; } if (ls_lua_isstring(L, 2)) paramIndex = 2; else if (ls_lua_isstring(L, 3)) paramIndex = 3; else { return 0; } rule->actions = copystr(ls_lua_tostring(L, paramIndex)); rule->flags = 0; paramIndex = paramIndex == 2 ? 3 : 2; if (ls_lua_istable(L, paramIndex)) { ls_lua_getfield(L, paramIndex, "bind"); if (ls_lua_istable(L, -1)) { ls_lua_pushnil(L); while (ls_lua_next(L, -2) != 0) { if (!ls_lua_tostring(L, -1)) { printf("!!\n"); exit(1); } rule->bindlist = list_append(rule->bindlist, ls_lua_tostring(L, -1), 0); ls_lua_pop(L, 1); } ls_lua_pop(L, 1); } ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "updated"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_UPDATED : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "together"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_TOGETHER : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "ignore"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_IGNORE : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "quietly"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_QUIETLY : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "piecemeal"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_PIECEMEAL : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "existing"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_EXISTING : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "response"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_RESPONSE : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "lua"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_LUA : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "screenoutput"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_SCREENOUTPUT : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "removeemptydirs"); rule->flags |= ls_lua_toboolean(L, -1) ? RULE_REMOVEEMPTYDIRS : 0; ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "maxtargets"); if (ls_lua_isnumber(L, -1)) { rule->flags |= RULE_MAXTARGETS; rule->maxtargets = (int)ls_lua_tonumber(L, -1); } ls_lua_pop(L, 1); ls_lua_getfield(L, paramIndex, "maxline"); if (ls_lua_isnumber(L, -1)) { rule->flags |= RULE_MAXLINE; rule->maxline = (int)ls_lua_tonumber(L, -1); } ls_lua_pop(L, 1); } return 0; }
void compile_builtins() { /* Note that we cannot share the PARSE object between the different */ /* variants of a given rule name, since we do no know if the Jambase */ /* or Jamfile will redefine one of the rules and thus free the PARSE */ /* object. */ bindrule( "Always" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TOUCHED ); bindrule( "ALWAYS" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TOUCHED ); bindrule( "Depends" )->procedure = parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_DEPENDS ); bindrule( "DEPENDS" )->procedure = parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_DEPENDS ); bindrule( "Echo" )->procedure = parse_make( builtin_echo, P0, P0, C0, C0, L0, L0, 0 ); bindrule( "ECHO" )->procedure = parse_make( builtin_echo, P0, P0, C0, C0, L0, L0, 0 ); bindrule( "Exit" )->procedure = parse_make( builtin_exit, P0, P0, C0, C0, L0, L0, 0 ); bindrule( "EXIT" )->procedure = parse_make( builtin_exit, P0, P0, C0, C0, L0, L0, 0 ); bindrule( "Includes" )->procedure = parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_INCLUDES ); bindrule( "INCLUDES" )->procedure = parse_make( builtin_depends, P0, P0, C0, C0, L0, L0, T_DEPS_INCLUDES ); bindrule( "Leaves" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_LEAVES ); bindrule( "LEAVES" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_LEAVES ); bindrule( "NoCare" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOCARE ); bindrule( "NOCARE" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOCARE ); bindrule( "NOTIME" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOTFILE ); bindrule( "NotFile" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOTFILE ); bindrule( "NOTFILE" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOTFILE ); bindrule( "NoUpdate" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOUPDATE ); bindrule( "NOUPDATE" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_NOUPDATE ); bindrule( "Temporary" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TEMP ); bindrule( "TEMPORARY" )->procedure = parse_make( builtin_flags, P0, P0, C0, C0, L0, L0, T_FLAG_TEMP ); }
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; }
static LIST* call_python_function(RULE* r, FRAME* frame) { LIST* result = 0; PyObject* arguments = PyTuple_New(frame->args->count); int i ; PyObject* py_result; for(i = 0; i < frame->args->count; ++i) { PyObject* arg = PyList_New(0); LIST* l = lol_get( frame->args, i); for(; l; l = l->next) { PyObject* v = PyString_FromString(l->string); /* Steals reference to 'v' */ PyList_Append(arg, v); } /* Steals reference to 'arg' */ PyTuple_SetItem(arguments, i, arg); } py_result = PyObject_CallObject(r->python_function, arguments); Py_DECREF(arguments); if (py_result != NULL) { if (PyList_Check(py_result)) { int size = PyList_Size(py_result); int i; for(i = 0; i < size; ++i) { PyObject* item = PyList_GetItem(py_result, i); if (PyString_Check(item)) { result = list_new(result, newstr(PyString_AsString(item))); } else { fprintf(stderr, "Non-string object returned by Python call\n"); } } } else if (PyInstance_Check(py_result)) { static char instance_name[1000]; static char imported_method_name[1000]; module_t* m; PyObject* method; PyObject* method_name = PyString_FromString("foo"); RULE* r; fprintf(stderr, "Got instance!\n"); snprintf(instance_name, 1000, "pyinstance%d", python_instance_number); snprintf(imported_method_name, 1000, "pyinstance%d.foo", python_instance_number); ++python_instance_number; m = bindmodule(instance_name); /* This is expected to get bound method. */ method = PyObject_GetAttr(py_result, method_name); r = bindrule( imported_method_name, root_module() ); r->python_function = method; result = list_new(0, newstr(instance_name)); Py_DECREF(method_name); } else if (py_result == Py_None) { result = L0; } else { fprintf(stderr, "Non-list object returned by Python call\n"); } Py_DECREF(py_result); } else { PyErr_Print(); fprintf(stderr,"Call failed\n"); } return result; }
void load_builtins() { bindrule( "Always" )->procedure = bindrule( "ALWAYS" )->procedure = parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_TOUCHED ); bindrule( "Depends" )->procedure = bindrule( "DEPENDS" )->procedure = parse_make( builtin_depends, P0, P0, P0, C0, C0, 0 ); bindrule( "echo" )->procedure = bindrule( "Echo" )->procedure = bindrule( "ECHO" )->procedure = parse_make( builtin_echo, P0, P0, P0, C0, C0, 0 ); bindrule( "exit" )->procedure = bindrule( "Exit" )->procedure = bindrule( "EXIT" )->procedure = parse_make( builtin_exit, P0, P0, P0, C0, C0, 0 ); bindrule( "Glob" )->procedure = bindrule( "GLOB" )->procedure = parse_make( builtin_glob, P0, P0, P0, C0, C0, 0 ); bindrule( "Includes" )->procedure = bindrule( "INCLUDES" )->procedure = parse_make( builtin_depends, P0, P0, P0, C0, C0, 1 ); bindrule( "Leaves" )->procedure = bindrule( "LEAVES" )->procedure = parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_LEAVES ); bindrule( "Match" )->procedure = bindrule( "MATCH" )->procedure = parse_make( builtin_match, P0, P0, P0, C0, C0, 0 ); bindrule( "ForceCare" )->procedure = parse_make( builtin_flags_forcecare, P0, P0, P0, C0, C0, T_FLAG_FORCECARE ); bindrule( "NoCare" )->procedure = bindrule( "NOCARE" )->procedure = parse_make( builtin_flags_nocare, P0, P0, P0, C0, C0, T_FLAG_NOCARE ); bindrule( "NOTIME" )->procedure = bindrule( "NotFile" )->procedure = bindrule( "NOTFILE" )->procedure = parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_NOTFILE ); bindrule( "NoUpdate" )->procedure = bindrule( "NOUPDATE" )->procedure = parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_NOUPDATE ); #ifdef OPT_BUILTIN_SUBST_EXT bindrule( "Subst" )->procedure = parse_make( builtin_subst, P0, P0, P0, C0, C0, 0 ); bindrule( "SubstLiteralize" )->procedure = parse_make( builtin_subst_literalize, P0, P0, P0, C0, C0, 0 ); #endif bindrule( "Temporary" )->procedure = bindrule( "TEMPORARY" )->procedure = parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_TEMP ); #ifdef OPT_MULTIPASS_EXT bindrule( "QueueJamfile" )->procedure = parse_make( builtin_queuejamfile, P0, P0, P0, C0, C0, 0 ); #endif #ifdef OPT_BUILTIN_MD5_EXT bindrule( "MD5" )->procedure = parse_make( builtin_md5, P0, P0, P0, C0, C0, 0 ); bindrule( "MD5File" )->procedure = parse_make( builtin_md5file, P0, P0, P0, C0, C0, 0 ); #endif /* OPT_BUILTIN_MD5_EXT */ #ifdef OPT_BUILTIN_MATH_EXT bindrule( "Math" )->procedure = parse_make( builtin_math, P0, P0, P0, C0, C0, 0 ); #endif #ifdef NT #ifdef OPT_BUILTIN_W32_GETREG_EXT bindrule( "W32_GETREG" )->procedure = parse_make( builtin_w32_getreg, P0, P0, P0, C0, C0, 0 ); #endif #ifdef OPT_BUILTIN_W32_GETREG64_EXT bindrule( "W32_GETREG64" )->procedure = parse_make( builtin_w32_getreg64, P0, P0, P0, C0, C0, 0 ); #endif #ifdef OPT_BUILTIN_W32_SHORTNAME_EXT bindrule( "W32_SHORTNAME" )->procedure = parse_make( builtin_w32_shortname, P0, P0, P0, C0, C0, 0 ); #endif #endif #ifdef OPT_HEADER_CACHE_EXT bindrule( "UseDepCache" )->procedure = parse_make( builtin_usedepcache, P0, P0, P0, C0, C0, T_FLAG_USEDEPCACHE ); #endif #ifdef OPT_BUILTIN_MD5CACHE_EXT bindrule( "UseFileCache" )->procedure = parse_make( builtin_usefilecache, P0, P0, P0, C0, C0, T_FLAG_USEFILECACHE ); bindrule( "OptionalFileCache" )->procedure = parse_make( builtin_usefilecache, P0, P0, P0, C0, C0, T_FLAG_USEFILECACHE | T_FLAG_OPTIONALFILECACHE ); bindrule( "UseCommandLine" )->procedure = parse_make( builtin_usecommandline, P0, P0, P0, C0, C0, T_FLAG_USECOMMANDLINE ); bindrule( "ScanContents" )->procedure = bindrule( "SCANCONTENTS" )->procedure = parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_SCANCONTENTS ); #endif #ifdef OPT_BUILTIN_NEEDS_EXT bindrule( "MightNotUpdate" )->procedure = parse_make( builtin_flags, P0, P0, P0, C0, C0, T_FLAG_MIGHTNOTUPDATE ); bindrule( "Needs" )->procedure = bindrule( "NEEDS" )->procedure = parse_make( builtin_depends, P0, P0, P0, C0, C0, 2 ); #endif #ifdef OPT_BUILTIN_LUA_SUPPORT_EXT bindrule( "LuaString" )->procedure = parse_make( builtin_luastring, P0, P0, P0, C0, C0, 0 ); bindrule( "LuaFile" )->procedure = parse_make( builtin_luafile, P0, P0, P0, C0, C0, 0 ); bindrule( "UseMD5Callback" )->procedure = parse_make( builtin_usemd5callback, P0, P0, P0, C0, C0, 0 ); #endif #ifdef OPT_SERIAL_OUTPUT_EXT bindrule( "Shell" )->procedure = parse_make( builtin_shell, P0, P0, P0, C0, C0, 0 ); #endif #ifdef OPT_BUILTIN_GROUPBYVAR_EXT bindrule( "GroupByVar" )->procedure = parse_make( builtin_groupbyvar, P0, P0, P0, C0, C0, 0 ); #endif #ifdef OPT_BUILTIN_SPLIT_EXT bindrule( "Split" )->procedure = parse_make( builtin_split, P0, P0, P0, C0, C0, 0 ); #endif bindrule( "ExpandFileList" )->procedure = parse_make( builtin_expandfilelist, P0, P0, P0, C0, C0, 0 ); bindrule( "ListSort" )->procedure = parse_make( builtin_listsort, P0, P0, P0, C0, C0, 0 ); }