Beispiel #1
0
int
make1( TARGET *t )
{
	state *pState;

	memset( (char *)counts, 0, sizeof( *counts ) );

	/* Recursively make the target and its dependents */
	push_state(&state_stack, t, NULL, T_STATE_MAKE1A);

	do
	{
		while((pState = current_state(&state_stack)) != NULL)
		{
            if (intr) 
                pop_state(&state_stack);

			switch(pState->curstate)
			{
			case T_STATE_MAKE1A:
				make1a(pState);
				break;
			case T_STATE_MAKE1ATAIL:
				make1atail(pState);
				break;
			case T_STATE_MAKE1B:
				make1b(pState);
				break;
			case T_STATE_MAKE1C:
				make1c(pState);
				break;
			case T_STATE_MAKE1D:
				make1d(pState);
				break;
			default:
				break;
			}
		}
	

	/* Wait for any outstanding commands to finish running. */
	} while( execwait() );

	clear_state_freelist();

	/* Talk about it */
	if( counts->failed )
	    printf( "...failed updating %d target%s...\n", counts->failed,
		        counts->failed > 1 ? "s" : "" );

	if( DEBUG_MAKE && counts->skipped )
	    printf( "...skipped %d target%s...\n", counts->skipped,
		        counts->skipped > 1 ? "s" : "" );

	if( DEBUG_MAKE && counts->made )
	    printf( "...updated %d target%s...\n", counts->made,
		        counts->made > 1 ? "s" : "" );

	return counts->total != counts->made;
}
Beispiel #2
0
int make1( TARGET * const t )
{
    state * pState;

    memset( (char *)counts, 0, sizeof( *counts ) );

    /* Recursively make the target and its dependencies. */
    push_state( &state_stack, t, NULL, T_STATE_MAKE1A );

    while ( 1 )
    {
        while ( ( pState = current_state( &state_stack ) ) )
        {
            if ( intr )
                pop_state( &state_stack );

            switch ( pState->curstate )
            {
                case T_STATE_MAKE1A: make1a( pState ); break;
                case T_STATE_MAKE1B: make1b( pState ); break;
                case T_STATE_MAKE1C: make1c( pState ); break;
                default:
                    assert( !"make1(): Invalid state detected." );
            }
        }
        if ( !cmdsrunning )
            break;
        /* Wait for outstanding commands to finish running. */
        exec_wait();
    }

    clear_state_freelist();

    /* Talk about it. */
    if ( counts->failed )
        printf( "...failed updating %d target%s...\n", counts->failed,
            counts->failed > 1 ? "s" : "" );
    if ( DEBUG_MAKE && counts->skipped )
        printf( "...skipped %d target%s...\n", counts->skipped,
            counts->skipped > 1 ? "s" : "" );
    if ( DEBUG_MAKE && counts->made )
        printf( "...updated %d target%s...\n", counts->made,
            counts->made > 1 ? "s" : "" );

    return counts->total != counts->made;
}
Beispiel #3
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 );
}
Beispiel #4
0
static void
make1d(
#ifdef OPT_SERIAL_OUTPUT_EXT
	const char*	outputname,
#endif
	void	*closure,
	int	status )
{
	TARGET	*t = (TARGET *)closure;
	CMD	*cmd = (CMD *)t->cmds;

#ifdef OPT_DEBUG_MAKE1_LOG_EXT
	if (DEBUG_MAKE1) {
	    printf( "make1d\t--\t%s\n" ,
		    t->name );
	}
#endif
	/* Execcmd() has completed.  All we need to do is fiddle with the */
	/* status and signal our completion so make1c() can run the next */
	/* command.  On interrupts, we bail heavily. */

	if( status == EXEC_CMD_FAIL && ( cmd->rule->flags & RULE_IGNORE ) )
	    status = EXEC_CMD_OK;

	/* On interrupt, set intr so _everything_ fails */

	if( status == EXEC_CMD_INTR )
	    ++intr;

#ifndef OPT_SERIAL_OUTPUT_EXT
	if( status == EXEC_CMD_FAIL && DEBUG_MAKE )
	{
	    /* Print command text on failure */

	    if( !DEBUG_EXEC )
		printf( "%s\n", buffer_ptr( &cmd->commandbuff ) );
#ifdef OPT_RESPONSE_FILES
	    if (!DEBUG_EXEC)
	    {
		printResponseFiles(cmd);
	    }
#endif

	    printf( "*** failed %s ", cmd->rule->name );
	    list_print( lol_get( &cmd->args, 0 ) );
	    printf( "...\n" );

	    if( globs.quitquick ) ++intr;
	}
#else
	if( DEBUG_MAKE )
	{
	    if( DEBUG_MAKEQ || ! ( cmd->rule->flags & RULE_QUIETLY ) )
	    {
#ifdef OPT_PERCENT_DONE_EXT
		    /* CWM - added '@' and %done to front of output */
		    int done = counts->skipped + counts->failed + counts->made;
		    float percent = (done * 99.0f) / globs.updating;
		    printf( "@ %2.0f%% %s ", percent, cmd->rule->name );
#else
		    /* CWM - Added '@' to front of output */
			printf( "@ %s ", cmd->rule->name );
#endif
#ifdef OPT_DEBUG_MAKE_PRINT_TARGET_NAME
		if (globs.printtarget) {
		    printf("%s ", t->name);
		} else {
		    list_print( lol_get( &cmd->args, 0 ) );
		}
#else
		list_print( lol_get( &cmd->args, 0 ) );
#endif
		printf( "\n" );
	    }
	}

	if( DEBUG_EXEC || (status == EXEC_CMD_FAIL && DEBUG_MAKE) )
	{
	    printf( "%s\n", buffer_ptr(&cmd->commandbuff) );
#ifdef OPT_RESPONSE_FILES
	    printResponseFiles(cmd);
#endif
	}

	/* Print the output now, if there was any */
	if( outputname )
	{
		FILE		*fp;
		size_t		n;
		char		buf[4096];

		fp = fopen( outputname, "r" );
		if (fp)
		{
			n = fread(buf, sizeof(char), sizeof buf, fp);
//			if (verifyIsRealOutput (buf, n))
			{
				fwrite(buf, sizeof(char), n, stdout);
				n = fread(buf, sizeof(char), sizeof buf, fp);
				while (n > 0)
				{
					fwrite(buf, sizeof(char), n, stdout);
					n = fread(buf, sizeof(char), sizeof buf, fp);
				}
			}
			fclose(fp);
		}
	}

	if( status == EXEC_CMD_FAIL && DEBUG_MAKE )
	{
	    printf( "*** failed %s ", cmd->rule->name );
#ifdef OPT_DEBUG_MAKE_PRINT_TARGET_NAME
	    if (globs.printtarget) {
		printf("%s ", t->name);
	    } else {
		list_print( lol_get( &cmd->args, 0 ) );
	    }
#else
	    list_print( lol_get( &cmd->args, 0 ) );
#endif
	    printf( "...\n" );

	    if (globs.quitquick)
	    {
		++intr;
	    }
	}
#endif /* OPT_SERIAL_OUTPUT_EXT */

	/* If the command was interrupted or failed and the target */
	/* is not "precious", remove the targets. */
	/* Precious == 'actions updated' -- the target maintains state. */

	if( status != EXEC_CMD_OK )
	{
		if ( !( cmd->rule->flags & RULE_UPDATED ) ) {
	    LIST *targets = lol_get( &cmd->args, 0 );

#ifdef OPT_NODELETE_READONLY
	    for( ; targets; targets = list_next( targets ) )
		if( file_writeable( targets->string ) &&
		    !unlink( targets->string ) )
		    printf( "*** removing %s\n", targets->string );
#else
	    for( ; targets; targets = list_next( targets ) )
		if( !unlink( targets->string ) )
		    printf( "*** removing %s\n", targets->string );
#endif
	}
	}
#ifdef OPT_BUILTIN_MD5CACHE_EXT
	else
	{
	    LIST *targets = lol_get( &cmd->args, 0 );

	    for( ; targets; targets = list_next( targets ) )
	    {
		TARGET *t = bindtarget( targets->string );
		filecache_update( t );
	    }
	}
#endif

	/* Free this command and call make1c() to move onto next command. */

	t->status = (char)status;
	t->cmds = (char *)cmd_next( cmd );

	cmd_free( cmd );

	make1c( t );
}
Beispiel #5
0
int make1( LIST * targets )
{
    state * pState;
    int status = 0;

    memset( (char *)counts, 0, sizeof( *counts ) );
    
    {
        LISTITER iter, end;
        stack temp_stack = { NULL };
        for ( iter = list_begin( targets ), end = list_end( targets );
              iter != end; iter = list_next( iter ) )
            push_state( &temp_stack, bindtarget( list_item( iter ) ), NULL, T_STATE_MAKE1A );
        push_stack_on_stack( &state_stack, &temp_stack );
    }

    /* Clear any state left over from the past */
    quit = 0;

    /* Recursively make the target and its dependencies. */

    while ( 1 )
    {
        while ( ( pState = current_state( &state_stack ) ) )
        {
            if ( quit )
                pop_state( &state_stack );

            switch ( pState->curstate )
            {
                case T_STATE_MAKE1A: make1a( pState ); break;
                case T_STATE_MAKE1B: make1b( pState ); break;
                case T_STATE_MAKE1C: make1c( pState ); break;
                default:
                    assert( !"make1(): Invalid state detected." );
            }
        }
        if ( !cmdsrunning )
            break;
        /* Wait for outstanding commands to finish running. */
        exec_wait();
    }

    clear_state_freelist();

    /* Talk about it. */
    if ( counts->failed )
        printf( "...failed updating %d target%s...\n", counts->failed,
            counts->failed > 1 ? "s" : "" );
    if ( DEBUG_MAKE && counts->skipped )
        printf( "...skipped %d target%s...\n", counts->skipped,
            counts->skipped > 1 ? "s" : "" );
    if ( DEBUG_MAKE && counts->made )
        printf( "...updated %d target%s...\n", counts->made,
            counts->made > 1 ? "s" : "" );

    /* If we were interrupted, exit now that all child processes
       have finished. */
    if ( intr )
        exit( 1 );

    {
        LISTITER iter, end;
        for ( iter = list_begin( targets ), end = list_end( targets );
              iter != end; iter = list_next( iter ) )
        {
            /* Check that the target was updated and that the
               update succeeded. */
            TARGET * t = bindtarget( list_item( iter ) );
            if (t->progress == T_MAKE_DONE)
            {
                if (t->status != EXEC_CMD_OK)
                    status = 1;
            }
            else if ( ! ( t->progress == T_MAKE_NOEXEC_DONE && globs.noexec ) )
            {
                status = 1;
            }
        }
    }
    return status;
}