Exemplo n.º 1
0
static void
make1a( state *pState)
{
    TARGET* t = pState->t;
	TARGETS	*c;
    TARGETS   *inc;

	/* If the parent is the first to try to build this target */
	/* or this target is in the make1c() quagmire, arrange for the */
	/* parent to be notified when this target is built. */

	if( pState->parent )
	    switch( pState->t->progress )
	{
	case T_MAKE_INIT:
	case T_MAKE_ACTIVE:
	case T_MAKE_RUNNING:
	    pState->t->parents = targetentry( pState->t->parents, pState->parent );
	    pState->parent->asynccnt++;
	}

	if( pState->t->progress != T_MAKE_INIT )
	{
		pop_state(&state_stack);
		return;
	}

	/* Asynccnt counts the dependents preventing this target from */
	/* proceeding to make1b() for actual building.  We start off with */
	/* a count of 1 to prevent anything from happening until we can */
	/* call all dependents.  This 1 is accounted for when we call */
	/* make1b() ourselves, below. */

	pState->t->asynccnt = 1;

    /* Add header node that was created during building process. */

    inc = 0;
    for (c = t->depends; c; c = c->next) {        
        if (c->target->rescanned && c->target->includes)
            inc = targetentry(inc, c->target->includes);           
    }
    t->depends = targetchain(t->depends, inc);

	/* against circular dependency. */

	pState->t->progress = T_MAKE_ONSTACK;

	{
		stack temp_stack = { NULL };
        for( c = t->depends; c && !intr; c = c->next )            
            push_state(&temp_stack, c->target, pState->t, T_STATE_MAKE1A);

		/* using stacks reverses the order of execution. Reverse it back */
		push_stack_on_stack(&state_stack, &temp_stack);
	}

	pState->curstate = T_STATE_MAKE1ATAIL;
}
Exemplo n.º 2
0
static void
make1c( state *pState )
{
	CMD	*cmd = (CMD *)pState->t->cmds;

	/* If there are (more) commands to run to build this target */
	/* (and we haven't hit an error running earlier comands) we */
	/* launch the command with execcmd(). */
	
	/* If there are no more commands to run, we collect the status */
	/* from all the actions then report our completion to all the */
	/* parents. */

	if( cmd && pState->t->status == EXEC_CMD_OK )
	{
		if( DEBUG_MAKEQ || 
            ! ( cmd->rule->actions->flags & RULE_QUIETLY ) && DEBUG_MAKE)
	    {
		printf( "%s ", cmd->rule->name );
		list_print( lol_get( &cmd->args, 0 ) );
		printf( "\n" );
	    }

	    if( DEBUG_EXEC )
		printf( "%s\n", cmd->buf );

	    if( globs.cmdout )
		fprintf( globs.cmdout, "%s", cmd->buf );

	    if( globs.noexec )
	    {
			pState->curstate = T_STATE_MAKE1D;
			pState->status = EXEC_CMD_OK;
	    } 
	    else
	    {
			TARGET *t = pState->t;
			fflush( stdout );

			pop_state(&state_stack); /* pop state first because execcmd could push state */
			execcmd( cmd->buf, make_closure, t, cmd->shell );
	    }
	}
	else
	{
	    TARGETS	*c;
	    ACTIONS	*actions;

	    /* Collect status from actions, and distribute it as well */

	    for( actions = pState->t->actions; actions; actions = actions->next )
		if( actions->action->status > pState->t->status )
		    pState->t->status = actions->action->status;

	    for( actions = pState->t->actions; actions; actions = actions->next )
		if( pState->t->status > actions->action->status )
		    actions->action->status = pState->t->status;

	    /* Tally success/failure for those we tried to update. */

	    if( pState->t->progress == T_MAKE_RUNNING )
		switch( pState->t->status )
	    {
	    case EXEC_CMD_OK:
		++counts->made;
		break;
	    case EXEC_CMD_FAIL:
		++counts->failed;
		break;
	    }

	    /* Tell parents dependent has been built */
		{
			stack temp_stack = { NULL };
			TARGET *t = pState->t;            
            TARGET* additional_includes = NULL;

			t->progress = T_MAKE_DONE;

            /* Target was updated. Rescan dependencies. */
            if (t->fate >= T_FATE_MISSING &&
                t->status == EXEC_CMD_OK &&
                !t->rescanned) {

                TARGET *target_to_rescan = t;
                SETTINGS *s;               

                target_to_rescan->rescanned = 1;

                if (target_to_rescan->flags & T_FLAG_INTERNAL) {
                    target_to_rescan = t->original_target;                    
                }

                /* Clean current includes */
                if (target_to_rescan->includes) {
                    target_to_rescan->includes = 0;
                }

                s = copysettings( target_to_rescan->settings );
                pushsettings( s );
                headers(target_to_rescan);
                popsettings( s );
                freesettings( s );

                if (target_to_rescan->includes) {
                    target_to_rescan->includes->rescanned = 1;
                    /* Tricky. The parents were already processed, but they
                       did not seen the internal node, because it was just 
                       created. We need to make the calls to make1a that would
                       have been done by parents here, and also make sure all
                       unprocessed parents will pick up the includes. We must
                       make sure processing of the additional make1a invocations
                       is done before make1b which means this target is built,
                       otherwise the parent will be considered built before this
                       make1a processing is even started.
                    */
                    make0(target_to_rescan->includes, target_to_rescan->parents->target, 0, 0, 0);
                    for( c = target_to_rescan->parents; c; c = c->next) {
                        c->target->depends = targetentry( c->target->depends, 
                                                          target_to_rescan->includes );
                    }
                    /* Will be processed below. */
                    additional_includes = target_to_rescan->includes;
                }                
            }

            if (additional_includes)
                for ( c = t->parents; c; c = c->next ) {                            
                    push_state(&temp_stack, additional_includes, c->target, T_STATE_MAKE1A);
                    
                }

			for( c = t->parents; c; c = c->next ) {
				push_state(&temp_stack, c->target, NULL, T_STATE_MAKE1B);
            }
             


#ifdef OPT_SEMAPHORE
	    /* If there is a semaphore, its now free */
	    if( t->semaphore )
	    {
		assert( t->semaphore->asynccnt == 1 );
		--(t->semaphore->asynccnt);

		if( DEBUG_EXECCMD )
		    printf( "SEM: %s is now free\n", t->semaphore->name);

		/* If anything is waiting, notify the next target. There's no
            point in notifying all waiting targets, since they'll be
            serialized again. */
		if( t->semaphore->parents )
		{
		    TARGETS *first = t->semaphore->parents;
		    if( first->next )
			first->next->tail = first->tail;
		    t->semaphore->parents = first->next;

		    if( DEBUG_EXECCMD )
			printf( "SEM: placing %s on stack\n", first->target->name);
            push_state(&temp_stack, first->target, NULL, T_STATE_MAKE1B);
		    free( first );
		}
	    }
#endif

		
			/* must pop state before pushing any more */
			pop_state(&state_stack);
		
			/* using stacks reverses the order of execution. Reverse it back */
			push_stack_on_stack(&state_stack, &temp_stack);

		}
	}
}
Exemplo n.º 3
0
static void
make1c( state *pState )
{
	CMD	*cmd = (CMD *)pState->t->cmds;

	/* If there are (more) commands to run to build this target */
	/* (and we haven't hit an error running earlier comands) we */
	/* launch the command with execcmd(). */
	
	/* If there are no more commands to run, we collect the status */
	/* from all the actions then report our completion to all the */
	/* parents. */

	if( cmd && pState->t->status == EXEC_CMD_OK )
	{
		if( DEBUG_MAKEQ || 
            ! ( cmd->rule->actions->flags & RULE_QUIETLY ) && DEBUG_MAKE)
	    {
		printf( "%s ", cmd->rule->name );
		list_print( lol_get( &cmd->args, 0 ) );
		printf( "\n" );
	    }

	    if( DEBUG_EXEC )
		printf( "%s\n", cmd->buf );

	    if( globs.cmdout )
		fprintf( globs.cmdout, "%s", cmd->buf );

	    if( globs.noexec )
	    {
			pState->curstate = T_STATE_MAKE1D;
			pState->status = EXEC_CMD_OK;
	    } 
	    else
	    {
			TARGET *t = pState->t;
			fflush( stdout );

			pop_state(&state_stack); /* pop state first because execcmd could push state */
			execcmd( cmd->buf, make_closure, t, cmd->shell );
	    }
	}
	else
	{
	    TARGETS	*c;
	    ACTIONS	*actions;

	    /* Collect status from actions, and distribute it as well */

	    for( actions = pState->t->actions; actions; actions = actions->next )
		if( actions->action->status > pState->t->status )
		    pState->t->status = actions->action->status;

	    for( actions = pState->t->actions; actions; actions = actions->next )
		if( pState->t->status > actions->action->status )
		    actions->action->status = pState->t->status;

	    /* Tally success/failure for those we tried to update. */

	    if( pState->t->progress == T_MAKE_RUNNING )
		switch( pState->t->status )
	    {
	    case EXEC_CMD_OK:
		++counts->made;
		break;
	    case EXEC_CMD_FAIL:
		++counts->failed;
		break;
	    }

	    /* Tell parents dependent has been built */
		{
			stack temp_stack = { NULL };
			TARGET *t = pState->t;

			t->progress = T_MAKE_DONE;

			for( c = t->parents; c; c = c->next )
				push_state(&temp_stack, c->target, NULL, T_STATE_MAKE1B);

#ifdef OPT_SEMAPHORE
	    /* If there is a semaphore, its now free */
	    if( t->semaphore )
	    {
		assert( t->semaphore->asynccnt == 1 );
		--(t->semaphore->asynccnt);

		if( DEBUG_EXECCMD )
		    printf( "SEM: %s is now free\n", t->semaphore->name);

		/* If anything is waiting, notify the next target. There's no
            point in notifying all waiting targets, since they'll be
            serialized again. */
		if( t->semaphore->parents )
		{
		    TARGETS *first = t->semaphore->parents;
		    if( first->next )
			first->next->tail = first->tail;
		    t->semaphore->parents = first->next;

		    if( DEBUG_EXECCMD )
			printf( "SEM: placing %s on stack\n", first->target->name);
            push_state(&temp_stack, first->target, NULL, T_STATE_MAKE1B);
		    free( first );
		}
	    }
#endif

		
			/* must pop state before pushing any more */
			pop_state(&state_stack);
		
			/* using stacks reverses the order of execution. Reverse it back */
			push_stack_on_stack(&state_stack, &temp_stack);

		}
	}
}
Exemplo n.º 4
0
static void make1c( state const * const pState )
{
    TARGET * const t = pState->t;
    CMD * const cmd = (CMD *)t->cmds;

    if ( cmd && t->status == EXEC_CMD_OK )
    {
        /* Pop state first in case something below (e.g. exec_cmd(), exec_wait()
         * or make1c_closure()) pushes a new state. Note that we must not access
         * the popped state data after this as the same stack node might have
         * been reused internally for some newly pushed state.
         */
        pop_state( &state_stack );

        /* Increment the jobs running counter. */
        ++cmdsrunning;

        /* Execute the actual build command or fake it if no-op. */
        if ( globs.noexec || cmd->noop )
        {
            timing_info time_info = { 0 };
            timestamp_current( &time_info.start );
            timestamp_copy( &time_info.end, &time_info.start );
            make1c_closure( t, EXEC_CMD_OK, &time_info, "", "", EXIT_OK );
        }
        else
        {
            exec_cmd( cmd->buf, make1c_closure, t, cmd->shell );

            /* Wait until under the concurrent command count limit. */
            /* FIXME: This wait could be skipped here and moved to just before
             * trying to execute a command that would cross the command count
             * limit. Note though that this might affect the order in which
             * unrelated targets get built and would thus require that all
             * affected Boost Build tests be updated.
             */
            assert( 0 < globs.jobs );
            assert( globs.jobs <= MAXJOBS );
            while ( cmdsrunning >= globs.jobs )
                exec_wait();
        }
    }
    else
    {
        ACTIONS * actions;

        /* Collect status from actions, and distribute it as well. */
        for ( actions = t->actions; actions; actions = actions->next )
            if ( actions->action->status > t->status )
                t->status = actions->action->status;
        for ( actions = t->actions; actions; actions = actions->next )
            if ( t->status > actions->action->status )
                actions->action->status = t->status;

        /* Tally success/failure for those we tried to update. */
        if ( t->progress == T_MAKE_RUNNING )
            switch ( t->status )
            {
                case EXEC_CMD_OK: ++counts->made; break;
                case EXEC_CMD_FAIL: ++counts->failed; break;
            }

        /* Tell parents their dependency has been built. */
        {
            TARGETS * c;
            stack temp_stack = { NULL };
            TARGET * additional_includes = NULL;

            t->progress = globs.noexec ? T_MAKE_NOEXEC_DONE : T_MAKE_DONE;

            /* Target has been updated so rescan it for dependencies. */
            if ( t->fate >= T_FATE_MISSING && t->status == EXEC_CMD_OK &&
                !( t->flags & T_FLAG_INTERNAL ) )
            {
                TARGET * saved_includes;
                SETTINGS * s;

                t->rescanned = 1;

                /* Clean current includes. */
                saved_includes = t->includes;
                t->includes = 0;

                s = copysettings( t->settings );
                pushsettings( root_module(), s );
                headers( t );
                popsettings( root_module(), s );
                freesettings( s );

                if ( t->includes )
                {
                    /* Tricky. The parents have already been processed, but they
                     * have not seen the internal node, because it was just
                     * created. We need to:
                     *  - push MAKE1A states that would have been pushed by the
                     *    parents here
                     *  - make sure all unprocessed parents will pick up the
                     *    new includes
                     *  - make sure processing the additional MAKE1A states is
                     *    done before processing the MAKE1B state for our
                     *    current target (which would mean this target has
                     *    already been built), otherwise the parent would be
                     *    considered built before the additional MAKE1A state
                     *    processing even got a chance to start.
                     */
                    make0( t->includes, t->parents->target, 0, 0, 0, t->includes
                        );
                    /* Link the old includes on to make sure that it gets
                     * cleaned up correctly.
                     */
                    t->includes->includes = saved_includes;
                    for ( c = t->dependants; c; c = c->next )
                        c->target->depends = targetentry( c->target->depends,
                            t->includes );
                    /* Will be processed below. */
                    additional_includes = t->includes;
                }
                else
                {
                    t->includes = saved_includes;
                }
            }

            if ( additional_includes )
                for ( c = t->parents; c; c = c->next )
                    push_state( &temp_stack, additional_includes, c->target,
                        T_STATE_MAKE1A );

            if ( t->scc_root )
            {
                TARGET * const scc_root = target_scc( t );
                assert( scc_root->progress < T_MAKE_DONE );
                for ( c = t->parents; c; c = c->next )
                {
                    if ( target_scc( c->target ) == scc_root )
                        push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B
                            );
                    else
                        scc_root->parents = targetentry( scc_root->parents,
                            c->target );
                }
            }
            else
            {
                for ( c = t->parents; c; c = c->next )
                    push_state( &temp_stack, c->target, NULL, T_STATE_MAKE1B );
            }

#ifdef OPT_SEMAPHORE
            /* If there is a semaphore, it is now free. */
            if ( t->semaphore )
            {
                assert( t->semaphore->asynccnt == 1 );
                --t->semaphore->asynccnt;

                if ( DEBUG_EXECCMD )
                    printf( "SEM: %s is now free\n", object_str(
                        t->semaphore->name ) );

                /* If anything is waiting, notify the next target. There is no
                 * point in notifying all waiting targets, since they will be
                 * notified again.
                 */
                if ( t->semaphore->parents )
                {
                    TARGETS * first = t->semaphore->parents;
                    t->semaphore->parents = first->next;
                    if ( first->next )
                        first->next->tail = first->tail;

                    if ( DEBUG_EXECCMD )
                        printf( "SEM: placing %s on stack\n", object_str(
                            first->target->name ) );
                    push_state( &temp_stack, first->target, NULL, T_STATE_MAKE1B
                        );
                    BJAM_FREE( first );
                }
            }
#endif

            /* Must pop state before pushing any more. */
            pop_state( &state_stack );

            /* Using stacks reverses the order of execution. Reverse it back. */
            push_stack_on_stack( &state_stack, &temp_stack );
        }
    }
}
Exemplo n.º 5
0
static void make1a( state * const pState )
{
    TARGET * t = pState->t;
    TARGET * const scc_root = target_scc( t );

    if ( !pState->parent || target_scc( pState->parent ) != scc_root )
        pState->t = t = scc_root;

    /* If the parent is the first to try to build this target or this target is
     * in the MAKE1C quagmire, arrange for the parent to be notified when this
     * target has been built.
     */
    if ( pState->parent && t->progress <= T_MAKE_RUNNING )
    {
        TARGET * const parent_scc = target_scc( pState->parent );
        if ( t != parent_scc )
        {
            t->parents = targetentry( t->parents, parent_scc );
            ++parent_scc->asynccnt;
        }
    }

    /* If the target has been previously updated with -n in effect, and we are
     * now ignoring -n, update it for real. E.g. if the UPDATE_NOW rule was
     * called for it twice - first with the -n option and then without.
     */
    if ( !globs.noexec && t->progress == T_MAKE_NOEXEC_DONE )
        t->progress = T_MAKE_INIT;

    /* If this target is already being processed then do nothing. There is no
     * need to start processing the same target all over again.
     */
    if ( t->progress != T_MAKE_INIT )
    {
        pop_state( &state_stack );
        return;
    }

    /* Guard against circular dependencies. */
    t->progress = T_MAKE_ONSTACK;

    /* 'asynccnt' counts the dependencies preventing this target from proceeding
     * to MAKE1C for actual building. We start off with a count of 1 to prevent
     * anything from happening until we can notify all dependencies that they
     * are needed. This 1 is then accounted for when we enter MAKE1B ourselves,
     * below. Without this if a dependency gets built before we finish
     * processing all of our other dependencies our build might be triggerred
     * prematurely.
     */
    t->asynccnt = 1;

    /* Push dependency build requests (to be executed in the natural order). */
    {
        stack temp_stack = { NULL };
        TARGETS * c;
        for ( c = t->depends; c && !intr; c = c->next )
            push_state( &temp_stack, c->target, t, T_STATE_MAKE1A );
        push_stack_on_stack( &state_stack, &temp_stack );
    }

    t->progress = T_MAKE_ACTIVE;

    /* Once all of our dependencies have started getting processed we can move
     * onto MAKE1B.
     */
    /* Implementation note:
     *   In theory this would be done by popping this state before pushing
     * dependency target build requests but as a slight optimization we simply
     * modify our current state and leave it on the stack instead.
     */
    pState->curstate = T_STATE_MAKE1B;
}
Exemplo n.º 6
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;
}