LIST * builtin_md5file( PARSE *parse, LOL *args, int *jmp ) { MD5_CTX context; unsigned char digest[16]; unsigned char digest_string[33]; unsigned char* p; int i; LIST *l; LIST *result; const size_t BUFFER_SIZE = 100 * 1024; unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE); MD5Init(&context); /* For each argument */ for (i = 0; i < args->count; ++i) { l = lol_get(args, i); if (l) { do { FILE* file; TARGET *t = bindtarget(l->string); pushsettings( t->settings ); t->boundname = search( t->name, &t->time ); popsettings( t->settings ); file = fopen(t->boundname, "rb"); if (file) { size_t readSize; do { readSize = fread(buffer, 1, BUFFER_SIZE, file); MD5Update(&context, buffer, readSize); } while (readSize != 0); fclose(file); } l = list_next(l); } while (l); } } free(buffer); MD5Final(digest, &context); p = digest_string; for (i = 0, p = digest_string; i < 16; i++, p += 2) { sprintf((char*)p, "%02x", digest[i]); } *p = 0; result = list_new(L0, (const char*)digest_string, 0); return result; }
void filecache_disable(TARGET *t) { BUFFER buff; LIST *filecache; pushsettings( t->settings ); filecache = var_get( "FILECACHE" ); if ( !filecache ) { popsettings( t->settings ); return; } buffer_init(&buff); buffer_addstring(&buff, filecache->string, strlen(filecache->string)); buffer_addstring(&buff, ".USE", 4); buffer_addchar(&buff, 0); var_set(buffer_ptr(&buff), list_new(L0, "0", 0), VAR_SET); buffer_free(&buff); buffer_init(&buff); buffer_addstring(&buff, filecache->string, strlen(filecache->string)); buffer_addstring(&buff, ".GENERATE", 9); buffer_addchar(&buff, 0); var_set(buffer_ptr(&buff), list_new(L0, "0", 0), VAR_SET); buffer_free(&buff); }
static const char * cache_name( void ) { static OBJECT * name = 0; if ( !name ) { OBJECT * hcachename = object_new( "HCACHEFILE" ); LIST * hcachevar = var_get( hcachename ); object_free( hcachename ); if ( hcachevar ) { TARGET * t = bindtarget( hcachevar->value ); pushsettings( t->settings ); /* Do not expect the cache file to be generated, so pass 0 as the * third argument to search. Expect the location to be specified via * LOCATE, so pass 0 as the fourth arugment. */ object_free( t->boundname ); t->boundname = search( t->name, &t->time, 0, 0 ); popsettings( t->settings ); if ( hcachevar ) name = object_copy( t->boundname ); } } return name ? object_str( name ) : 0; }
/* * swap_settings() - replace the settings from the current module and * target with those from the new module and target */ static void swap_settings( module_t** current_module , TARGET** current_target , module_t* new_module , TARGET* new_target) { if (new_module == root_module()) new_module = 0; if (new_target == *current_target && new_module == *current_module) return; if (*current_target) popsettings( (*current_target)->settings ); if (new_module != *current_module) { if (*current_module) exit_module( *current_module ); *current_module = new_module; if (new_module) enter_module( new_module ); } *current_target = new_target; if (new_target) pushsettings( new_target->settings ); }
/* Look up the __TIMING_RULE__ variable on the given target, and if * non-empty, invoke the rule it names, passing the given * timing_info */ static void call_timing_rule(TARGET* target, timing_info* time) { LIST* timing_rule; pushsettings(target->settings); timing_rule = var_get( "__TIMING_RULE__" ); popsettings(target->settings); if (timing_rule) { /* We'll prepend $(__TIMING_RULE__[2-]) to the first argument */ LIST* initial_args = list_copy( L0, timing_rule->next ); /* Prepare the argument list */ FRAME frame[1]; frame_init( frame ); /* First argument is the name of the timed target */ lol_add( frame->args, list_new( initial_args, target->name ) ); append_double_string(frame->args, time->user); append_double_string(frame->args, time->system); if( lol_get( frame->args, 2 ) ) evaluate_rule( timing_rule->string, frame ); /* Clean up */ frame_free( frame ); } }
static void bind_explicitly_located_target(void* xtarget, void* data) { TARGET* t = (TARGET*)xtarget; if (! (t->flags & T_FLAG_NOTFILE) ) { /* Check if there's a setting for LOCATE_TARGET */ SETTINGS* s = t->settings; for(; s ; s = s->next) { if (strcmp(s->symbol, "LOCATE") == 0) { pushsettings(t->settings); t->boundname = search( t->name, &t->time ); t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING; popsettings(t->settings); { LOCATED_TARGET lt, *lta = < lt.file_name = t->boundname; lt.target = t; if (!located_targets) located_targets = hashinit( sizeof(LOCATED_TARGET), "located targets" ); /* TODO: should check if we've entered the item or not. */ hashenter(located_targets, (HASHDATA **)<a); } break; } } } }
/* * Get a filename in cache for given md5sum. */ const char *filecache_getpath(TARGET *t) { char buffer[1024]; LIST *filecache; const char *cachedir = NULL; LIST *cachevar; pushsettings( t->settings ); filecache = var_get( "FILECACHE" ); if ( !filecache ) { popsettings( t->settings ); return NULL; } /* get directory where objcache should reside */ strcpy( buffer, filecache->string ); strcat( buffer, ".PATH" ); cachevar = var_get( buffer ); if( cachevar ) { TARGET *t = bindtarget( cachevar->string ); t->boundname = search( t->name, &t->time ); cachedir = copystr( t->boundname ); } popsettings( t->settings ); return cachedir; }
LIST * compile_on( PARSE *parse, FRAME *frame ) { LIST *nt = parse_evaluate( parse->left, frame ); LIST *result = 0; if( DEBUG_COMPILE ) { debug_compile( 0, "on", frame ); list_print( nt ); printf( "\n" ); } if( nt ) { TARGET *t = bindtarget( nt->string ); pushsettings( t->settings ); result = parse_evaluate( parse->right, frame ); popsettings( t->settings ); } list_free( nt ); return result; }
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; }
void filecache_disable(TARGET *t) { BUFFER buff; LIST *filecache; char const* filecacheStr; pushsettings( t->settings ); filecache = var_get( "FILECACHE" ); if ( !list_first(filecache) ) { popsettings( t->settings ); return; } filecacheStr = list_value(list_first(filecache)); buffer_init(&buff); buffer_addstring(&buff, filecacheStr, strlen(filecacheStr)); buffer_addstring(&buff, ".USE", 4); buffer_addchar(&buff, 0); var_set(buffer_ptr(&buff), list_append(L0, "0", 0), VAR_SET); buffer_free(&buff); buffer_init(&buff); buffer_addstring(&buff, filecacheStr, strlen(filecacheStr)); buffer_addstring(&buff, ".GENERATE", 9); buffer_addchar(&buff, 0); var_set(buffer_ptr(&buff), list_append(L0, "0", 0), VAR_SET); buffer_free(&buff); }
static const char * cache_name( void ) { static OBJECT * name = 0; if ( !name ) { LIST * hcachevar = var_get( root_module(), constant_HCACHEFILE ); if ( !list_empty( hcachevar ) ) { TARGET * t = bindtarget( list_front( hcachevar ) ); pushsettings( root_module(), t->settings ); /* Do not expect the cache file to be generated, so pass 0 as the * third argument to search. Expect the location to be specified via * LOCATE, so pass 0 as the fourth arugment. */ object_free( t->boundname ); t->boundname = search( t->name, &t->time, 0, 0 ); popsettings( root_module(), t->settings ); name = object_copy( t->boundname ); } } return name ? object_str( name ) : 0; }
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)); pushsettings(t->settings); var_set(ls_lua_tostring(L, 2), luahelper_addtolist(L, L0, 3), VAR_SET); popsettings(t->settings); } return 0; }
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 ); } }
static void make1bind( TARGET * t ) { if ( t->flags & T_FLAG_NOTFILE ) return; pushsettings( root_module(), t->settings ); object_free( t->boundname ); t->boundname = search( t->name, &t->time, 0, t->flags & T_FLAG_ISFILE ); t->binding = timestamp_empty( &t->time ) ? T_BIND_MISSING : T_BIND_EXISTS; popsettings( root_module(), t->settings ); }
static void make1bind( TARGET *t ) { if( t->flags & T_FLAG_NOTFILE ) return; pushsettings( t->settings ); t->boundname = search( t->name, &t->time, 0 ); t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING; popsettings( t->settings ); }
/* Look up the __ACTION_RULE__ variable on the given target, and if * non-empty, invoke the rule it names, passing the given info, * timing_info, executed command and command output */ static void call_action_rule(TARGET* target, int status, timing_info* time, char *executed_command, char *command_output) { LIST* action_rule; pushsettings(target->settings); action_rule = var_get( "__ACTION_RULE__" ); popsettings(target->settings); if (action_rule) { /* rule action-rule ( args * : target : command status start end user system : output ? ) */ /* Prepare the argument list */ FRAME frame[1]; frame_init( frame ); /* args * :: $(__ACTION_RULE__[2-]) */ lol_add( frame->args, list_copy( L0, action_rule->next ) ); /* target :: the name of the target */ lol_add( frame->args, list_new( L0, target->name ) ); /* command status start end user system :: info about the action command */ lol_add( frame->args, list_new( list_new( list_new( list_new( list_new( list_new( L0, newstr(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(L0, newstr(command_output))); else lol_add(frame->args, L0); /* Call the rule. */ evaluate_rule( action_rule->string, frame ); /* Clean up */ frame_free( frame ); } }
LIST * compile_include( PARSE *parse, FRAME *frame ) { LIST *nt = parse_evaluate( parse->left, frame ); if( DEBUG_COMPILE ) { debug_compile( 0, "include", frame); list_print( nt ); printf( "\n" ); } if( nt ) { TARGET *t = bindtarget( nt->string ); /* DWA 2001/10/22 - Perforce Jam clears the arguments here, which * prevents an included file from being treated as part of the body * of a rule. I didn't see any reason to do that, so I lifted the * restriction. */ /* Bind the include file under the influence of */ /* "on-target" variables. Though they are targets, */ /* include files are not built with make(). */ pushsettings( t->settings ); /* We don't expect that file to be included is generated by some action. Therefore, pass 0 as third argument. */ t->boundname = search( t->name, &t->time, 0 ); popsettings( t->settings ); parse_file( t->boundname, frame ); } list_free( nt ); return L0; }
int LS_jam_getvar(ls_lua_State *L) { LIST *list; LISTITEM* item; int index; int numParams = ls_lua_gettop(L); if (numParams < 1 || numParams > 2) return 0; if (!ls_lua_isstring(L, 1)) return 0; if (numParams == 1) { list = var_get(ls_lua_tostring(L, 1)); } else { TARGET *t; if (!ls_lua_isstring(L, 2)) return 0; t = bindtarget(ls_lua_tostring(L, 1)); pushsettings(t->settings); list = var_get(ls_lua_tostring(L, 2)); popsettings(t->settings); } ls_lua_newtable(L); index = 1; for (item = list_first(list); item; item = list_next(item), ++index) { ls_lua_pushnumber(L, index); ls_lua_pushstring(L, list_value(item)); ls_lua_settable(L, -3); } return 1; }
/* * Return the name of the header cache file. May return NULL. * * The user sets this by setting the HCACHEFILE variable in a Jamfile. * We cache the result so the user can't change the cache file during * header scanning. */ static char* cache_name(void) { static char* name = 0; if (!name) { LIST *hcachevar = var_get("HCACHEFILE"); if (hcachevar) { TARGET *t = bindtarget( hcachevar->string ); pushsettings( t->settings ); t->boundname = search( t->name, &t->time ); popsettings( t->settings ); if (hcachevar) { name = copystr(t->boundname); } } } return name; }
static void swap_settings ( module_t * * current_module, TARGET * * current_target, module_t * new_module, TARGET * new_target ) { if ( ( new_target == *current_target ) && ( new_module == *current_module ) ) return; if ( *current_target ) popsettings( *current_module, (*current_target)->settings ); if ( new_target ) pushsettings( new_module, new_target->settings ); *current_module = new_module; *current_target = new_target; }
static void make1bind( TARGET *t, int warn ) { if( t->flags & T_FLAG_NOTFILE ) return; /* 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( warn ) printf( "warning: using independent target %s\n", t->name ); pushsettings( t->settings ); t->boundname = search( t->name, &t->time ); t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING; popsettings( t->settings ); }
/* Look up the __TIMING_RULE__ variable on the given target, and if * non-empty, invoke the rule it names, passing the given * timing_info */ static void call_timing_rule(TARGET* target, timing_info* time) { LIST* timing_rule; pushsettings(target->settings); timing_rule = var_get( "__TIMING_RULE__" ); popsettings(target->settings); if (timing_rule) { /* rule timing-rule ( args * : target : start end user system ) */ /* Prepare the argument list */ FRAME frame[1]; frame_init( frame ); /* args * :: $(__TIMING_RULE__[2-]) */ lol_add( frame->args, list_copy( L0, timing_rule->next ) ); /* target :: the name of the target */ lol_add( frame->args, list_new( L0, target->name ) ); /* start end user system :: info about the action command */ lol_add( frame->args, list_new( list_new( list_new( list_new( L0, outf_time(time->start) ), outf_time(time->end) ), outf_double(time->user) ), outf_double(time->system) ) ); /* Call the rule. */ evaluate_rule( timing_rule->string, frame ); /* Clean up */ frame_free( frame ); } }
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_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; }
static void bind_explicitly_located_target(void* xtarget, void* data) { TARGET* t = (TARGET*)xtarget; if (! (t->flags & T_FLAG_NOTFILE) ) { /* Check if there's a setting for LOCATE */ SETTINGS* s = t->settings; for(; s ; s = s->next) { if (strcmp(s->symbol, "LOCATE") == 0) { pushsettings(t->settings); /* We're binding a target with explicit LOCATE. So third argument is of now use: nothing will be returned through it. */ t->boundname = search( t->name, &t->time, 0 ); popsettings(t->settings); break; } } } }
LIST * compile_include( PARSE *parse, LOL *args, int *jmp ) { LIST *nt = (*parse->left->func)( parse->left, args, jmp ); if( DEBUG_COMPILE ) { debug_compile( 0, "include" ); list_print( nt ); printf( "\n" ); } if( nt && list_first(nt) ) { TARGET *t = bindtarget( list_value(list_first(nt)) ); /* Bind the include file under the influence of */ /* "on-target" variables. Though they are targets, */ /* include files are not built with make(). */ /* Needn't copysettings(), as search sets no vars. */ pushsettings( t->settings ); t->boundname = search( t->name, &t->time ); popsettings( t->settings ); /* Don't parse missing file if NOCARE set */ if( t->time || !( t->flags & T_FLAG_NOCARE ) ) parse_file( t->boundname ); } list_free( nt ); 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 ); } }
/* * Return the name of the header cache file. May return NULL. * * The user sets this by setting the HCACHEFILE variable in a Jamfile. * We cache the result so the user can't change the cache file during * header scanning. */ static char* cache_name(void) { static char* name = 0; if (!name) { LIST *hcachevar = var_get("HCACHEFILE"); if (hcachevar) { TARGET *t = bindtarget( hcachevar->string ); pushsettings( t->settings ); /* Don't expect cache file to be generated, so pass 0 as third argument to search. */ t->boundname = search( t->name, &t->time, 0 ); popsettings( t->settings ); if (hcachevar) { name = copystr(t->boundname); } } } return name; }
LIST * compile_on( PARSE *parse, LOL *args, int *jmp ) { LIST *nt = (*parse->left->func)( parse->left, args, jmp ); LIST *result = 0; if( DEBUG_COMPILE ) { debug_compile( 0, "on" ); list_print( nt ); printf( "\n" ); } /* * Copy settings, so that 'on target var on target = val' * doesn't set var globally. */ if( nt && list_first(nt) ) { TARGET *t = bindtarget( list_value(list_first(nt)) ); SETTINGS *s = copysettings( t->settings ); pushsettings( s ); result = (*parse->right->func)( parse->right, args, jmp ); popsettings( s ); freesettings( s ); } list_free( nt ); return result; }
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 ); */ }