Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/tools/build/jam_src/make1.c @ 12

Last change on this file since 12 was 12, checked in by landauf, 18 years ago

added boost

File size: 28.5 KB
Line 
1/*
2 * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
3 *
4 * This file is part of Jam - see jam.c for Copyright information.
5 */
6
7/*  This file is ALSO:
8 *  Copyright 2001-2004 David Abrahams.
9 *  Distributed under the Boost Software License, Version 1.0.
10 *  (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
11 */
12
13/*
14 * make1.c - execute command to bring targets up to date
15 *
16 * This module contains make1(), the entry point called by make() to
17 * recursively decend the dependency graph executing update actions as
18 * marked by make0().
19 *
20 * External routines:
21 *
22 *      make1() - execute commands to update a TARGET and all its dependents
23 *
24 * Internal routines, the recursive/asynchronous command executors:
25 *
26 *      make1a() - recursively traverse target tree, calling make1b()
27 *      make1b() - dependents of target built, now build target with make1c()
28 *      make1c() - launch target's next command, call make1b() when done
29 *      make1d() - handle command execution completion and call back make1c()
30 *
31 * Internal support routines:
32 *
33 *      make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
34 *      make1list() - turn a list of targets into a LIST, for $(<) and $(>)
35 *      make1settings() - for vars that get bound values, build up replacement lists
36 *      make1bind() - bind targets that weren't bound in dependency analysis
37 *
38 * 04/16/94 (seiwald) - Split from make.c.
39 * 04/21/94 (seiwald) - Handle empty "updated" actions.
40 * 05/04/94 (seiwald) - async multiprocess (-j) support
41 * 06/01/94 (seiwald) - new 'actions existing' does existing sources
42 * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
43 * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
44 * 01/22/94 (seiwald) - pass per-target JAMSHELL down to execcmd().
45 * 02/28/95 (seiwald) - Handle empty "existing" actions.
46 * 03/10/95 (seiwald) - Fancy counts.
47 */
48
49# include "jam.h"
50
51# include "lists.h"
52# include "parse.h"
53# include "assert.h"
54# include "variable.h"
55# include "rules.h"
56# include "headers.h"
57
58# include "search.h"
59# include "newstr.h"
60# include "make.h"
61# include "command.h"
62# include "execcmd.h"
63
64# include <stdlib.h>
65
66#if defined(sun) || defined(__sun)
67#include <unistd.h> /* for unlink */
68#endif
69
70static CMD *make1cmds( TARGET *t );
71static LIST *make1list( LIST *l, TARGETS *targets, int flags );
72static SETTINGS *make1settings( LIST *vars );
73static void make1bind( TARGET *t );
74
75/* Ugly static - it's too hard to carry it through the callbacks. */
76
77static struct {
78        int     failed;
79        int     skipped;
80        int     total;
81        int     made;
82} counts[1] ;
83
84/*
85 * Target state - remove recursive calls by just keeping track of state target is in
86 */
87typedef struct _state
88{
89  struct _state *prev; /* previous state on stack */
90  TARGET *t; /* current target */
91  TARGET *parent; /* parent argument necessary for make1a() */
92#define T_STATE_MAKE1A 0 /* make1a() should be called */
93#define T_STATE_MAKE1ATAIL 1 /* make1atail() should be called */
94#define T_STATE_MAKE1B 2 /* make1b() should be called */
95#define T_STATE_MAKE1C 3 /* make1c() should be called */
96#define T_STATE_MAKE1D 4 /* make1d() should be called */
97  int curstate; /* current state */
98  int status;
99} state;
100
101static void make1a( state *pState);
102static void make1atail(state *pState);
103static void make1b( state *pState );
104static void make1c( state *pState );
105static void make1d( state *pState );
106static void make_closure(void *closure, int status, timing_info*);
107
108typedef struct _stack
109{
110        state *stack;
111} stack;
112
113static stack state_stack = { NULL };
114
115static state *state_freelist = NULL;
116
117static state *alloc_state()
118{
119        if(state_freelist != NULL)
120        {
121                state *pState;
122
123                pState = state_freelist;
124                state_freelist = pState->prev;
125                memset(pState, 0, sizeof(state));
126                return pState;
127        }
128        else
129        {
130                return (state *)malloc(sizeof(state));
131        }
132}
133
134static void free_state(state *pState)
135{
136        pState->prev = state_freelist;
137        state_freelist = pState;
138}
139
140static void clear_state_freelist()
141{
142        while(state_freelist != NULL)
143        {
144                state *pState = state_freelist;
145                state_freelist = state_freelist->prev;
146                free(pState);
147        }
148}
149
150static state *current_state(stack *pStack)
151{
152        return pStack->stack;
153}
154
155static void pop_state(stack *pStack)
156{
157        state *pState;
158
159        if(pStack->stack != NULL)
160        {
161                pState = pStack->stack->prev;
162                free_state(pStack->stack);
163                pStack->stack = pState;
164        }
165}
166
167static state *push_state(stack *pStack, TARGET *t, TARGET *parent, int curstate)
168{
169        state *pState;
170
171        pState = alloc_state();
172
173        pState->t = t;
174        pState->parent = parent;
175        pState->prev = pStack->stack;
176        pState->curstate = curstate;
177
178        pStack->stack = pState;
179
180        return pStack->stack;
181}
182
183/* pushes a stack onto another stack, effectively reversing the order */
184static void push_stack_on_stack(stack *pDest, stack *pSrc)
185{
186        while(pSrc->stack != NULL)
187        {
188                state *pState;
189
190                pState = pSrc->stack;
191                pSrc->stack = pSrc->stack->prev;
192                pState->prev = pDest->stack;
193                pDest->stack = pState;
194        }
195}
196
197/*
198 * make1() - execute commands to update a TARGET and all its dependents
199 */
200
201static int intr = 0;
202
203int
204make1( TARGET *t )
205{
206        state *pState;
207
208        memset( (char *)counts, 0, sizeof( *counts ) );
209
210        /* Recursively make the target and its dependents */
211        push_state(&state_stack, t, NULL, T_STATE_MAKE1A);
212
213        do
214        {
215                while((pState = current_state(&state_stack)) != NULL)
216                {
217            if (intr) 
218                pop_state(&state_stack);
219
220                        switch(pState->curstate)
221                        {
222                        case T_STATE_MAKE1A:
223                                make1a(pState);
224                                break;
225                        case T_STATE_MAKE1ATAIL:
226                                make1atail(pState);
227                                break;
228                        case T_STATE_MAKE1B:
229                                make1b(pState);
230                                break;
231                        case T_STATE_MAKE1C:
232                                make1c(pState);
233                                break;
234                        case T_STATE_MAKE1D:
235                                make1d(pState);
236                                break;
237                        default:
238                                break;
239                        }
240                }
241       
242
243        /* Wait for any outstanding commands to finish running. */
244        } while( execwait() );
245
246        clear_state_freelist();
247
248        /* Talk about it */
249        if( counts->failed )
250            printf( "...failed updating %d target%s...\n", counts->failed,
251                        counts->failed > 1 ? "s" : "" );
252
253        if( DEBUG_MAKE && counts->skipped )
254            printf( "...skipped %d target%s...\n", counts->skipped,
255                        counts->skipped > 1 ? "s" : "" );
256
257        if( DEBUG_MAKE && counts->made )
258            printf( "...updated %d target%s...\n", counts->made,
259                        counts->made > 1 ? "s" : "" );
260
261        return counts->total != counts->made;
262}
263
264/*
265 * make1a() - recursively traverse target tree, calling make1b()
266 */
267
268static void
269make1a( state *pState)
270{
271    TARGET* t = pState->t;
272        TARGETS *c;
273    TARGETS   *inc;
274
275        /* If the parent is the first to try to build this target */
276        /* or this target is in the make1c() quagmire, arrange for the */
277        /* parent to be notified when this target is built. */
278
279        if( pState->parent )
280            switch( pState->t->progress )
281        {
282        case T_MAKE_INIT:
283        case T_MAKE_ACTIVE:
284        case T_MAKE_RUNNING:
285            pState->t->parents = targetentry( pState->t->parents, pState->parent );
286            pState->parent->asynccnt++;
287        }
288
289        if( pState->t->progress != T_MAKE_INIT )
290        {
291                pop_state(&state_stack);
292                return;
293        }
294
295        /* Asynccnt counts the dependents preventing this target from */
296        /* proceeding to make1b() for actual building.  We start off with */
297        /* a count of 1 to prevent anything from happening until we can */
298        /* call all dependents.  This 1 is accounted for when we call */
299        /* make1b() ourselves, below. */
300
301        pState->t->asynccnt = 1;
302
303    /* Add header node that was created during building process. */
304
305    inc = 0;
306    for (c = t->depends; c; c = c->next) {       
307        if (c->target->rescanned && c->target->includes)
308            inc = targetentry(inc, c->target->includes);           
309    }
310    t->depends = targetchain(t->depends, inc);
311
312        /* against circular dependency. */
313
314        pState->t->progress = T_MAKE_ONSTACK;
315
316        {
317                stack temp_stack = { NULL };
318        for( c = t->depends; c && !intr; c = c->next )           
319            push_state(&temp_stack, c->target, pState->t, T_STATE_MAKE1A);
320
321                /* using stacks reverses the order of execution. Reverse it back */
322                push_stack_on_stack(&state_stack, &temp_stack);
323        }
324
325        pState->curstate = T_STATE_MAKE1ATAIL;
326}
327
328static void make1atail(state *pState)
329{
330        pState->t->progress = T_MAKE_ACTIVE;
331
332        /* Now that all dependents have bumped asynccnt, we now allow */
333        /* decrement our reference to asynccnt. */ 
334        pState->curstate = T_STATE_MAKE1B;
335}
336
337/*
338 * make1b() - dependents of target built, now build target with make1c()
339 */
340
341static void
342make1b( state *pState )
343{
344    TARGET      *t = pState->t;
345    TARGETS     *c;
346    TARGET      *failed = 0;
347    char* failed_name = "dependencies";
348
349    /* If any dependents are still outstanding, wait until they */
350    /* call make1b() to signal their completion. */
351
352    if( --(pState->t->asynccnt) )
353        {
354                pop_state(&state_stack);
355                return;
356        }
357   
358    /* Try to aquire a semaphore. If it's locked, wait until the target
359       that locked it is build and signals completition. */
360#ifdef OPT_SEMAPHORE
361        if( t->semaphore && t->semaphore->asynccnt )
362        {
363        /* Append 't' to the list of targets waiting on semaphore. */
364            t->semaphore->parents = targetentry( t->semaphore->parents, t );
365            t->asynccnt++;
366
367            if( DEBUG_EXECCMD )
368                printf( "SEM: %s is busy, delaying launch of %s\n",
369                        t->semaphore->name, t->name);
370                pop_state(&state_stack);
371            return;
372        }
373#endif
374
375
376    /* Now ready to build target 't'... if dependents built ok. */
377
378    /* Collect status from dependents */
379
380
381    for( c = t->depends; c; c = c->next )
382        if( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ))
383        {
384            failed = c->target;
385            pState->t->status = c->target->status;
386        }
387    /* If a internal header node failed to build, we'd want to output the
388       target that it failed on. */
389    if (failed && (failed->flags & T_FLAG_INTERNAL)) {
390        failed_name = failed->failed;
391    } else if (failed) {
392        failed_name = failed->name;
393    }
394    t->failed = failed_name;
395
396    /* If actions on deps have failed, bail. */
397    /* Otherwise, execute all actions to make target */
398
399    if( pState->t->status == EXEC_CMD_FAIL && pState->t->actions )
400    {
401        ++counts->skipped;
402        if ( ( pState->t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
403        {
404            if( !unlink( pState->t->boundname ) )
405                printf( "...removing outdated %s\n", pState->t->boundname );
406        }
407        else {
408            printf( "...skipped %s for lack of %s...\n", pState->t->name, failed_name );
409        }
410    }
411
412    if( pState->t->status == EXEC_CMD_OK )
413        switch( pState->t->fate )
414        {
415            /* These are handled by the default case below now
416        case T_FATE_INIT:
417        case T_FATE_MAKING:
418            */
419
420        case T_FATE_STABLE:
421        case T_FATE_NEWER:
422            break;
423
424        case T_FATE_CANTFIND:
425        case T_FATE_CANTMAKE:
426            pState->t->status = EXEC_CMD_FAIL;
427            break;
428
429        case T_FATE_ISTMP:
430            if( DEBUG_MAKE )
431                printf( "...using %s...\n", pState->t->name );
432            break;
433
434        case T_FATE_TOUCHED:
435        case T_FATE_MISSING:
436        case T_FATE_NEEDTMP:
437        case T_FATE_OUTDATED:
438        case T_FATE_UPDATE:
439        case T_FATE_REBUILD:
440
441            /* Set "on target" vars, build actions, unset vars */
442            /* Set "progress" so that make1c() counts this target among */
443            /* the successes/failures. */
444
445            if( pState->t->actions )
446            {
447                ++counts->total;
448                if( DEBUG_MAKE && !( counts->total % 100 ) )
449                    printf( "...on %dth target...\n", counts->total );
450
451                pState->t->cmds = (char *)make1cmds( pState->t );
452                pState->t->progress = T_MAKE_RUNNING;
453            }
454
455            break;
456           
457            /* All possible fates should have been accounted for by now */
458        default:
459            printf("ERROR: %s has bad fate %d", pState->t->name, pState->t->fate);
460            abort();
461        }
462
463                /* Call make1c() to begin the execution of the chain of commands */
464                /* needed to build target.  If we're not going to build target */
465                /* (because of dependency failures or because no commands need to */
466                /* be run) the chain will be empty and make1c() will directly */
467                /* signal the completion of target. */
468
469        /* Recurse on our dependents, manipulating progress to guard */
470
471#ifdef OPT_SEMAPHORE
472        /* If there is a semaphore, indicate that its in use */
473        if( pState->t->semaphore )
474        {
475            ++(pState->t->semaphore->asynccnt);
476
477            if( DEBUG_EXECCMD )
478                printf( "SEM: %s now used by %s\n", pState->t->semaphore->name,
479                       pState->t->name );
480        }
481#endif
482
483        pState->curstate = T_STATE_MAKE1C;
484}
485
486/*
487 * make1c() - launch target's next command, call make1b() when done
488 */
489
490static void
491make1c( state *pState )
492{
493        CMD     *cmd = (CMD *)pState->t->cmds;
494
495        /* If there are (more) commands to run to build this target */
496        /* (and we haven't hit an error running earlier comands) we */
497        /* launch the command with execcmd(). */
498       
499        /* If there are no more commands to run, we collect the status */
500        /* from all the actions then report our completion to all the */
501        /* parents. */
502
503        if( cmd && pState->t->status == EXEC_CMD_OK )
504        {
505                if( DEBUG_MAKEQ || 
506            ! ( cmd->rule->actions->flags & RULE_QUIETLY ) && DEBUG_MAKE)
507            {
508                printf( "%s ", cmd->rule->name );
509                list_print( lol_get( &cmd->args, 0 ) );
510                printf( "\n" );
511            }
512
513            if( DEBUG_EXEC )
514                printf( "%s\n", cmd->buf );
515
516            if( globs.cmdout )
517                fprintf( globs.cmdout, "%s", cmd->buf );
518
519            if( globs.noexec )
520            {
521                        pState->curstate = T_STATE_MAKE1D;
522                        pState->status = EXEC_CMD_OK;
523            } 
524            else
525            {
526                        TARGET *t = pState->t;
527                        fflush( stdout );
528
529                        pop_state(&state_stack); /* pop state first because execcmd could push state */
530                        execcmd( cmd->buf, make_closure, t, cmd->shell );
531            }
532        }
533        else
534        {
535            TARGETS     *c;
536            ACTIONS     *actions;
537
538            /* Collect status from actions, and distribute it as well */
539
540            for( actions = pState->t->actions; actions; actions = actions->next )
541                if( actions->action->status > pState->t->status )
542                    pState->t->status = actions->action->status;
543
544            for( actions = pState->t->actions; actions; actions = actions->next )
545                if( pState->t->status > actions->action->status )
546                    actions->action->status = pState->t->status;
547
548            /* Tally success/failure for those we tried to update. */
549
550            if( pState->t->progress == T_MAKE_RUNNING )
551                switch( pState->t->status )
552            {
553            case EXEC_CMD_OK:
554                ++counts->made;
555                break;
556            case EXEC_CMD_FAIL:
557                ++counts->failed;
558                break;
559            }
560
561            /* Tell parents dependent has been built */
562                {
563                        stack temp_stack = { NULL };
564                        TARGET *t = pState->t;           
565            TARGET* additional_includes = NULL;
566
567                        t->progress = T_MAKE_DONE;
568
569            /* Target was updated. Rescan dependencies. */
570            if (t->fate >= T_FATE_MISSING &&
571                t->status == EXEC_CMD_OK &&
572                !t->rescanned) {
573
574                TARGET *target_to_rescan = t;
575                SETTINGS *s;               
576
577                target_to_rescan->rescanned = 1;
578
579                if (target_to_rescan->flags & T_FLAG_INTERNAL) {
580                    target_to_rescan = t->original_target;                   
581                }
582
583                /* Clean current includes */
584                if (target_to_rescan->includes) {
585                    target_to_rescan->includes = 0;
586                }
587
588                s = copysettings( target_to_rescan->settings );
589                pushsettings( s );
590                headers(target_to_rescan);
591                popsettings( s );
592                freesettings( s );
593
594                if (target_to_rescan->includes) {
595                    target_to_rescan->includes->rescanned = 1;
596                    /* Tricky. The parents were already processed, but they
597                       did not seen the internal node, because it was just
598                       created. We need to make the calls to make1a that would
599                       have been done by parents here, and also make sure all
600                       unprocessed parents will pick up the includes. We must
601                       make sure processing of the additional make1a invocations
602                       is done before make1b which means this target is built,
603                       otherwise the parent will be considered built before this
604                       make1a processing is even started.
605                    */
606                    make0(target_to_rescan->includes, target_to_rescan->parents->target, 0, 0, 0);
607                    for( c = target_to_rescan->parents; c; c = c->next) {
608                        c->target->depends = targetentry( c->target->depends, 
609                                                          target_to_rescan->includes );
610                    }
611                    /* Will be processed below. */
612                    additional_includes = target_to_rescan->includes;
613                }               
614            }
615
616            if (additional_includes)
617                for ( c = t->parents; c; c = c->next ) {                           
618                    push_state(&temp_stack, additional_includes, c->target, T_STATE_MAKE1A);
619                   
620                }
621
622                        for( c = t->parents; c; c = c->next ) {
623                                push_state(&temp_stack, c->target, NULL, T_STATE_MAKE1B);
624            }
625             
626
627
628#ifdef OPT_SEMAPHORE
629            /* If there is a semaphore, its now free */
630            if( t->semaphore )
631            {
632                assert( t->semaphore->asynccnt == 1 );
633                --(t->semaphore->asynccnt);
634
635                if( DEBUG_EXECCMD )
636                    printf( "SEM: %s is now free\n", t->semaphore->name);
637
638                /* If anything is waiting, notify the next target. There's no
639            point in notifying all waiting targets, since they'll be
640            serialized again. */
641                if( t->semaphore->parents )
642                {
643                    TARGETS *first = t->semaphore->parents;
644                    if( first->next )
645                        first->next->tail = first->tail;
646                    t->semaphore->parents = first->next;
647
648                    if( DEBUG_EXECCMD )
649                        printf( "SEM: placing %s on stack\n", first->target->name);
650            push_state(&temp_stack, first->target, NULL, T_STATE_MAKE1B);
651                    free( first );
652                }
653            }
654#endif
655
656               
657                        /* must pop state before pushing any more */
658                        pop_state(&state_stack);
659               
660                        /* using stacks reverses the order of execution. Reverse it back */
661                        push_stack_on_stack(&state_stack, &temp_stack);
662
663                }
664        }
665}
666
667/* To l, append a 1-element list containing the string representation
668 * of x
669 */
670static void append_double_string( LOL *l, double x )
671{
672    char buffer[50];
673    sprintf(buffer, "%f", x);
674    lol_add( l, list_new( L0, newstr( buffer ) ) );
675}
676
677/* Look up the __TIMING_RULE__ variable on the given target, and if
678 * non-empty, invoke the rule it names, passing the given
679 * timing_info
680 */
681static void call_timing_rule(TARGET* target, timing_info* time)
682{
683    LIST* timing_rule;
684   
685    pushsettings(target->settings);
686    timing_rule = var_get( "__TIMING_RULE__" );
687    popsettings(target->settings);
688
689    if (timing_rule)
690    {
691        /* We'll prepend $(__TIMING_RULE__[2-]) to the first argument */
692        LIST* initial_args = list_copy( L0, timing_rule->next );
693           
694        /* Prepare the argument list */
695        FRAME frame[1];
696        frame_init( frame );
697
698        /* First argument is the name of the timed target */
699        lol_add( frame->args, list_new( initial_args, target->name ) );
700        append_double_string(frame->args, time->user);
701        append_double_string(frame->args, time->system);
702
703        if( lol_get( frame->args, 2 ) )
704            evaluate_rule( timing_rule->string, frame );
705           
706        /* Clean up */
707        frame_free( frame );
708    }
709}
710
711static void make_closure(
712    void *closure, int status, timing_info* time)
713{
714    TARGET* built = (TARGET*)closure;
715
716    call_timing_rule(built, time);
717    if (DEBUG_EXECCMD)
718        printf("%f sec system; %f sec user\n", time->system, time->user);
719   
720    push_state(&state_stack, built, NULL, T_STATE_MAKE1D)->status = status;
721}
722
723/*
724 * make1d() - handle command execution completion and call back make1c()
725 */
726
727static void
728make1d(state *pState)
729{
730        TARGET  *t = pState->t;
731        CMD     *cmd = (CMD *)t->cmds;
732        int status = pState->status;
733
734        /* Execcmd() has completed.  All we need to do is fiddle with the */
735        /* status and signal our completion so make1c() can run the next */
736        /* command.  On interrupts, we bail heavily. */
737
738        if ( t->flags & T_FLAG_FAIL_EXPECTED )
739        {
740          /* invert execution result when FAIL_EXPECTED was applied */
741          switch (status)
742          {
743            case EXEC_CMD_FAIL: status = EXEC_CMD_OK; break;
744            case EXEC_CMD_OK:   status = EXEC_CMD_FAIL; break;
745            default:
746              ;
747          }
748        }
749       
750        if( status == EXEC_CMD_FAIL && ( cmd->rule->actions->flags & RULE_IGNORE ) )
751            status = EXEC_CMD_OK;
752
753        /* On interrupt, set intr so _everything_ fails */
754
755        if( status == EXEC_CMD_INTR )
756            ++intr;
757
758        if( status == EXEC_CMD_FAIL && DEBUG_MAKE )
759        {
760            /* Print command text on failure */
761
762            if( !DEBUG_EXEC )
763                printf( "%s\n", cmd->buf );
764
765            printf( "...failed %s ", cmd->rule->name );
766            list_print( lol_get( &cmd->args, 0 ) );
767            printf( "...\n" );
768        }
769
770        if (status == EXEC_CMD_FAIL)
771                if( globs.quitquick ) ++intr;
772
773        /* If the command was interrupted or failed and the target */
774        /* is not "precious", remove the targets */
775
776        if( status != EXEC_CMD_OK && !( cmd->rule->actions->flags & RULE_TOGETHER ) )
777        {
778            LIST *targets = lol_get( &cmd->args, 0 );
779
780            for( ; targets; targets = list_next( targets ) )
781                if( !unlink( targets->string ) )
782                    printf( "...removing %s\n", targets->string );
783        }
784
785        /* Free this command and call make1c() to move onto next command. */
786
787        t->status = status;
788        t->cmds = (char *)cmd_next( cmd );
789
790        cmd_free( cmd );
791
792        pState->curstate = T_STATE_MAKE1C;
793}
794
795/*
796 * swap_settings() - replace the settings from the current module and
797 *                   target with those from the new module and target
798 */
799static void swap_settings(
800    module_t** current_module
801    , TARGET** current_target
802    , module_t* new_module
803    , TARGET* new_target)
804{
805    if (new_module == root_module())
806        new_module = 0;
807   
808    if (new_target == *current_target && new_module == *current_module)
809        return;
810
811    if (*current_target)
812        popsettings( (*current_target)->settings );
813       
814    if (new_module != *current_module)
815    {
816        if (*current_module)
817            exit_module( *current_module );
818
819        *current_module = new_module;
820       
821        if (new_module)
822            enter_module( new_module );
823    }
824
825    *current_target = new_target;
826    if (new_target)
827        pushsettings( new_target->settings );
828}
829
830/*
831 * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
832 *
833 * Essentially copies a chain of ACTIONs to a chain of CMDs,
834 * grouping RULE_TOGETHER actions, splitting RULE_PIECEMEAL actions,
835 * and handling RULE_NEWSRCS actions.  The result is a chain of
836 * CMDs which can be expanded by var_string() and executed with
837 * execcmd().
838 */
839
840static CMD *
841make1cmds( TARGET *t )
842{
843        CMD *cmds = 0;
844        LIST *shell = 0;
845       
846        module_t *settings_module = 0;
847        TARGET *settings_target = 0;
848       
849        /* Step through actions */
850        /* Actions may be shared with other targets or grouped with */
851        /* RULE_TOGETHER, so actions already seen are skipped. */
852       
853        ACTIONS* a0;
854        for(a0 = t->actions ; a0; a0 = a0->next )
855        {
856            RULE    *rule = a0->action->rule;
857            rule_actions *actions = rule->actions;
858            SETTINGS *boundvars;
859            LIST    *nt, *ns;
860            ACTIONS *a1;
861            int     start, chunk, length;
862
863            /* Only do rules with commands to execute. */
864            /* If this action has already been executed, use saved status */
865
866            if( !actions || a0->action->running )
867                continue;
868
869            a0->action->running = 1;
870           
871            /* Make LISTS of targets and sources */
872            /* If `execute together` has been specified for this rule, tack */
873            /* on sources from each instance of this rule for this target. */
874
875            nt = make1list( L0, a0->action->targets, 0 );
876            ns = make1list( L0, a0->action->sources, actions->flags );
877
878            if( actions->flags & RULE_TOGETHER )
879                for( a1 = a0->next; a1; a1 = a1->next )
880                    if( a1->action->rule == rule && !a1->action->running )
881            {
882                ns = make1list( ns, a1->action->sources, actions->flags );
883                a1->action->running = 1;
884            }
885
886            /* If doing only updated (or existing) sources, but none have */
887            /* been updated (or exist), skip this action. */
888
889            if( !ns && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
890            {
891                list_free( nt );
892                continue;
893            }
894
895            swap_settings( &settings_module, &settings_target, rule->module, t );
896            if (!shell)
897                shell = var_get( "JAMSHELL" );  /* shell is per-target */
898               
899            /* If we had 'actions xxx bind vars' we bind the vars now */
900
901            boundvars = make1settings( actions->bindlist );
902            pushsettings( boundvars );
903
904            /*
905             * Build command, starting with all source args.
906             *
907             * If cmd_new returns 0, it's because the resulting command
908             * length is > MAXLINE.  In this case, we'll slowly reduce
909             * the number of source arguments presented until it does
910             * fit.  This only applies to actions that allow PIECEMEAL
911             * commands.
912             *
913             * While reducing slowly takes a bit of compute time to get
914             * things just right, it's worth it to get as close to MAXLINE
915             * as possible, because launching the commands we're executing
916             * is likely to be much more compute intensive!
917             *
918             * Note we loop through at least once, for sourceless actions.
919             */
920
921            start = 0;
922            chunk = length = list_length( ns );
923
924            do
925            {
926                /* Build cmd: cmd_new consumes its lists. */
927
928                CMD *cmd = cmd_new( rule, 
929                        list_copy( L0, nt ), 
930                        list_sublist( ns, start, chunk ),
931                        list_copy( L0, shell ) );
932
933                if( cmd )
934                {
935                    /* It fit: chain it up. */
936
937                    if( !cmds ) cmds = cmd;
938                    else cmds->tail->next = cmd;
939                    cmds->tail = cmd;
940                    start += chunk;
941                }
942                else if( ( actions->flags & RULE_PIECEMEAL ) && chunk > 1 )
943                {
944                    /* Reduce chunk size slowly. */
945
946                    chunk = chunk * 9 / 10;
947                }
948                else
949                {
950                    /* Too long and not splittable. */
951
952                    printf( "%s actions too long (max %d):\n", 
953                        rule->name, MAXLINE );
954
955                    /* Tell the user what didn't fit */
956                    cmd = cmd_new(
957                        rule, list_copy( L0, nt ), 
958                        list_sublist( ns, start, chunk ),
959                        list_new( L0, newstr( "%" ) ) );
960
961                    printf( cmd->buf );
962               
963                    exit( EXITBAD );
964                }
965            }
966            while( start < length );
967
968            /* These were always copied when used. */
969
970            list_free( nt );
971            list_free( ns );
972
973            /* Free the variables whose values were bound by */
974            /* 'actions xxx bind vars' */
975
976            popsettings( boundvars );
977            freesettings( boundvars );
978        }
979
980        swap_settings( &settings_module, &settings_target, 0, 0 );
981        return cmds;
982}
983
984/*
985 * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
986 */
987
988static LIST *
989make1list( 
990        LIST    *l,
991        TARGETS *targets,
992        int     flags )
993{
994    for( ; targets; targets = targets->next )
995    {
996        TARGET *t = targets->target;
997
998        if( t->binding == T_BIND_UNBOUND )
999            make1bind( t );
1000
1001    if ( ( flags & RULE_EXISTING ) && ( flags & RULE_NEWSRCS ) )
1002    {
1003        if ( t->binding != T_BIND_EXISTS && t->fate <= T_FATE_STABLE)
1004            continue;
1005    }
1006    else
1007    { 
1008        if( ( flags & RULE_EXISTING ) && t->binding != T_BIND_EXISTS )
1009            continue;
1010
1011        if( ( flags & RULE_NEWSRCS ) && t->fate <= T_FATE_STABLE )
1012            continue;
1013    }
1014
1015        /* Prohibit duplicates for RULE_TOGETHER */
1016
1017        if( flags & RULE_TOGETHER )
1018        {
1019            LIST *m;
1020
1021            for( m = l; m; m = m->next )
1022                if( !strcmp( m->string, t->boundname ) )
1023                    break;
1024
1025            if( m )
1026                continue;
1027        }
1028
1029        /* Build new list */
1030
1031        l = list_new( l, copystr( t->boundname ) );
1032    }
1033
1034    return l;
1035}
1036
1037/*
1038 * make1settings() - for vars that get bound values, build up replacement lists
1039 */
1040
1041static SETTINGS *
1042make1settings( LIST *vars )
1043{
1044        SETTINGS *settings = 0;
1045
1046        for( ; vars; vars = list_next( vars ) )
1047        {
1048            LIST *l = var_get( vars->string );
1049            LIST *nl = 0;
1050
1051            for( ; l; l = list_next( l ) ) 
1052            {
1053                TARGET *t = bindtarget( l->string );
1054
1055                /* Make sure the target is bound */
1056
1057                if( t->binding == T_BIND_UNBOUND )
1058                    make1bind( t );
1059
1060                /* Build new list */
1061
1062                nl = list_new( nl, copystr( t->boundname ) );
1063            }
1064
1065            /* Add to settings chain */
1066
1067            settings = addsettings( settings, 0, vars->string, nl );
1068        }
1069
1070        return settings;
1071}
1072
1073/*
1074 * make1bind() - bind targets that weren't bound in dependency analysis
1075 *
1076 * Spot the kludge!  If a target is not in the dependency tree, it didn't
1077 * get bound by make0(), so we have to do it here.  Ugly.
1078 */
1079
1080static void
1081make1bind( 
1082        TARGET  *t )
1083{
1084        if( t->flags & T_FLAG_NOTFILE )
1085            return;
1086
1087        pushsettings( t->settings );
1088        t->boundname = search( t->name, &t->time, 0 );
1089        t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
1090        popsettings( t->settings );
1091}
Note: See TracBrowser for help on using the repository browser.