Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/tools/jam/src/make1.c @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

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