| /* |
| * Copyright 1993, 1995 Christopher Seiwald. |
| * |
| * This file is part of Jam - see jam.c for Copyright information. |
| */ |
| |
| /* This file is ALSO: |
| * Copyright 2001-2004 David Abrahams. |
| * Distributed under the Boost Software License, Version 1.0. |
| * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) |
| */ |
| |
| /* |
| * make.c - bring a target up to date, once rules are in place. |
| * |
| * This modules controls the execution of rules to bring a target and its |
| * dependencies up to date. It is invoked after the targets, rules, et. al. |
| * described in rules.h are created by the interpreting jam files. |
| * |
| * This file contains the main make() entry point and the first pass make0(). |
| * The second pass, make1(), which actually does the command execution, is in |
| * make1.c. |
| * |
| * External routines: |
| * make() - make a target, given its name |
| * |
| * Internal routines: |
| * make0() - bind and scan everything to make a TARGET |
| * make0sort() - reorder TARGETS chain by their time (newest to oldest) |
| * |
| * 12/26/93 (seiwald) - allow NOTIME targets to be expanded via $(<), $(>). |
| * 01/04/94 (seiwald) - print all targets, bounded, when tracing commands. |
| * 04/08/94 (seiwald) - progress report now reflects only targets with actions. |
| * 04/11/94 (seiwald) - Combined deps & headers into deps[2] in TARGET. |
| * 12/20/94 (seiwald) - NOTIME renamed NOTFILE. |
| * 12/20/94 (seiwald) - make0() headers after determining fate of target, so |
| * that headers are not seen as being dependent on |
| * themselves. |
| * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets. |
| * 02/02/95 (seiwald) - propagate leaf source time for new LEAVES rule. |
| * 02/14/95 (seiwald) - NOUPDATE rule means don't update existing target. |
| * 08/22/95 (seiwald) - NOUPDATE targets immune to anyhow (-a) flag. |
| * 09/06/00 (seiwald) - NOCARE affects targets with sources/actions. |
| * 03/02/01 (seiwald) - reverse NOCARE change. |
| * 03/14/02 (seiwald) - TEMPORARY targets no longer take on parents age. |
| * 03/16/02 (seiwald) - support for -g (reorder builds by source time). |
| */ |
| |
| #include "jam.h" |
| |
| #include "lists.h" |
| #include "parse.h" |
| #include "variable.h" |
| #include "rules.h" |
| |
| #ifdef OPT_HEADER_CACHE_EXT |
| #include "hcache.h" |
| #endif |
| |
| #include "search.h" |
| #include "newstr.h" |
| #include "make.h" |
| #include "headers.h" |
| #include "command.h" |
| #include <assert.h> |
| |
| #ifndef max |
| #define max( a,b ) ((a)>(b)?(a):(b)) |
| #endif |
| |
| static TARGETS * make0sort( TARGETS * c ); |
| |
| #ifdef OPT_GRAPH_DEBUG_EXT |
| static void dependGraphOutput( TARGET * t, int depth ); |
| #endif |
| |
| static const char * target_fate[] = |
| { |
| "init", /* T_FATE_INIT */ |
| "making", /* T_FATE_MAKING */ |
| "stable", /* T_FATE_STABLE */ |
| "newer", /* T_FATE_NEWER */ |
| "temp", /* T_FATE_ISTMP */ |
| "touched", /* T_FATE_TOUCHED */ |
| "rebuild", /* T_FATE_REBUILD */ |
| "missing", /* T_FATE_MISSING */ |
| "needtmp", /* T_FATE_NEEDTMP */ |
| "old", /* T_FATE_OUTDATED */ |
| "update", /* T_FATE_UPDATE */ |
| "nofind", /* T_FATE_CANTFIND */ |
| "nomake" /* T_FATE_CANTMAKE */ |
| }; |
| |
| static const char * target_bind[] = |
| { |
| "unbound", |
| "missing", |
| "parents", |
| "exists", |
| }; |
| |
| # define spaces(x) ( " " + ( x > 20 ? 0 : 20-x ) ) |
| |
| |
| /* |
| * make() - make a target, given its name. |
| */ |
| |
| int make( int n_targets, char const * * targets, int anyhow ) |
| { |
| int i; |
| COUNTS counts[ 1 ]; |
| int status = 0; /* 1 if anything fails */ |
| |
| #ifdef OPT_HEADER_CACHE_EXT |
| hcache_init(); |
| #endif |
| |
| memset( (char *)counts, 0, sizeof( *counts ) ); |
| |
| /* First bind all targets with LOCATE_TARGET setting. This is needed to |
| * correctly handle dependencies to generated headers. |
| */ |
| bind_explicitly_located_targets(); |
| |
| { |
| PROFILE_ENTER( MAKE_MAKE0 ); |
| for ( i = 0; i < n_targets; ++i ) |
| make0( bindtarget( targets[ i ] ), 0, 0, counts, anyhow ); |
| PROFILE_EXIT( MAKE_MAKE0 ); |
| } |
| |
| #ifdef OPT_GRAPH_DEBUG_EXT |
| if ( DEBUG_GRAPH ) |
| for ( i = 0; i < n_targets; ++i ) |
| dependGraphOutput( bindtarget( targets[ i ] ), 0 ); |
| #endif |
| |
| if ( DEBUG_MAKE ) |
| { |
| if ( counts->targets ) |
| printf( "...found %d target%s...\n", counts->targets, |
| counts->targets > 1 ? "s" : "" ); |
| if ( counts->temp ) |
| printf( "...using %d temp target%s...\n", counts->temp, |
| counts->temp > 1 ? "s" : "" ); |
| if ( counts->updating ) |
| printf( "...updating %d target%s...\n", counts->updating, |
| counts->updating > 1 ? "s" : "" ); |
| if ( counts->cantfind ) |
| printf( "...can't find %d target%s...\n", counts->cantfind, |
| counts->cantfind > 1 ? "s" : "" ); |
| if ( counts->cantmake ) |
| printf( "...can't make %d target%s...\n", counts->cantmake, |
| counts->cantmake > 1 ? "s" : "" ); |
| } |
| |
| #ifdef OPT_HEADER_CACHE_EXT |
| hcache_done(); |
| #endif |
| |
| status = counts->cantfind || counts->cantmake; |
| |
| { |
| PROFILE_ENTER( MAKE_MAKE1 ); |
| for ( i = 0; i < n_targets; ++i ) |
| status |= make1( bindtarget( targets[ i ] ) ); |
| PROFILE_EXIT( MAKE_MAKE1 ); |
| } |
| |
| return status; |
| } |
| |
| |
| /* Force any dependants of t that have already at least begun being visited by |
| * make0() to be updated. |
| */ |
| |
| static void update_dependants( TARGET * t ) |
| { |
| TARGETS * q; |
| |
| for ( q = t->dependants; q; q = q->next ) |
| { |
| TARGET * p = q->target; |
| char fate0 = p->fate; |
| |
| /* If we have already at least begun visiting it and we are not already |
| * rebuilding it for other reasons. |
| */ |
| if ( ( fate0 != T_FATE_INIT ) && ( fate0 < T_FATE_BUILD ) ) |
| { |
| p->fate = T_FATE_UPDATE; |
| |
| if ( DEBUG_FATE ) |
| { |
| printf( "fate change %s from %s to %s (as dependant of %s)\n", |
| p->name, target_fate[ (int) fate0 ], target_fate[ (int) p->fate ], t->name ); |
| } |
| |
| /* If we are done visiting it, go back and make sure its dependants |
| * get rebuilt. |
| */ |
| if ( fate0 > T_FATE_MAKING ) |
| update_dependants( p ); |
| } |
| } |
| } |
| |
| |
| /* |
| * Make sure that all of t's rebuilds get rebuilt. |
| */ |
| |
| static void force_rebuilds( TARGET * t ) |
| { |
| TARGETS * d; |
| for ( d = t->rebuilds; d; d = d->next ) |
| { |
| TARGET * r = d->target; |
| |
| /* If it is not already being rebuilt for other reasons. */ |
| if ( r->fate < T_FATE_BUILD ) |
| { |
| if ( DEBUG_FATE ) |
| printf( "fate change %s from %s to %s (by rebuild)\n", |
| r->name, target_fate[ (int) r->fate ], target_fate[ T_FATE_REBUILD ] ); |
| |
| /* Force rebuild it. */ |
| r->fate = T_FATE_REBUILD; |
| |
| /* And make sure its dependants are updated too. */ |
| update_dependants( r ); |
| } |
| } |
| } |
| |
| |
| /* |
| * make0() - bind and scan everything to make a TARGET. |
| * |
| * Recursively binds a target, searches for #included headers, calls itself on |
| * those headers and any dependencies. |
| */ |
| |
| 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; |
| TARGET * ptime = t; |
| time_t last; |
| time_t leaf; |
| time_t hlast; |
| int fate; |
| char const * 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 is 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, |
| t->flags & T_FLAG_ISFILE ); |
| /* If it was detected that this target refers to an already existing and |
| * bound one, we add an include dependency, so that every target |
| * depending on us will depend on that other target as well. |
| */ |
| if ( another_target ) |
| target_include( t, bindtarget( 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 does not 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[ (int) 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() dependencies & headers. |
| */ |
| |
| /* Step 3a: recursively make0() dependencies. */ |
| for ( c = t->depends; c; c = c->next ) |
| { |
| int internal = t->flags & T_FLAG_INTERNAL; |
| |
| /* 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 dependencies' includes to our direct dependencies. */ |
| { |
| TARGETS * 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 dependencies' 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[(int) fate], target_fate[(int) 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, mark it as having eternally old dependencies. |
| * Do not inherit our fate from our dependencies. Decide fate based only on |
| * 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; |
| |
| /* Do not inherit our fate from our dependencies. 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 not find or make child, can not 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 is missing and there are no actions to create it, boom. */ |
| /* If we can not make a target we do not care about it, okay. */ |
| /* We could insist that there are updating actions for all missing */ |
| /* files, but if they have dependencies we just pretend it is a 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 dependencies and do not 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 dependencies' 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 |
| * have 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 dependencies by their update time. |
| */ |
| |
| if ( globs.newestfirst ) |
| t->depends = make0sort( t->depends ); |
| |
| /* |
| * Step 6: a little harmless tabulating for tracing purposes |
| */ |
| |
| /* Do not 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[ (int) t->fate ], |
| spaces( depth ), t->name ); |
| } |
| |
| |
| #ifdef OPT_GRAPH_DEBUG_EXT |
| |
| static const char * target_name( TARGET * t ) |
| { |
| static char buf[ 1000 ]; |
| if ( t->flags & T_FLAG_INTERNAL ) |
| { |
| sprintf( buf, "%s (internal node)", t->name ); |
| return buf; |
| } |
| return t->name; |
| } |
| |
| |
| /* |
| * dependGraphOutput() - output the DG after make0 has run. |
| */ |
| |
| static void dependGraphOutput( TARGET * t, int depth ) |
| { |
| TARGETS * c; |
| |
| if ( ( t->flags & T_FLAG_VISITED ) || !t->name || !t->boundname ) |
| return; |
| |
| t->flags |= T_FLAG_VISITED; |
| |
| switch ( t->fate ) |
| { |
| case T_FATE_TOUCHED: |
| case T_FATE_MISSING: |
| case T_FATE_OUTDATED: |
| case T_FATE_UPDATE: |
| printf( "->%s%2d Name: %s\n", spaces( depth ), depth, target_name( t ) ); |
| break; |
| default: |
| printf( " %s%2d Name: %s\n", spaces( depth ), depth, target_name( t ) ); |
| break; |
| } |
| |
| if ( strcmp( t->name, t->boundname ) ) |
| printf( " %s Loc: %s\n", spaces( depth ), t->boundname ); |
| |
| switch ( t->fate ) |
| { |
| case T_FATE_STABLE: |
| printf( " %s : Stable\n", spaces( depth ) ); |
| break; |
| case T_FATE_NEWER: |
| printf( " %s : Newer\n", spaces( depth ) ); |
| break; |
| case T_FATE_ISTMP: |
| printf( " %s : Up to date temp file\n", spaces( depth ) ); |
| break; |
| case T_FATE_NEEDTMP: |
| printf( " %s : Temporary file, to be updated\n", spaces( depth ) ); |
| break; |
| case T_FATE_TOUCHED: |
| printf( " %s : Been touched, updating it\n", spaces( depth ) ); |
| break; |
| case T_FATE_MISSING: |
| printf( " %s : Missing, creating it\n", spaces( depth ) ); |
| break; |
| case T_FATE_OUTDATED: |
| printf( " %s : Outdated, updating it\n", spaces( depth ) ); |
| break; |
| case T_FATE_REBUILD: |
| printf( " %s : Rebuild, updating it\n", spaces( depth ) ); |
| break; |
| case T_FATE_UPDATE: |
| printf( " %s : Updating it\n", spaces( depth ) ); |
| break; |
| case T_FATE_CANTFIND: |
| printf( " %s : Can not find it\n", spaces( depth ) ); |
| break; |
| case T_FATE_CANTMAKE: |
| printf( " %s : Can make it\n", spaces( depth ) ); |
| break; |
| } |
| |
| if ( t->flags & ~T_FLAG_VISITED ) |
| { |
| printf( " %s : ", spaces( depth ) ); |
| if ( t->flags & T_FLAG_TEMP ) printf( "TEMPORARY " ); |
| if ( t->flags & T_FLAG_NOCARE ) printf( "NOCARE " ); |
| if ( t->flags & T_FLAG_NOTFILE ) printf( "NOTFILE " ); |
| if ( t->flags & T_FLAG_TOUCHED ) printf( "TOUCHED " ); |
| if ( t->flags & T_FLAG_LEAVES ) printf( "LEAVES " ); |
| if ( t->flags & T_FLAG_NOUPDATE ) printf( "NOUPDATE " ); |
| printf( "\n" ); |
| } |
| |
| for ( c = t->depends; c; c = c->next ) |
| { |
| printf( " %s : Depends on %s (%s)", spaces( depth ), |
| target_name( c->target ), target_fate[ (int) c->target->fate ] ); |
| if ( c->target->time == t->time ) |
| printf( " (max time)"); |
| printf( "\n" ); |
| } |
| |
| for ( c = t->depends; c; c = c->next ) |
| dependGraphOutput( c->target, depth + 1 ); |
| } |
| #endif |
| |
| |
| /* |
| * make0sort() - reorder TARGETS chain by their time (newest to oldest). |
| * |
| * We walk chain, taking each item and inserting it on the sorted result, with |
| * newest items at the front. This involves updating each of the TARGETS' |
| * c->next and c->tail. Note that we make c->tail a valid prev pointer for every |
| * entry. Normally, it is only valid at the head, where prev == tail. Note also |
| * that while tail is a loop, next ends at the end of the chain. |
| */ |
| |
| static TARGETS * make0sort( TARGETS * chain ) |
| { |
| PROFILE_ENTER( MAKE_MAKE0SORT ); |
| |
| TARGETS * result = 0; |
| |
| /* Walk the current target list. */ |
| while ( chain ) |
| { |
| TARGETS * c = chain; |
| TARGETS * s = result; |
| |
| chain = chain->next; |
| |
| /* Find point s in result for c. */ |
| while ( s && ( s->target->time > c->target->time ) ) |
| s = s->next; |
| |
| /* Insert c in front of s (might be 0). Do not even think of deciphering |
| * this. |
| */ |
| c->next = s; /* good even if s = 0 */ |
| if ( result == s ) result = c; /* new head of chain? */ |
| if ( !s ) s = result; /* wrap to ensure a next */ |
| if ( result != c ) s->tail->next = c; /* not head? be prev's next */ |
| c->tail = s->tail; /* take on next's prev */ |
| s->tail = c; /* make next's prev us */ |
| } |
| |
| PROFILE_EXIT( MAKE_MAKE0SORT ); |
| return result; |
| } |
| |
| |
| static LIST * targets_to_update_ = 0; |
| |
| |
| void mark_target_for_updating( char * target ) |
| { |
| targets_to_update_ = list_new( targets_to_update_, target ); |
| } |
| |
| |
| LIST * targets_to_update() |
| { |
| return targets_to_update_; |
| } |
| |
| |
| void clear_targets_to_update() |
| { |
| list_free( targets_to_update_ ); |
| targets_to_update_ = 0; |
| } |