Exemple #1
0
static void
make1b( state *pState )
{
    TARGET      *t = pState->t;
    TARGETS     *c;
    TARGET      *failed = 0;
    char* failed_name = "dependencies";

    /* If any dependents are still outstanding, wait until they */
    /* call make1b() to signal their completion. */

    if( --(pState->t->asynccnt) )
	{
		pop_state(&state_stack);
		return;
	}
    
    /* Try to aquire a semaphore. If it's locked, wait until the target
       that locked it is build and signals completition. */
#ifdef OPT_SEMAPHORE
	if( t->semaphore && t->semaphore->asynccnt )
	{
        /* Append 't' to the list of targets waiting on semaphore. */
	    t->semaphore->parents = targetentry( t->semaphore->parents, t );
	    t->asynccnt++;

	    if( DEBUG_EXECCMD )
		printf( "SEM: %s is busy, delaying launch of %s\n",
			t->semaphore->name, t->name);
		pop_state(&state_stack);
	    return;
	}
#endif


    /* Now ready to build target 't'... if dependents built ok. */

    /* Collect status from dependents */


    for( c = t->depends; c; c = c->next )
        if( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ))
        {
            failed = c->target;
            pState->t->status = c->target->status;
        }
    /* If a internal header node failed to build, we'd want to output the 
       target that it failed on. */
    if (failed && (failed->flags & T_FLAG_INTERNAL)) {
        failed_name = failed->failed;
    } else if (failed) {
        failed_name = failed->name;
    }
    t->failed = failed_name;

    /* If actions on deps have failed, bail. */
    /* Otherwise, execute all actions to make target */

    if( pState->t->status == EXEC_CMD_FAIL && pState->t->actions )
    {
        ++counts->skipped;
        if ( ( pState->t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
        {
            if( !unlink( pState->t->boundname ) )
                printf( "...removing outdated %s\n", pState->t->boundname );
        }
        else {
            printf( "...skipped %s for lack of %s...\n", pState->t->name, failed_name );
        }
    }

    if( pState->t->status == EXEC_CMD_OK )
        switch( pState->t->fate )
        {
            /* These are handled by the default case below now
        case T_FATE_INIT:
        case T_FATE_MAKING:
            */

        case T_FATE_STABLE:
        case T_FATE_NEWER:
            break;

        case T_FATE_CANTFIND:
        case T_FATE_CANTMAKE:
            pState->t->status = EXEC_CMD_FAIL;
            break;

        case T_FATE_ISTMP:
            if( DEBUG_MAKE )
                printf( "...using %s...\n", pState->t->name );
            break;

        case T_FATE_TOUCHED:
        case T_FATE_MISSING:
        case T_FATE_NEEDTMP:
        case T_FATE_OUTDATED:
        case T_FATE_UPDATE:
        case T_FATE_REBUILD:

            /* Set "on target" vars, build actions, unset vars */
            /* Set "progress" so that make1c() counts this target among */
            /* the successes/failures. */

            if( pState->t->actions )
            {
                ++counts->total;
                if( DEBUG_MAKE && !( counts->total % 100 ) )
                    printf( "...on %dth target...\n", counts->total );

                pState->t->cmds = (char *)make1cmds( pState->t );
                pState->t->progress = T_MAKE_RUNNING;
            }

            break;
            
            /* All possible fates should have been accounted for by now */
        default:
            printf("ERROR: %s has bad fate %d", pState->t->name, pState->t->fate);
            abort();
        }

		/* Call make1c() to begin the execution of the chain of commands */
		/* needed to build target.  If we're not going to build target */
		/* (because of dependency failures or because no commands need to */
		/* be run) the chain will be empty and make1c() will directly */
		/* signal the completion of target. */

	/* Recurse on our dependents, manipulating progress to guard */

#ifdef OPT_SEMAPHORE
	/* If there is a semaphore, indicate that its in use */
	if( pState->t->semaphore )
	{
	    ++(pState->t->semaphore->asynccnt);

	    if( DEBUG_EXECCMD )
		printf( "SEM: %s now used by %s\n", pState->t->semaphore->name,
		       pState->t->name );
	}
#endif

	pState->curstate = T_STATE_MAKE1C;
}
Exemple #2
0
static void
make1b( TARGET *t )
{
	TARGETS	*c;
	const char *failed;
#ifdef OPT_MULTIPASS_EXT
	int missing;
#endif
#ifdef OPT_BUILTIN_NEEDS_EXT
	int childmightnotupdate;
	int childscancontents;
	int childupdated;
#endif

#ifdef OPT_DEBUG_MAKE1_LOG_EXT
	if (DEBUG_MAKE1) {
	    printf( "make1b\t--\t%s (asynccnt %d)\n" ,
		    t->name, t->asynccnt);
	}
#endif
	/* If any dependents are still outstanding, wait until they */
	/* call make1b() to signal their completion. */

	if( --t->asynccnt )
	    return;

#ifdef OPT_INTERRUPT_FIX
	if( intr )
	    return;
#endif

	failed = "dependents";
#ifdef OPT_MULTIPASS_EXT
	missing = 0;
#endif
#ifdef OPT_BUILTIN_NEEDS_EXT
	childmightnotupdate = 0;
	childscancontents = 0;
	childupdated = 0;
#endif

#ifdef OPT_SEMAPHORE
	if( t->semaphore && t->semaphore->asynccnt )
	{
	    /* We can't launch yet.  Try again when the semaphore is free */
#ifdef OPT_BUILTIN_NEEDS_EXT
	    t->semaphore->parents = targetentry( t->semaphore->parents, t, 0 );
#else
	    t->semaphore->parents = targetentry( t->semaphore->parents, t );
#endif
	    t->asynccnt++;

	    if( DEBUG_EXECCMD )
		printf( "SEM: %s is busy, delaying launch of %s\n",
			t->semaphore->name, t->name);
	    return;
	}
#endif
	/* Now ready to build target 't'... if dependents built ok. */

	/* Collect status from dependents */

	for( c = t->depends; c; c = c->next ) {
	    if ( !(t->flags & T_FLAG_INTERNAL) && c->target->asynccnt ) {
//			printf("warning: Trying to build '%s' before dependent '%s' is done!\n", t->name, c->target->name);
		}
#ifdef OPT_BUILTIN_NEEDS_EXT
	    /* Only test a target's MightNotUpdate flag if the target's build was successful. */
	    if( c->target->status == EXEC_CMD_OK ) {
		if ( c->target->flags & T_FLAG_MIGHTNOTUPDATE ) {
		    time_t timestamp;

		    /* Mark that we've seen a MightNotUpdate flag in this set of children. */
		    childmightnotupdate = 1;

		    /* Grab the generated target's timestamp. */
		    if ( file_time( c->target->boundname, &timestamp ) == 0 ) {
			/* If the child's timestamp is greater that the target's timestamp, then it updated. */
				if ( timestamp > t->time ) {
					if ( c->target->flags & T_FLAG_SCANCONTENTS ) {
						childscancontents = 1;
						if ( getcachedmd5sum( c->target, 1 ) )
							childupdated = 1;
					} else
						childupdated = 1;
				} else {
					childscancontents = 1;
				}
		    }
		}
		/* If it didn't have the MightNotUpdate flag but did update, mark it. */
		else if ( c->target->fate > T_FATE_STABLE  &&  !c->needs ) {
			if ( c->target->flags & T_FLAG_SCANCONTENTS ) {
				childscancontents = 1;
				if ( getcachedmd5sum( c->target, 1 ) )
					childupdated = 1;
			} else
				childupdated = 1;
		}
	    }
#endif

	    if( c->target->status > t->status )
	{
	    failed = c->target->name;
	    t->status = c->target->status;
#ifdef OPT_MULTIPASS_EXT
		if ( ( c->target->fate == T_FATE_MISSING  &&  ! ( c->target->flags & T_FLAG_NOCARE )  &&  !c->target->actions ) || t->status == EXEC_CMD_NEXTPASS )
		{
			missing = 1;
			if ( queuedjamfiles )
			{
				ACTIONS *actions;

				t->status = EXEC_CMD_NEXTPASS;

				for( actions = t->actions; actions; actions = actions->next )
				{
					actions->action->pass++;
				}
			}
		}
#endif
	}

#ifdef OPT_NOCARE_NODES_EXT
	/* CWM */
	/* If actions on deps have failed, but if this is a 'nocare' target */
	/* then continue anyway. */

	if( ( t->flags & T_FLAG_NOCARE ) && t->status == EXEC_CMD_FAIL )
	{
		printf( "...dependency on %s failed, but don't care...\n", t->name );
		t->status = EXEC_CMD_OK;
	}
#endif
	}

#ifdef OPT_BUILTIN_NEEDS_EXT
	/* If we found a MightNotUpdate flag and there was an update, mark the fate as updated. */
	if ( childmightnotupdate  &&  childupdated  &&  t->fate == T_FATE_STABLE )
	      t->fate = T_FATE_UPDATE;
	if ( childscancontents ) {
		if ( !childupdated ) {
			if ( t->includes ) {
				for( c = t->includes->depends; c; c = c->next ) {
					if ( c->target->fate > T_FATE_STABLE  &&  !c->needs ) {
						if ( c->target->flags & T_FLAG_SCANCONTENTS ) {
							if ( getcachedmd5sum( c->target, 1 )  ||  !md5matchescommandline( c->target ) ) {
								childupdated = 1;
								break;
							}
						} else {
							childupdated = 1;
							break;
						}
					}
				}
			}

			if ( !childupdated )
				t->fate = T_FATE_STABLE;
		} else if ( t->fate == T_FATE_STABLE )
			t->fate = T_FATE_UPDATE;
	}
	if ( t->fate == T_FATE_UPDATE  &&  !childupdated  &&  t->status != EXEC_CMD_NEXTPASS )
		if ( md5matchescommandline( t ) )
		    t->fate = T_FATE_STABLE;
	if ( t->flags & ( T_FLAG_MIGHTNOTUPDATE | T_FLAG_SCANCONTENTS )  &&  t->actions ) {
#ifdef OPT_ACTIONS_WAIT_FIX
	    /* See http://maillist.perforce.com/pipermail/jamming/2003-December/002252.html */
	    /* Determine if an action is already running on behalf of another target, and if so, */
	    /* bail out of make1b() prior to calling make1cmds() by adding more parents to the */
	    /* in-progress target and incrementing the asynccnt of the new target. */
	    make1wait( t );
	    if ( t->asynccnt != 0 )
		return;
#endif
	}
#endif

	/* If actions on deps have failed, bail. */
	/* Otherwise, execute all actions to make target */

#ifdef OPT_MULTIPASS_EXT
	if( t->status == EXEC_CMD_FAIL && t->actions && !missing )
#else
	if( t->status == EXEC_CMD_FAIL && t->actions )
#endif
	{
	    ++counts->skipped;
	    printf( "*** skipped %s for lack of %s...\n", t->name, failed );
	}

	if( t->status == EXEC_CMD_OK )
	    switch( t->fate )
	{
	case T_FATE_INIT:
	case T_FATE_MAKING:
	    /* shouldn't happen */

	case T_FATE_STABLE:
	case T_FATE_NEWER:
	    break;

	case T_FATE_CANTFIND:
	case T_FATE_CANTMAKE:
	    t->status = EXEC_CMD_FAIL;
	    break;

	case T_FATE_ISTMP:
	    if( DEBUG_MAKEQ )
		printf( "*** using %s...\n", t->name );
	    break;

	case T_FATE_TOUCHED:
	case T_FATE_MISSING:
	case T_FATE_NEEDTMP:
	case T_FATE_OUTDATED:
	case T_FATE_UPDATE:
	    /* Set "on target" vars, build actions, unset vars */
	    /* Set "progress" so that make1c() counts this target among */
	    /* the successes/failures. */

#ifdef OPT_DEBUG_MAKE1_LOG_EXT
	    if (DEBUG_MAKE1) {
		printf( "make1b\t--\t%s (has actions)\n" , t->name );
	    }
#endif
	    if( t->actions )
	    {
#ifdef OPT_ACTIONS_WAIT_FIX
		/* See http://maillist.perforce.com/pipermail/jamming/2003-December/002252.html */
		/* Determine if an action is already running on behalf of another target, and if so, */
		/* bail out of make1b() prior to calling make1cmds() by adding more parents to the */
		/* in-progress target and incrementing the asynccnt of the new target. */
		make1wait( t );
		if ( t->asynccnt != 0 )
		    return;
#endif
		++counts->total;

#ifndef OPT_IMPROVED_PROGRESS_EXT
		if( DEBUG_MAKE && !( counts->total % 100 ) )
		    printf( "*** on %dth target...\n", counts->total );
#else
		{
		    double est_remaining;

		    est_remaining =
			progress_update(globs.progress, counts->total);

		    if (est_remaining > 0) {
			int minutes = (int)est_remaining / 60;
			int seconds = (int)est_remaining % 60;

			if (minutes > 0 || seconds > 0) {
			    printf("*** completed %.0f%% (",
				   ((double)counts->total * 100 /
				    globs.updating));
			    if (minutes > 0)
				printf("%d min ", minutes);
			    if (seconds >= 0)
				printf("%d sec ", seconds);
			    printf("remaining)...\n");
			}
		    }
		}
#endif

#ifdef OPT_BUILTIN_MD5CACHE_EXT
		pushsettings( t->settings );
		filecache_fillvalues( t );
		popsettings( t->settings );
		t->cmds = (char *)make1cmds( t, t->actions );
#else
		pushsettings( t->settings );
		t->cmds = (char *)make1cmds( t->actions );
		popsettings( t->settings );
#endif

		t->progress = T_MAKE_RUNNING;
	    }

	    break;
	}

#ifdef OPT_SEMAPHORE
	/* If there is a semaphore, indicate that its in use */
	if( t->semaphore )
	{
	    ++(t->semaphore->asynccnt);

	    if( DEBUG_EXECCMD )
		printf( "SEM: %s now used by %s\n", t->semaphore->name,
		       t->name );
	}
#endif
	/* Call make1c() to begin the execution of the chain of commands */
	/* needed to build target.  If we're not going to build target */
	/* (because of dependency failures or because no commands need to */
	/* be run) the chain will be empty and make1c() will directly */
	/* signal the completion of target. */

	make1c( t );
}
Exemple #3
0
static void make1b( state * const pState )
{
    TARGET * const t = pState->t;
    TARGET * failed = 0;
    char const * failed_name = "dependencies";

    /* If any dependencies are still outstanding, wait until they signal their
     * completion by pushing this same state for their parent targets.
     */
    if ( --t->asynccnt )
    {
        pop_state( &state_stack );
        return;
    }

    /* Try to aquire a semaphore. If it is locked, wait until the target that
     * locked it is built and signals completition.
     */
#ifdef OPT_SEMAPHORE
    if ( t->semaphore && t->semaphore->asynccnt )
    {
        /* Append 't' to the list of targets waiting on semaphore. */
        t->semaphore->parents = targetentry( t->semaphore->parents, t );
        t->asynccnt++;

        if ( DEBUG_EXECCMD )
            printf( "SEM: %s is busy, delaying launch of %s\n",
                object_str( t->semaphore->name ), object_str( t->name ) );
        pop_state( &state_stack );
        return;
    }
#endif

    /* Now ready to build target 't', if dependencies built OK. */

    /* Collect status from dependencies. If -n was passed then act as though all
     * dependencies built correctly (the only way they can fail is if UPDATE_NOW
     * was called). If the dependencies can not be found or we got an interrupt,
     * we can not get here.
     */
    if ( !globs.noexec )
    {
        TARGETS * c;
        for ( c = t->depends; c; c = c->next )
            if ( c->target->status > t->status && !( c->target->flags &
                T_FLAG_NOCARE ) )
            {
                failed = c->target;
                t->status = c->target->status;
            }
    }

    /* If an internal header node failed to build, we want to output the target
     * that it failed on.
     */
    if ( failed )
        failed_name = failed->flags & T_FLAG_INTERNAL
            ? failed->failed
            : object_str( failed->name );
    t->failed = failed_name;

    /* If actions for building any of the dependencies have failed, bail.
     * Otherwise, execute all actions to make the current target.
     */
    if ( ( t->status == EXEC_CMD_FAIL ) && t->actions )
    {
        ++counts->skipped;
        if ( ( t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
        {
            if ( !unlink( object_str( t->boundname ) ) )
                printf( "...removing outdated %s\n", object_str( t->boundname )
                    );
        }
        else
            printf( "...skipped %s for lack of %s...\n", object_str( t->name ),
                failed_name );
    }

    if ( t->status == EXEC_CMD_OK )
        switch ( t->fate )
        {
        case T_FATE_STABLE:
        case T_FATE_NEWER:
            break;

        case T_FATE_CANTFIND:
        case T_FATE_CANTMAKE:
            t->status = EXEC_CMD_FAIL;
            break;

        case T_FATE_ISTMP:
            if ( DEBUG_MAKE )
                printf( "...using %s...\n", object_str( t->name ) );
            break;

        case T_FATE_TOUCHED:
        case T_FATE_MISSING:
        case T_FATE_NEEDTMP:
        case T_FATE_OUTDATED:
        case T_FATE_UPDATE:
        case T_FATE_REBUILD:
            /* Prepare commands for executing actions scheduled for this target.
             * Commands have their embedded variables automatically expanded,
             * including making use of any "on target" variables.
             */
            if ( t->actions )
            {
                ++counts->total;
                if ( DEBUG_MAKE && !( counts->total % 100 ) )
                    printf( "...on %dth target...\n", counts->total );

                t->cmds = (char *)make1cmds( t );
                /* Update the target's "progress" so MAKE1C processing counts it
                 * among its successes/failures.
                 */
                t->progress = T_MAKE_RUNNING;
            }
            break;

        /* All valid fates should have been accounted for by now. */
        default:
            printf( "ERROR: %s has bad fate %d", object_str( t->name ),
                t->fate );
            abort();
        }

#ifdef OPT_SEMAPHORE
    /* If there is a semaphore, indicate that it is in use. */
    if ( t->semaphore )
    {
        ++t->semaphore->asynccnt;
        if ( DEBUG_EXECCMD )
            printf( "SEM: %s now used by %s\n", object_str( t->semaphore->name
                ), object_str( t->name ) );
    }
#endif

    /* Proceed to MAKE1C to begin executing the chain of commands prepared for
     * building the target. If we are not going to build the target (e.g. due to
     * dependency failures or no commands needing to be run) the chain will be
     * empty and MAKE1C processing will directly signal the target's completion.
     */
    /* Implementation note:
     *   Morfing the current state on the stack instead of popping it and
     * pushing a new one is a slight optimization with no side-effects since we
     * pushed no other states while processing this one.
     */
    pState->curstate = T_STATE_MAKE1C;
}
Exemple #4
0
static void make1b( state * const pState )
{
    TARGET * const t = pState->t;
    TARGET * failed = 0;
    char const * failed_name = "dependencies";

    pop_state( &state_stack );

    /* If any dependencies are still outstanding, wait until they signal their
     * completion by pushing this same state for their parent targets.
     */
    if ( --t->asynccnt )
    {
        return;
    }

    /* Now ready to build target 't', if dependencies built OK. */

    /* Collect status from dependencies. If -n was passed then act as though all
     * dependencies built correctly (the only way they can fail is if UPDATE_NOW
     * was called). If the dependencies can not be found or we got an interrupt,
     * we can not get here.
     */
    if ( !globs.noexec )
    {
        TARGETS * c;
        for ( c = t->depends; c; c = c->next )
            if ( c->target->status > t->status && !( c->target->flags &
                T_FLAG_NOCARE ) )
            {
                failed = c->target;
                t->status = c->target->status;
            }
    }

    /* If an internal header node failed to build, we want to output the target
     * that it failed on.
     */
    if ( failed )
        failed_name = failed->flags & T_FLAG_INTERNAL
            ? failed->failed
            : object_str( failed->name );
    t->failed = failed_name;

    /* If actions for building any of the dependencies have failed, bail.
     * Otherwise, execute all actions to make the current target.
     */
    if ( ( t->status == EXEC_CMD_FAIL ) && t->actions )
    {
        ++counts->skipped;
        if ( ( t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
        {
            if ( !unlink( object_str( t->boundname ) ) )
                printf( "...removing outdated %s\n", object_str( t->boundname )
                    );
        }
        else
            printf( "...skipped %s for lack of %s...\n", object_str( t->name ),
                failed_name );
    }

    if ( t->status == EXEC_CMD_OK )
        switch ( t->fate )
        {
        case T_FATE_STABLE:
        case T_FATE_NEWER:
            break;

        case T_FATE_CANTFIND:
        case T_FATE_CANTMAKE:
            t->status = EXEC_CMD_FAIL;
            break;

        case T_FATE_ISTMP:
            if ( DEBUG_MAKE )
                printf( "...using %s...\n", object_str( t->name ) );
            break;

        case T_FATE_TOUCHED:
        case T_FATE_MISSING:
        case T_FATE_NEEDTMP:
        case T_FATE_OUTDATED:
        case T_FATE_UPDATE:
        case T_FATE_REBUILD:
            /* Prepare commands for executing actions scheduled for this target.
             * Commands have their embedded variables automatically expanded,
             * including making use of any "on target" variables.
             */
            if ( t->actions )
            {
                ++counts->total;
                if ( DEBUG_MAKE && !( counts->total % 100 ) )
                    printf( "...on %dth target...\n", counts->total );

                t->cmds = (char *)make1cmds( t );
                /* Update the target's "progress" so MAKE1C processing counts it
                 * among its successes/failures.
                 */
                t->progress = T_MAKE_RUNNING;
            }
            break;

        /* All valid fates should have been accounted for by now. */
        default:
            printf( "ERROR: %s has bad fate %d", object_str( t->name ),
                t->fate );
            abort();
        }

    /* Proceed to MAKE1C to begin executing the chain of commands prepared for
     * building the target. If we are not going to build the target (e.g. due to
     * dependency failures or no commands needing to be run) the chain will be
     * empty and MAKE1C processing will directly signal the target's completion.
     */

    if ( t->cmds == NULL || --( ( CMD * )t->cmds )->asynccnt == 0 )
        push_state( &state_stack, t, NULL, T_STATE_MAKE1C );
    else if ( DEBUG_EXECCMD )
    {
        CMD * cmd = ( CMD * )t->cmds;
        printf( "Delaying %s %s: %d targets not ready\n", object_str( cmd->rule->name ), object_str( t->boundname ), cmd->asynccnt );
    }
}