int LS_jam_setvar(ls_lua_State *L) { int numParams = ls_lua_gettop(L); if (numParams < 2 || numParams > 3) return 0; if (!ls_lua_isstring(L, 1)) return 0; if (numParams == 2) { var_set(ls_lua_tostring(L, 1), luahelper_addtolist(L, L0, 2), VAR_SET); } else { TARGET *t; if (!ls_lua_isstring(L, 2)) return 0; t = bindtarget(ls_lua_tostring(L, 1)); t->settings = addsettings(t->settings, VAR_SET, ls_lua_tostring(L, 2), luahelper_addtolist(L, L0, 3)); } return 0; }
static SETTINGS * make1settings( LIST *vars ) { SETTINGS *settings = 0; for( ; vars; vars = list_next( vars ) ) { LIST *l = var_get( vars->string ); LIST *nl = 0; for( ; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); /* Make sure the target is bound */ if( t->binding == T_BIND_UNBOUND ) make1bind( t ); /* Build new list */ nl = list_new( nl, copystr( t->boundname ) ); } /* Add to settings chain */ settings = addsettings( settings, 0, vars->string, nl ); } return settings; }
LIST * builtin_usefilecache( PARSE *parse, LOL *args, int *jmp ) { LIST *l = lol_get( args, 0 ); LIST *l2 = lol_get( args, 1 ); const char* cachevar = l2 ? l2->string : "generic"; BUFFER buff; buffer_init( &buff ); buffer_addstring( &buff, "FILECACHE.", 10 ); buffer_addstring( &buff, cachevar, strlen( cachevar ) ); buffer_addchar( &buff, 0 ); for( ; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); t->settings = addsettings( t->settings, VAR_SET, "FILECACHE", list_new( L0, buffer_ptr( &buff ), 0 ) ); t->flags |= parse->num; } buffer_free( &buff ); return L0; }
LIST * compile_foreach( PARSE * parse, FRAME * frame ) { LIST * nv = parse_evaluate( parse->left, frame ); LIST * l; SETTINGS * s = 0; if ( parse->num ) { s = addsettings( s, VAR_SET, parse->string, L0 ); pushsettings( s ); } /* Call var_set to reset $(parse->string) for each val. */ for ( l = nv; l; l = list_next( l ) ) { LIST * val = list_new( L0, copystr( l->string ) ); var_set( parse->string, val, VAR_SET ); list_free( parse_evaluate( parse->right, frame ) ); } if ( parse->num ) { popsettings( s ); freesettings( s ); } list_free( nv ); return L0; }
static SETTINGS * make1settings( LIST *vars ) { SETTINGS *settings = 0; for( ; vars; vars = list_next( vars ) ) { LIST *l = var_get( vars->string ); LIST *nl = 0; for( ; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); /* Make sure the target is bound, warning if it is not in the */ /* dependency graph. */ if( t->binding == T_BIND_UNBOUND ) make1bind( t, 1 ); /* Build new list */ nl = list_new( nl, t->boundname, 1 ); } /* Add to settings chain */ settings = addsettings( settings, 0, vars->string, nl ); } return settings; }
static SETTINGS * make1settings( struct module_t * module, LIST * vars ) { SETTINGS * settings = 0; LISTITER vars_iter = list_begin( vars ); LISTITER const vars_end = list_end( vars ); for ( ; vars_iter != vars_end; vars_iter = list_next( vars_iter ) ) { LIST * const l = var_get( module, list_item( vars_iter ) ); LIST * nl = L0; LISTITER iter = list_begin( l ); LISTITER const end = list_end( l ); for ( ; iter != end; iter = list_next( iter ) ) { TARGET * const t = bindtarget( list_item( iter ) ); /* Make sure the target is bound. */ if ( t->binding == T_BIND_UNBOUND ) make1bind( t ); /* Build a new list. */ nl = list_push_back( nl, object_copy( t->boundname ) ); } /* Add to settings chain. */ settings = addsettings( settings, VAR_SET, list_item( vars_iter ), nl ); } return settings; }
SETTINGS * copysettings( SETTINGS * head ) { SETTINGS * copy = 0; SETTINGS * v; for ( v = head; v; v = v->next ) copy = addsettings( copy, VAR_SET, v->symbol, list_copy( 0, v->value ) ); return copy; }
LIST * builtin_usedepcache( PARSE *parse, LOL *args, int *jmp ) { LIST *l = lol_get( args, 0 ); LIST *l2 = lol_get( args, 1 ); for( ; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); if ( l2 ) t->settings = addsettings( t->settings, VAR_SET, "DEPCACHE", list_copy( L0, l2 ) ); else t->settings = addsettings( t->settings, VAR_SET, "DEPCACHE", L0 ); t->flags |= parse->num; } return L0; }
LIST * builtin_usemd5callback( PARSE *parse, LOL *args, int *jmp ) { LIST *l = lol_get( args, 0 ); LIST *l2 = lol_get( args, 1 ); for( ; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); t->settings = addsettings( t->settings, VAR_SET, "MD5CALLBACK", list_copy( L0, l2 ) ); } return L0; }
LIST * builtin_usecommandline( PARSE *parse, LOL *args, int *jmp ) { LIST *l = lol_get( args, 0 ); LIST *l2 = lol_get( args, 1 ); for( ; l; l = list_next( l ) ) { TARGET *t = bindtarget( l->string ); t->settings = addsettings( t->settings, VAR_SET, "COMMANDLINE", list_copy( L0, l2 ) ); t->flags |= parse->num; } return L0; }
LIST * compile_settings( PARSE *parse, LOL *args, int *jmp ) { LIST *nt = (*parse->left->func)( parse->left, args, jmp ); LIST *ns = (*parse->third->func)( parse->third, args, jmp ); LIST *targets = (*parse->right->func)( parse->right, args, jmp ); LISTITEM *ts; if( DEBUG_COMPILE ) { debug_compile( 0, "set" ); list_print( nt ); printf( "on " ); list_print( targets ); printf( " %s ", set_names[ parse->num ] ); list_print( ns ); printf( "\n" ); } /* Call addsettings to save variable setting */ /* addsettings keeps ns, so need to copy it */ /* Pass append flag to addsettings() */ for( ts = list_first(targets); ts; ts = list_next( ts ) ) { TARGET *t = bindtarget( list_value(ts) ); LISTITEM *l; for( l = list_first(nt); l; l = list_next( l ) ) t->settings = addsettings( t->settings, parse->num, list_value(l), list_copy( NULL, ns ) ); } list_free( nt ); list_free( targets ); return ns; }
LIST * compile_settings( PARSE *parse, FRAME *frame ) { LIST *nt = parse_evaluate( parse->left, frame ); LIST *ns = parse_evaluate( parse->third, frame ); LIST *targets = parse_evaluate( parse->right, frame ); LIST *ts; int append = parse->num == ASSIGN_APPEND; if( DEBUG_COMPILE ) { debug_compile( 0, "set", frame); list_print( nt ); printf( " on " ); list_print( targets ); printf( " %s ", append ? "+=" : "=" ); list_print( ns ); printf( "\n" ); } /* Call addsettings to save variable setting */ /* addsettings keeps ns, so need to copy it */ /* Pass append flag to addsettings() */ for( ts = targets; ts; ts = list_next( ts ) ) { TARGET *t = bindtarget( ts->string ); LIST *l; for( l = nt; l; l = list_next( l ) ) t->settings = addsettings( t->settings, append, l->string, list_copy( (LIST*)0, ns ) ); } list_free( nt ); list_free( targets ); return ns; }
LIST * compile_local( PARSE *parse, LOL *args, int *jmp ) { LISTITEM *l; SETTINGS *s = 0; LIST *nt = (*parse->left->func)( parse->left, args, jmp ); LIST *ns = (*parse->right->func)( parse->right, args, jmp ); LIST *result; if( DEBUG_COMPILE ) { debug_compile( 0, "local" ); list_print( nt ); printf( " = " ); list_print( ns ); printf( "\n" ); } /* Initial value is ns */ for( l = list_first(nt); l; l = list_next( l ) ) s = addsettings( s, 0, list_value(l), list_copy( NULL, ns ) ); list_free( ns ); list_free( nt ); /* Note that callees of the current context get this "local" */ /* variable, making it not so much local as layered. */ pushsettings( s ); result = (*parse->third->func)( parse->third, args, jmp ); popsettings( s ); freesettings( s ); return result; }
LIST * compile_local( PARSE *parse, FRAME *frame ) { LIST *l; SETTINGS *s = 0; LIST *nt = parse_evaluate( parse->left, frame ); LIST *ns = parse_evaluate( parse->right, frame ); LIST *result; if( DEBUG_COMPILE ) { debug_compile( 0, "local", frame); list_print( nt ); printf( " = " ); list_print( ns ); printf( "\n" ); } /* Initial value is ns */ for( l = nt; l; l = list_next( l ) ) s = addsettings( s, 0, l->string, list_copy( (LIST*)0, ns ) ); list_free( ns ); list_free( nt ); /* Note that callees of the current context get this "local" */ /* variable, making it not so much local as layered. */ pushsettings( s ); result = parse_evaluate( parse->third, frame ); popsettings( s ); freesettings( s ); return result; }
LIST * compile_settings( PARSE * parse, FRAME * frame ) { LIST * nt = parse_evaluate( parse->left, frame ); LIST * ns = parse_evaluate( parse->third, frame ); LIST * targets = parse_evaluate( parse->right, frame ); LIST * ts; char const * trace; int setflag = assign_var_mode( parse->num, &trace ); if ( DEBUG_COMPILE ) { debug_compile( 0, "set", frame ); list_print( nt ); printf( " on " ); list_print( targets ); printf( " %s ", trace ); list_print( ns ); printf( "\n" ); } /* Call addsettings() to save variable setting. addsettings() keeps ns, so * need to copy it. Pass append flag to addsettings(). */ for ( ts = targets; ts; ts = list_next( ts ) ) { TARGET * t = bindtarget( ts->string ); LIST * l; for ( l = nt; l; l = list_next( l ) ) t->settings = addsettings( t->settings, setflag, l->string, list_copy( (LIST *)0, ns ) ); } list_free( nt ); list_free( targets ); return ns; }
/* * collect_arguments() - local argument checking and collection */ static SETTINGS * collect_arguments( RULE* rule, FRAME* frame ) { SETTINGS *locals = 0; LOL * all_actual = frame->args; LOL * all_formal = rule->arguments ? rule->arguments->data : 0; if ( all_formal ) /* Nothing to set; nothing to check */ { int max = all_formal->count > all_actual->count ? all_formal->count : all_actual->count; int n; for ( n = 0; n < max ; ++n ) { LIST *actual = lol_get( all_actual, n ); char *type_name = 0; LIST *formal; for ( formal = lol_get( all_formal, n ); formal; formal = formal->next ) { char* name = formal->string; if ( is_type_name(name) ) { if ( type_name ) argument_error( "missing argument name before type name:", rule, frame, formal ); if ( !formal->next ) argument_error( "missing argument name after type name:", rule, frame, formal ); type_name = formal->string; } else { LIST* value = 0; char modifier; LIST* arg_name = formal; /* hold the argument name for type checking */ int multiple = 0; /* Stop now if a variable number of arguments are specified */ if ( name[0] == '*' && name[1] == 0 ) return locals; modifier = arg_modifier( formal ); if ( !actual && modifier != '?' && modifier != '*' ) argument_error( "missing argument", rule, frame, formal ); switch ( modifier ) { case '+': case '*': value = list_copy( 0, actual ); multiple = 1; actual = 0; /* skip an extra element for the modifier */ formal = formal->next; break; case '?': /* skip an extra element for the modifier */ formal = formal->next; /* fall through */ default: if ( actual ) /* in case actual is missing */ { value = list_new( 0, actual->string ); actual = actual->next; } } locals = addsettings(locals, VAR_SET, name, value); locals->multiple = multiple; type_check( type_name, value, frame, rule, arg_name ); type_name = 0; } } if ( actual ) { argument_error( "extra argument", rule, frame, actual ); } } } return locals; }
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; }
static CMD * make1cmds( ACTIONS *a0 ) #endif { CMD *cmds = 0; LIST *shell = var_get( "JAMSHELL" ); /* shell is per-target */ /* Step through actions */ /* Actions may be shared with other targets or grouped with */ /* RULE_TOGETHER, so actions already seen are skipped. */ for( ; a0; a0 = a0->next ) { RULE *rule = a0->action->rule; SETTINGS *boundvars; LIST *nt, *ns; ACTIONS *a1; int start, chunk, length, maxline; TARGETS *autosettingsreverse = 0; TARGETS *autot; #ifdef OPT_MULTIPASS_EXT if ( a0->action->pass != actionpass ) continue; #endif /* Only do rules with commands to execute. */ /* If this action has already been executed, use saved status */ #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { printf( "make1cmds\t--\t%s (actions %s, running %s)\n" , rule->name, rule->actions ? "yes" : "no", a0->action->running ? "yes" : "no" ); } #endif if( !rule->actions || a0->action->running ) continue; #ifdef OPT_REMOVE_EMPTY_DIRS_EXT if ( rule->flags & RULE_REMOVEEMPTYDIRS ) { for( a1 = a0; a1; a1 = a1->next ) { TARGETS* sources; for ( sources = a1->action->sources; sources; sources = sources->next ) { emptydirtargets = list_new( emptydirtargets, sources->target->name, 1 ); } } } #endif for ( autot = a0->action->autosettings; autot; autot = autot->next ) { if ( autot->target != t ) pushsettings( autot->target->settings ); autosettingsreverse = targetentryhead( autosettingsreverse, autot->target, 0 ); } pushsettings( t->settings ); a0->action->running = 1; #ifdef OPT_ACTIONS_WAIT_FIX a0->action->run_tgt = t; #endif /* Make LISTS of targets and sources */ /* If `execute together` has been specified for this rule, tack */ /* on sources from each instance of this rule for this target. */ #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { LIST *list = make1list(L0, a0->action->targets, 0); printf("make1cmds\t--\ttargets: "); list_print(list); list_free(list); printf("\n"); list = make1list(L0, a0->action->sources, 0); printf("make1cmds\t--\tsources: "); list_print(list); list_free(list); printf("\n"); } #endif #ifdef OPT_BUILTIN_MD5CACHE_EXT if (t->filecache_generate || t->filecache_use) { LIST* targets = make1list_unbound( L0, a0->action->targets, 0 ); LIST* sources = make1list_unbound( L0, a0->action->sources, rule->flags ); nt = L0; ns = L0; if ( strncmp( rule->name, "batched_", 8 ) == 0 ) { int anycacheable = 0; for( ; targets; targets = targets->next, sources = ( sources == NULL ? sources : sources->next ) ) { TARGET *t = bindtarget(targets->string); TARGET *s = sources!=NULL ? bindtarget(sources->string) : NULL; /* if this target could be cacheable */ if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate || t->filecache_use) ) { /* find its final md5sum */ MD5_CTX context; MD5SUM buildsumorg; anycacheable = 1; memcpy(&buildsumorg, &t->buildmd5sum, sizeof(t->buildmd5sum)); MD5Init( &context ); MD5Update( &context, t->buildmd5sum, sizeof( t->buildmd5sum ) ); { TARGET *outt = bindtarget( t->boundname ); outt->flags |= T_FLAG_USEFILECACHE; MD5Final( outt->buildmd5sum, &context ); memcpy(&t->buildmd5sum, &outt->buildmd5sum, sizeof(t->buildmd5sum)); } if (DEBUG_MD5HASH) { printf( "Cacheable: %s buildmd5: %s org: %s\n", t->boundname, md5tostring(t->buildmd5sum), md5tostring(buildsumorg) ); } /* if using cache is allowed */ if (t->filecache_use) { const char *cachedname; /* if the target is available in the cache */ cachedname = filecache_getfilename(t, t->buildmd5sum, ".doesntwork"); if (cachedname!=NULL) { time_t cachedtime; if ( file_time( cachedname, &cachedtime ) == 0 ) { /* try to get it from the cache */ if (copyfile(t->boundname, cachedname, NULL)) { printf( "Using cached %s\n", t->name ); continue; } else { printf( "Cannot retrieve %s from cache (will build normally)\n", t->name ); } } else { if( DEBUG_MD5HASH) { printf( "Cannot find %s in cache as %s\n", t->name, cachedname ); } } } } /* Build new lists */ nt = list_new( nt, t->boundname, 1 ); if (s) ns = list_new( ns, s->boundname, 1 ); } } if ( !anycacheable ) { nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, rule->flags ); } } else { int allcached = 1; popsettings( t->settings ); for( ; targets; targets = list_next(targets) ) { TARGET *t = bindtarget(targets->string); // TARGET *s = sources!=NULL ? bindtarget(sources->string) : NULL; TARGETS *c; TARGET *outt; LIST *filecache = 0; if ( t->flags & T_FLAG_USEFILECACHE ) { pushsettings( t->settings ); filecache = filecache_fillvalues( t ); popsettings( t->settings ); } /* if this target could be cacheable */ if ( (t->flags & T_FLAG_USEFILECACHE) && (t->filecache_generate || t->filecache_use) ) { /* find its final md5sum */ MD5_CTX context; if( DEBUG_MD5HASH ) { printf( "------------------------------------------------\n" ); printf( "------------------------------------------------\n" ); printf( "------------------------------------------------\n" ); } /* sort all dependents by name, so we can make reliable md5sums */ t->depends = make0sortbyname( t->depends ); MD5Init( &context ); /* add the path of the file to the sum - it is significant because one command can create more than one file */ MD5Update( &context, (unsigned char*)t->name, (unsigned int)strlen( t->name ) ); /* add in the COMMANDLINE */ if ( t->flags & T_FLAG_USECOMMANDLINE ) { SETTINGS *vars; for ( vars = t->settings; vars; vars = vars->next ) { if ( vars->symbol[0] == 'C' && strcmp( vars->symbol, "COMMANDLINE" ) == 0 ) { LIST *list; for ( list = vars->value; list; list = list->next ) { MD5Update( &context, (unsigned char*)list->string, (unsigned int)strlen( list->string ) ); if( DEBUG_MD5HASH ) printf( "\t\tCOMMANDLINE: %s\n", list->string ); } break; } } } /* for each dependencies */ for( c = t->depends; c; c = c->next ) { /* If this is a "Needs" dependency, don't care about its contents. */ if (c->needs) { continue; } /* add name of the dependency and its contents */ make0calcmd5sum( c->target, 1 ); if ( c->target->buildmd5sum_calculated ) { MD5Update( &context, (unsigned char*)c->target->name, (unsigned int)strlen( c->target->name ) ); MD5Update( &context, c->target->buildmd5sum, sizeof( c->target->buildmd5sum ) ); } } outt = bindtarget( t->boundname ); outt->flags |= T_FLAG_USEFILECACHE; outt->filecache_generate = t->filecache_generate; outt->filecache_use = t->filecache_use; outt->settings = addsettings( outt->settings, VAR_SET, "FILECACHE", list_new( L0, filecache->string, 1 ) ); MD5Final( outt->buildmd5sum, &context ); if (DEBUG_MD5HASH) { printf( "Cacheable: %s buildmd5: %s\n", t->boundname, md5tostring(outt->buildmd5sum) ); } /* if using cache is allowed */ if ( t->filecache_use && allcached ) { allcached = filecache_retrieve( t, outt->buildmd5sum ); } else { allcached = 0; } } else { allcached = 0; } } pushsettings( t->settings ); if ( !allcached ) { nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, rule->flags ); } } list_free( targets ); list_free( sources ); /* if no targets survived (all were retrieved from the cache) or no sources survived (all are up to date) */ if (nt==NULL) { // || ns==NULL) { /* skip this action */ list_free(ns); popsettings( t->settings ); for ( autot = autosettingsreverse; autot; autot = autot->next ) { if ( autot->target != t ) pushsettings( autot->target->settings ); } continue; } } else { #if 0 if ( strncmp( rule->name, "batched_", 8 ) == 0 ) { TARGETS* targets = a0->action->targets; TARGETS* sources = a0->action->sources; int anycacheable = 0; nt = L0; ns = L0; /* walk sources and targets simultaneously */ for( ; targets; targets = targets->next, sources = (sources==NULL?sources:sources->next) ) { TARGET *t = targets->target; TARGET *s = sources!=NULL ? sources->target : NULL; /* Sources to 'actions existing' are never in the dependency */ /* graph (if they were, they'd get built and 'existing' would */ /* be superfluous, so throttle warning message about independent */ /* targets. */ if( t->binding == T_BIND_UNBOUND ) make1bind( t, 0 ); if( s!=NULL) { if ( s->binding == T_BIND_UNBOUND ) make1bind( s, !( rule->flags & RULE_EXISTING ) ); if ( s->binding == T_BIND_UNBOUND ) printf("Warning using unbound source %s for batched action.\n", s->name); } if( ( rule->flags & RULE_EXISTING ) && s!=NULL && s->binding != T_BIND_EXISTS ) continue; if( t->fate < T_FATE_BUILD ) continue; /* Build new lists */ nt = list_new( nt, t->boundname, 1 ); if (s!=NULL) { ns = list_new( ns, s->boundname, 1 ); } } if (sources!=NULL) { printf("warning: more sources than targets in a batched action!\n"); } } else { #endif nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, rule->flags ); #if 0 } #endif } #else nt = make1list( L0, a0->action->targets, 0 ); ns = make1list( L0, a0->action->sources, rule->flags ); #endif if( rule->flags & RULE_TOGETHER ) for( a1 = a0->next; a1; a1 = a1->next ) #ifdef OPT_MULTIPASS_EXT if( a1->action->pass == actionpass && a1->action->rule == rule && !a1->action->running ) #else if( a1->action->rule == rule && !a1->action->running ) #endif { ns = make1list( ns, a1->action->sources, rule->flags ); a1->action->running = 1; #ifdef OPT_ACTIONS_WAIT_FIX a1->action->run_tgt = t; #endif } /* If doing only updated (or existing) sources, but none have */ /* been updated (or exist), skip this action. */ if( !ns && ( rule->flags & ( RULE_UPDATED | RULE_EXISTING ) ) ) { list_free( nt ); #ifdef OPT_DEBUG_MAKE1_LOG_EXT if (DEBUG_MAKE1) { const char* desc = 0; if ((rule->flags & (RULE_UPDATED | RULE_EXISTING)) == (RULE_UPDATED | RULE_EXISTING)) { desc = "updated/existing"; } else if (rule->flags & RULE_UPDATED) { desc = "updated"; } else if (rule->flags & RULE_EXISTING) { desc = "existing"; } printf( "make1cmds\t--\t%s (skipping actions by %s)\n" , rule->name, desc ); } #endif /* OPT_DEBUG_MAKE1_LOG_EXT */ popsettings( t->settings ); for ( autot = autosettingsreverse; autot; autot = autot->next ) { if ( autot->target != t ) pushsettings( autot->target->settings ); } continue; } /* If we had 'actions xxx bind vars' we bind the vars now */ boundvars = make1settings( rule->bindlist ); pushsettings( boundvars ); /* * Build command, starting with all source args. * * If cmd_new returns 0, it's because the resulting command * length is > MAXLINE. In this case, we'll slowly reduce * the number of source arguments presented until it does * fit. This only applies to actions that allow PIECEMEAL * commands. * * While reducing slowly takes a bit of compute time to get * things just right, it's worth it to get as close to MAXLINE * as possible, because launching the commands we're executing * is likely to be much more compute intensive! * * Note we loop through at least once, for sourceless actions. * * Max line length is the action specific maxline or, if not * given or bigger than MAXLINE, MAXLINE. */ start = 0; chunk = length = list_length( ns ); /* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */ maxline = rule->maxline; /* commented so jamgram.y can compile #else maxline = rule->flags / RULE_MAXLINE; #endif */ #ifdef OPT_PIECEMEAL_PUNT_EXT maxline = maxline && maxline < CMDBUF ? maxline : CMDBUF; #else maxline = maxline && maxline < MAXLINE ? maxline : MAXLINE; #endif do { /* Build cmd: cmd_new consumes its lists. */ /* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */ int thischunk = rule->maxtargets != 0 ? (chunk < rule->maxtargets ? chunk : rule->maxtargets) : chunk; CMD *cmd = cmd_new( rule, list_copy( L0, nt ), list_sublist( ns, start, thischunk ), list_copy( L0, shell ), maxline ); /* commented so jamgram.y can compile #else CMD *cmd = cmd_new( rule, list_copy( L0, nt ), list_sublist( ns, start, chunk ), list_copy( L0, shell ), maxline ); #endif */ if( cmd ) { /* It fit: chain it up. */ if( !cmds ) cmds = cmd; else cmds->tail->next = cmd; cmds->tail = cmd; /* commented out so jamgram.y can compile #ifdef OPT_ACTION_MAXTARGETS_EXT */ start += thischunk; /* commented out so jamgram.y can compile #else start += chunk; #endif */ } else if( ( rule->flags & RULE_PIECEMEAL ) && chunk > 1 ) { /* Reduce chunk size slowly. */ chunk = chunk * 9 / 10; } else { /* Too long and not splittable. */ #ifdef OPT_PIECEMEAL_PUNT_EXT if (maxline < CMDBUF) { maxline = CMDBUF; continue; } #endif printf( "%s actions too long (max %d)!\n", rule->name, maxline ); exit( EXITBAD ); } } while( start < length ); /* These were always copied when used. */ list_free( nt ); list_free( ns ); /* Free the variables whose values were bound by */ /* 'actions xxx bind vars' */ popsettings( boundvars ); freesettings( boundvars ); popsettings( t->settings ); for ( autot = autosettingsreverse; autot; autot = autot->next ) { if ( autot->target != t ) pushsettings( autot->target->settings ); } } return cmds; }