The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

make1.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc.
00003  *
00004  * This file is part of Jam - see jam.c for Copyright information.
00005  */
00006 
00007 /*  This file is ALSO:
00008  *  (C) Copyright David Abrahams 2001. Permission to copy, use,
00009  *  modify, sell and distribute this software is granted provided this
00010  *  copyright notice appears in all copies. This software is provided
00011  *  "as is" without express or implied warranty, and with no claim as
00012  *  to its suitability for any purpose.
00013  */
00014 
00015 /*
00016  * make1.c - execute command to bring targets up to date
00017  *
00018  * This module contains make1(), the entry point called by make() to 
00019  * recursively decend the dependency graph executing update actions as
00020  * marked by make0().
00021  *
00022  * External routines:
00023  *
00024  *      make1() - execute commands to update a TARGET and all its dependents
00025  *
00026  * Internal routines, the recursive/asynchronous command executors:
00027  *
00028  *      make1a() - recursively traverse target tree, calling make1b()
00029  *      make1b() - dependents of target built, now build target with make1c()
00030  *      make1c() - launch target's next command, call make1b() when done
00031  *      make1d() - handle command execution completion and call back make1c()
00032  *
00033  * Internal support routines:
00034  *
00035  *      make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
00036  *      make1list() - turn a list of targets into a LIST, for $(<) and $(>)
00037  *      make1settings() - for vars that get bound values, build up replacement lists
00038  *      make1bind() - bind targets that weren't bound in dependency analysis
00039  *
00040  * 04/16/94 (seiwald) - Split from make.c.
00041  * 04/21/94 (seiwald) - Handle empty "updated" actions.
00042  * 05/04/94 (seiwald) - async multiprocess (-j) support
00043  * 06/01/94 (seiwald) - new 'actions existing' does existing sources
00044  * 12/20/94 (seiwald) - NOTIME renamed NOTFILE.
00045  * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets.
00046  * 01/22/94 (seiwald) - pass per-target JAMSHELL down to execcmd().
00047  * 02/28/95 (seiwald) - Handle empty "existing" actions.
00048  * 03/10/95 (seiwald) - Fancy counts.
00049  */
00050 
00051 # include "jam.h"
00052 
00053 # include "lists.h"
00054 # include "parse.h"
00055 # include "assert.h"
00056 # include "variable.h"
00057 # include "rules.h"
00058 # include "headers.h"
00059 
00060 # include "search.h"
00061 # include "newstr.h"
00062 # include "make.h"
00063 # include "command.h"
00064 # include "execcmd.h"
00065 
00066 #if defined(sun) || defined(__sun)
00067 #include <unistd.h> /* for unlink */
00068 #endif
00069 
00070 static CMD *make1cmds( TARGET *t );
00071 static LIST *make1list( LIST *l, TARGETS *targets, int flags );
00072 static SETTINGS *make1settings( LIST *vars );
00073 static void make1bind( TARGET *t, int warn );
00074 
00075 /* Ugly static - it's too hard to carry it through the callbacks. */
00076 
00077 static struct {
00078         int     failed;
00079         int     skipped;
00080         int     total;
00081         int     made;
00082 } counts[1] ;
00083 
00084 /*
00085  * Target state - remove recursive calls by just keeping track of state target is in
00086  */
00087 typedef struct _state
00088 {
00089   struct _state *prev; /* previous state on stack */
00090   TARGET *t; /* current target */
00091   TARGET *parent; /* parent argument necessary for make1a() */
00092 #define T_STATE_MAKE1A 0 /* make1a() should be called */
00093 #define T_STATE_MAKE1ATAIL 1 /* make1atail() should be called */
00094 #define T_STATE_MAKE1B 2 /* make1b() should be called */
00095 #define T_STATE_MAKE1C 3 /* make1c() should be called */
00096 #define T_STATE_MAKE1D 4 /* make1d() should be called */
00097   int curstate; /* current state */
00098   int status;
00099 } state;
00100 
00101 static void make1a( state *pState);
00102 static void make1atail(state *pState);
00103 static void make1b( state *pState );
00104 static void make1c( state *pState );
00105 static void make1d( state *pState );
00106 static void make_closure(void *closure, int status);
00107 
00108 typedef struct _stack
00109 {
00110         state *stack;
00111 } stack;
00112 
00113 static stack state_stack = { NULL };
00114 
00115 static state *state_freelist = NULL;
00116 
00117 static state *alloc_state()
00118 {
00119         if(state_freelist != NULL)
00120         {
00121                 state *pState;
00122 
00123                 pState = state_freelist;
00124                 state_freelist = pState->prev;
00125                 memset(pState, 0, sizeof(state));
00126                 return pState;
00127         }
00128         else
00129         {
00130                 return (state *)malloc(sizeof(state));
00131         }
00132 }
00133 
00134 static void free_state(state *pState)
00135 {
00136         pState->prev = state_freelist;
00137         state_freelist = pState;
00138 }
00139 
00140 static void clear_state_freelist()
00141 {
00142         while(state_freelist != NULL)
00143         {
00144                 state *pState = state_freelist;
00145                 state_freelist = state_freelist->prev;
00146                 free(pState);
00147         }
00148 }
00149 
00150 static state *current_state(stack *pStack)
00151 {
00152         return pStack->stack;
00153 }
00154 
00155 static void pop_state(stack *pStack)
00156 {
00157         state *pState;
00158 
00159         if(pStack->stack != NULL)
00160         {
00161                 pState = pStack->stack->prev;
00162                 free_state(pStack->stack);
00163                 pStack->stack = pState;
00164         }
00165 }
00166 
00167 static state *push_state(stack *pStack, TARGET *t, TARGET *parent, int curstate)
00168 {
00169         state *pState;
00170 
00171         pState = alloc_state();
00172 
00173         pState->t = t;
00174         pState->parent = parent;
00175         pState->prev = pStack->stack;
00176         pState->curstate = curstate;
00177 
00178         pStack->stack = pState;
00179 
00180         return pStack->stack;
00181 }
00182 
00183 /* pushes a stack onto another stack, effectively reversing the order */
00184 static void push_stack_on_stack(stack *pDest, stack *pSrc)
00185 {
00186         while(pSrc->stack != NULL)
00187         {
00188                 state *pState;
00189 
00190                 pState = pSrc->stack;
00191                 pSrc->stack = pSrc->stack->prev;
00192                 pState->prev = pDest->stack;
00193                 pDest->stack = pState;
00194         }
00195 }
00196 
00197 /*
00198  * make1() - execute commands to update a TARGET and all its dependents
00199  */
00200 
00201 static int intr = 0;
00202 
00203 int
00204 make1( TARGET *t )
00205 {
00206         state *pState;
00207 
00208         memset( (char *)counts, 0, sizeof( *counts ) );
00209 
00210         /* Recursively make the target and its dependents */
00211         push_state(&state_stack, t, NULL, T_STATE_MAKE1A);
00212 
00213         do
00214         {
00215                 while((pState = current_state(&state_stack)) != NULL)
00216                 {
00217             if (intr) 
00218                 pop_state(&state_stack);
00219 
00220                         switch(pState->curstate)
00221                         {
00222                         case T_STATE_MAKE1A:
00223                                 make1a(pState);
00224                                 break;
00225                         case T_STATE_MAKE1ATAIL:
00226                                 make1atail(pState);
00227                                 break;
00228                         case T_STATE_MAKE1B:
00229                                 make1b(pState);
00230                                 break;
00231                         case T_STATE_MAKE1C:
00232                                 make1c(pState);
00233                                 break;
00234                         case T_STATE_MAKE1D:
00235                                 make1d(pState);
00236                                 break;
00237                         default:
00238                                 break;
00239                         }
00240                 }
00241         
00242 
00243         /* Wait for any outstanding commands to finish running. */
00244         } while( execwait() );
00245 
00246         clear_state_freelist();
00247 
00248         /* Talk about it */
00249         if( counts->failed )
00250             printf( "...failed updating %d target%s...\n", counts->failed,
00251                         counts->failed > 1 ? "s" : "" );
00252 
00253         if( DEBUG_MAKE && counts->skipped )
00254             printf( "...skipped %d target%s...\n", counts->skipped,
00255                         counts->skipped > 1 ? "s" : "" );
00256 
00257         if( DEBUG_MAKE && counts->made )
00258             printf( "...updated %d target%s...\n", counts->made,
00259                         counts->made > 1 ? "s" : "" );
00260 
00261         return counts->total != counts->made;
00262 }
00263 
00264 /*
00265  * make1a() - recursively traverse target tree, calling make1b()
00266  */
00267 
00268 static void
00269 make1a( state *pState)
00270 {
00271     TARGET* t = pState->t;
00272         TARGETS *c;
00273     TARGETS   *inc;
00274 
00275         /* If the parent is the first to try to build this target */
00276         /* or this target is in the make1c() quagmire, arrange for the */
00277         /* parent to be notified when this target is built. */
00278 
00279         if( pState->parent )
00280             switch( pState->t->progress )
00281         {
00282         case T_MAKE_INIT:
00283         case T_MAKE_ACTIVE:
00284         case T_MAKE_RUNNING:
00285             pState->t->parents = targetentry( pState->t->parents, pState->parent );
00286             pState->parent->asynccnt++;
00287         }
00288 
00289         if( pState->t->progress != T_MAKE_INIT )
00290         {
00291                 pop_state(&state_stack);
00292                 return;
00293         }
00294 
00295         /* Asynccnt counts the dependents preventing this target from */
00296         /* proceeding to make1b() for actual building.  We start off with */
00297         /* a count of 1 to prevent anything from happening until we can */
00298         /* call all dependents.  This 1 is accounted for when we call */
00299         /* make1b() ourselves, below. */
00300 
00301         pState->t->asynccnt = 1;
00302 
00303     /* Add header node that was created during building process. */
00304 
00305     inc = 0;
00306     for (c = t->depends; c; c = c->next) {        
00307         if (c->target->rescanned && c->target->includes)
00308             inc = targetentry(inc, c->target->includes);           
00309     }
00310     t->depends = targetchain(t->depends, inc);
00311 
00312         /* against circular dependency. */
00313 
00314         pState->t->progress = T_MAKE_ONSTACK;
00315 
00316         {
00317                 stack temp_stack = { NULL };
00318         for( c = t->depends; c && !intr; c = c->next )            
00319             push_state(&temp_stack, c->target, pState->t, T_STATE_MAKE1A);
00320 
00321                 /* using stacks reverses the order of execution. Reverse it back */
00322                 push_stack_on_stack(&state_stack, &temp_stack);
00323         }
00324 
00325         pState->curstate = T_STATE_MAKE1ATAIL;
00326 }
00327 
00328 static void make1atail(state *pState)
00329 {
00330         pState->t->progress = T_MAKE_ACTIVE;
00331 
00332         /* Now that all dependents have bumped asynccnt, we now allow */
00333         /* decrement our reference to asynccnt. */ 
00334         pState->curstate = T_STATE_MAKE1B;
00335 }
00336 
00337 /*
00338  * make1b() - dependents of target built, now build target with make1c()
00339  */
00340 
00341 static void
00342 make1b( state *pState )
00343 {
00344     TARGET      *t = pState->t;
00345     TARGETS     *c;
00346     TARGET      *failed = 0;
00347     char* failed_name = "dependencies";
00348 
00349     /* If any dependents are still outstanding, wait until they */
00350     /* call make1b() to signal their completion. */
00351 
00352     if( --(pState->t->asynccnt) )
00353         {
00354                 pop_state(&state_stack);
00355                 return;
00356         }
00357     
00358     /* Try to aquire a semaphore. If it's locked, wait until the target
00359        that locked it is build and signals completition. */
00360 #ifdef OPT_SEMAPHORE
00361         if( t->semaphore && t->semaphore->asynccnt )
00362         {
00363         /* Append 't' to the list of targets waiting on semaphore. */
00364             t->semaphore->parents = targetentry( t->semaphore->parents, t );
00365             t->asynccnt++;
00366 
00367             if( DEBUG_EXECCMD )
00368                 printf( "SEM: %s is busy, delaying launch of %s\n",
00369                         t->semaphore->name, t->name);
00370                 pop_state(&state_stack);
00371             return;
00372         }
00373 #endif
00374 
00375 
00376     /* Now ready to build target 't'... if dependents built ok. */
00377 
00378     /* Collect status from dependents */
00379 
00380 
00381     for( c = t->depends; c; c = c->next )
00382         if( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ))
00383         {
00384             failed = c->target;
00385             pState->t->status = c->target->status;
00386         }
00387     /* If a internal header node failed to build, we'd want to output the 
00388        target that it failed on. */
00389     if (failed && (failed->flags & T_FLAG_INTERNAL)) {
00390         failed_name = failed->failed;
00391     } else if (failed) {
00392         failed_name = failed->name;
00393     }
00394     t->failed = failed_name;
00395 
00396     /* If actions on deps have failed, bail. */
00397     /* Otherwise, execute all actions to make target */
00398 
00399     if( pState->t->status == EXEC_CMD_FAIL && pState->t->actions )
00400     {
00401         ++counts->skipped;
00402         if ( ( pState->t->flags & ( T_FLAG_RMOLD | T_FLAG_NOTFILE ) ) == T_FLAG_RMOLD )
00403         {
00404             if( !unlink( pState->t->boundname ) )
00405                 printf( "...removing outdated %s\n", pState->t->boundname );
00406         }
00407         else {
00408             printf( "...skipped %s for lack of %s...\n", pState->t->name, failed_name );
00409         }
00410     }
00411 
00412     if( pState->t->status == EXEC_CMD_OK )
00413         switch( pState->t->fate )
00414         {
00415         case T_FATE_INIT:
00416         case T_FATE_MAKING:
00417             /* shouldn't happen */
00418 
00419         case T_FATE_STABLE:
00420         case T_FATE_NEWER:
00421             break;
00422 
00423         case T_FATE_CANTFIND:
00424         case T_FATE_CANTMAKE:
00425             pState->t->status = EXEC_CMD_FAIL;
00426             break;
00427 
00428         case T_FATE_ISTMP:
00429             if( DEBUG_MAKE )
00430                 printf( "...using %s...\n", pState->t->name );
00431             break;
00432 
00433         case T_FATE_TOUCHED:
00434         case T_FATE_MISSING:
00435         case T_FATE_NEEDTMP:
00436         case T_FATE_OUTDATED:
00437         case T_FATE_UPDATE:
00438 
00439             /* Set "on target" vars, build actions, unset vars */
00440             /* Set "progress" so that make1c() counts this target among */
00441             /* the successes/failures. */
00442 
00443             if( pState->t->actions )
00444             {
00445                 ++counts->total;
00446                 if( DEBUG_MAKE && !( counts->total % 100 ) )
00447                     printf( "...on %dth target...\n", counts->total );
00448 
00449                 pState->t->cmds = (char *)make1cmds( pState->t );
00450                 pState->t->progress = T_MAKE_RUNNING;
00451             }
00452 
00453             break;
00454         }
00455 
00456                 /* Call make1c() to begin the execution of the chain of commands */
00457                 /* needed to build target.  If we're not going to build target */
00458                 /* (because of dependency failures or because no commands need to */
00459                 /* be run) the chain will be empty and make1c() will directly */
00460                 /* signal the completion of target. */
00461 
00462         /* Recurse on our dependents, manipulating progress to guard */
00463 
00464 #ifdef OPT_SEMAPHORE
00465         /* If there is a semaphore, indicate that its in use */
00466         if( pState->t->semaphore )
00467         {
00468             ++(pState->t->semaphore->asynccnt);
00469 
00470             if( DEBUG_EXECCMD )
00471                 printf( "SEM: %s now used by %s\n", pState->t->semaphore->name,
00472                        pState->t->name );
00473         }
00474 #endif
00475 
00476         pState->curstate = T_STATE_MAKE1C;
00477 }
00478 
00479 /*
00480  * make1c() - launch target's next command, call make1b() when done
00481  */
00482 
00483 static void
00484 make1c( state *pState )
00485 {
00486         CMD     *cmd = (CMD *)pState->t->cmds;
00487 
00488         /* If there are (more) commands to run to build this target */
00489         /* (and we haven't hit an error running earlier comands) we */
00490         /* launch the command with execcmd(). */
00491         
00492         /* If there are no more commands to run, we collect the status */
00493         /* from all the actions then report our completion to all the */
00494         /* parents. */
00495 
00496         if( cmd && pState->t->status == EXEC_CMD_OK )
00497         {
00498                 if( DEBUG_MAKEQ || 
00499             ! ( cmd->rule->actions->flags & RULE_QUIETLY ) && DEBUG_MAKE)
00500             {
00501                 printf( "%s ", cmd->rule->name );
00502                 list_print( lol_get( &cmd->args, 0 ) );
00503                 printf( "\n" );
00504             }
00505 
00506             if( DEBUG_EXEC )
00507                 printf( "%s\n", cmd->buf );
00508 
00509             if( globs.cmdout )
00510                 fprintf( globs.cmdout, "%s", cmd->buf );
00511 
00512             if( globs.noexec )
00513             {
00514                         pState->curstate = T_STATE_MAKE1D;
00515                         pState->status = EXEC_CMD_OK;
00516             } 
00517             else
00518             {
00519                         TARGET *t = pState->t;
00520                         fflush( stdout );
00521 
00522                         pop_state(&state_stack); /* pop state first because execcmd could push state */
00523                         execcmd( cmd->buf, make_closure, t, cmd->shell );
00524             }
00525         }
00526         else
00527         {
00528             TARGETS     *c;
00529             ACTIONS     *actions;
00530 
00531             /* Collect status from actions, and distribute it as well */
00532 
00533             for( actions = pState->t->actions; actions; actions = actions->next )
00534                 if( actions->action->status > pState->t->status )
00535                     pState->t->status = actions->action->status;
00536 
00537             for( actions = pState->t->actions; actions; actions = actions->next )
00538                 if( pState->t->status > actions->action->status )
00539                     actions->action->status = pState->t->status;
00540 
00541             /* Tally success/failure for those we tried to update. */
00542 
00543             if( pState->t->progress == T_MAKE_RUNNING )
00544                 switch( pState->t->status )
00545             {
00546             case EXEC_CMD_OK:
00547                 ++counts->made;
00548                 break;
00549             case EXEC_CMD_FAIL:
00550                 ++counts->failed;
00551                 break;
00552             }
00553 
00554             /* Tell parents dependent has been built */
00555                 {
00556                         stack temp_stack = { NULL };
00557                         TARGET *t = pState->t;            
00558             TARGET* additional_includes = NULL;
00559 
00560                         t->progress = T_MAKE_DONE;
00561 
00562             /* Target was updated. Rescan dependencies. */
00563             if (t->fate >= T_FATE_MISSING &&
00564                 t->status == EXEC_CMD_OK &&
00565                 !t->rescanned) {
00566 
00567                 TARGET *target_to_rescan = t;
00568                 SETTINGS *s;               
00569 
00570                 target_to_rescan->rescanned = 1;
00571 
00572                 if (target_to_rescan->flags & T_FLAG_INTERNAL) {
00573                     target_to_rescan = t->original_target;                    
00574                 }
00575 
00576                 /* Clean current includes */
00577                 if (target_to_rescan->includes) {
00578                     target_to_rescan->includes = 0;
00579                 }
00580 
00581                 s = copysettings( target_to_rescan->settings );
00582                 pushsettings( s );
00583                 headers(target_to_rescan);
00584                 popsettings( s );
00585                 freesettings( s );
00586 
00587                 if (target_to_rescan->includes) {
00588                     target_to_rescan->includes->rescanned = 1;
00589                     /* Tricky. The parents were already processed, but they
00590                        did not seen the internal node, because it was just 
00591                        created. We need to make the calls to make1a that would
00592                        have been done by parents here, and also make sure all
00593                        unprocessed parents will pick up the includes. We must
00594                        make sure processing of the additional make1a invocations
00595                        is done before make1b which means this target is built,
00596                        otherwise the parent will be considered built before this
00597                        make1a processing is even started.
00598                     */
00599                     make0(target_to_rescan->includes, target_to_rescan->parents->target, 0, 0, 0);
00600                     for( c = target_to_rescan->parents; c; c = c->next) {
00601                         c->target->depends = targetentry( c->target->depends, 
00602                                                           target_to_rescan->includes );
00603                     }
00604                     /* Will be processed below. */
00605                     additional_includes = target_to_rescan->includes;
00606                 }                
00607             }
00608 
00609             if (additional_includes)
00610                 for ( c = t->parents; c; c = c->next ) {                            
00611                     push_state(&temp_stack, additional_includes, c->target, T_STATE_MAKE1A);
00612                     
00613                 }
00614 
00615                         for( c = t->parents; c; c = c->next ) {
00616                                 push_state(&temp_stack, c->target, NULL, T_STATE_MAKE1B);
00617             }
00618              
00619 
00620 
00621 #ifdef OPT_SEMAPHORE
00622             /* If there is a semaphore, its now free */
00623             if( t->semaphore )
00624             {
00625                 assert( t->semaphore->asynccnt == 1 );
00626                 --(t->semaphore->asynccnt);
00627 
00628                 if( DEBUG_EXECCMD )
00629                     printf( "SEM: %s is now free\n", t->semaphore->name);
00630 
00631                 /* If anything is waiting, notify the next target. There's no
00632             point in notifying all waiting targets, since they'll be
00633             serialized again. */
00634                 if( t->semaphore->parents )
00635                 {
00636                     TARGETS *first = t->semaphore->parents;
00637                     if( first->next )
00638                         first->next->tail = first->tail;
00639                     t->semaphore->parents = first->next;
00640 
00641                     if( DEBUG_EXECCMD )
00642                         printf( "SEM: placing %s on stack\n", first->target->name);
00643             push_state(&temp_stack, first->target, NULL, T_STATE_MAKE1B);
00644                     free( first );
00645                 }
00646             }
00647 #endif
00648 
00649                 
00650                         /* must pop state before pushing any more */
00651                         pop_state(&state_stack);
00652                 
00653                         /* using stacks reverses the order of execution. Reverse it back */
00654                         push_stack_on_stack(&state_stack, &temp_stack);
00655 
00656                 }
00657         }
00658 }
00659 
00660 static void make_closure(void *closure, int status)
00661 {
00662         push_state(&state_stack, (TARGET *)closure, NULL, T_STATE_MAKE1D)->status = status;
00663 }
00664 
00665 /*
00666  * make1d() - handle command execution completion and call back make1c()
00667  */
00668 
00669 static void
00670 make1d(state *pState)
00671 {
00672         TARGET  *t = pState->t;
00673         CMD     *cmd = (CMD *)t->cmds;
00674         int status = pState->status;
00675 
00676         /* Execcmd() has completed.  All we need to do is fiddle with the */
00677         /* status and signal our completion so make1c() can run the next */
00678         /* command.  On interrupts, we bail heavily. */
00679 
00680         if ( t->flags & T_FLAG_FAIL_EXPECTED )
00681         {
00682           /* invert execution result when FAIL_EXPECTED was applied */
00683           switch (status)
00684           {
00685             case EXEC_CMD_FAIL: status = EXEC_CMD_OK; break;
00686             case EXEC_CMD_OK:   status = EXEC_CMD_FAIL; break;
00687             default:
00688               ;
00689           }
00690         }
00691         
00692         if( status == EXEC_CMD_FAIL && ( cmd->rule->actions->flags & RULE_IGNORE ) )
00693             status = EXEC_CMD_OK;
00694 
00695         /* On interrupt, set intr so _everything_ fails */
00696 
00697         if( status == EXEC_CMD_INTR )
00698             ++intr;
00699 
00700         if( status == EXEC_CMD_FAIL && DEBUG_MAKE )
00701         {
00702             /* Print command text on failure */
00703 
00704             if( !DEBUG_EXEC )
00705                 printf( "%s\n", cmd->buf );
00706 
00707             printf( "...failed %s ", cmd->rule->name );
00708             list_print( lol_get( &cmd->args, 0 ) );
00709             printf( "...\n" );
00710         }
00711 
00712         if (status == EXEC_CMD_FAIL)
00713                 if( globs.quitquick ) ++intr;
00714 
00715         /* If the command was interrupted or failed and the target */
00716         /* is not "precious", remove the targets */
00717 
00718         if( status != EXEC_CMD_OK && !( cmd->rule->actions->flags & RULE_TOGETHER ) )
00719         {
00720             LIST *targets = lol_get( &cmd->args, 0 );
00721 
00722             for( ; targets; targets = list_next( targets ) )
00723                 if( !unlink( targets->string ) )
00724                     printf( "...removing %s\n", targets->string );
00725         }
00726 
00727         /* Free this command and call make1c() to move onto next command. */
00728 
00729         t->status = status;
00730         t->cmds = (char *)cmd_next( cmd );
00731 
00732         cmd_free( cmd );
00733 
00734         pState->curstate = T_STATE_MAKE1C;
00735 }
00736 
00737 /*
00738  * swap_settings() - replace the settings from the current module and
00739  *                   target with those from the new module and target
00740  */
00741 static void swap_settings(
00742     module_t** current_module
00743     , TARGET** current_target
00744     , module_t* new_module
00745     , TARGET* new_target)
00746 {
00747     if (new_module == root_module())
00748         new_module = 0;
00749     
00750     if (new_target == *current_target && new_module == *current_module)
00751         return;
00752 
00753     if (*current_target)
00754         popsettings( (*current_target)->settings );
00755         
00756     if (new_module != *current_module)
00757     {
00758         if (*current_module)
00759             exit_module( *current_module );
00760 
00761         *current_module = new_module;
00762         
00763         if (new_module)
00764             enter_module( new_module );
00765     }
00766 
00767     *current_target = new_target;
00768     if (new_target)
00769         pushsettings( new_target->settings );
00770 }
00771 
00772 /*
00773  * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc
00774  *
00775  * Essentially copies a chain of ACTIONs to a chain of CMDs, 
00776  * grouping RULE_TOGETHER actions, splitting RULE_PIECEMEAL actions,
00777  * and handling RULE_NEWSRCS actions.  The result is a chain of
00778  * CMDs which can be expanded by var_string() and executed with
00779  * execcmd().
00780  */
00781 
00782 static CMD *
00783 make1cmds( TARGET *t )
00784 {
00785         CMD *cmds = 0;
00786         LIST *shell = 0;
00787         
00788         module_t *settings_module = 0;
00789         TARGET *settings_target = 0;
00790         
00791         /* Step through actions */
00792         /* Actions may be shared with other targets or grouped with */
00793         /* RULE_TOGETHER, so actions already seen are skipped. */
00794         
00795         ACTIONS* a0;
00796         for(a0 = t->actions ; a0; a0 = a0->next )
00797         {
00798             RULE    *rule = a0->action->rule;
00799             rule_actions *actions = rule->actions;
00800             SETTINGS *boundvars;
00801             LIST    *nt, *ns;
00802             ACTIONS *a1;
00803             int     start, chunk, length;
00804 
00805             /* Only do rules with commands to execute. */
00806             /* If this action has already been executed, use saved status */
00807 
00808             if( !actions || a0->action->running )
00809                 continue;
00810 
00811             a0->action->running = 1;
00812             
00813             /* Make LISTS of targets and sources */
00814             /* If `execute together` has been specified for this rule, tack */
00815             /* on sources from each instance of this rule for this target. */
00816 
00817             nt = make1list( L0, a0->action->targets, 0 );
00818             ns = make1list( L0, a0->action->sources, actions->flags );
00819 
00820             if( actions->flags & RULE_TOGETHER )
00821                 for( a1 = a0->next; a1; a1 = a1->next )
00822                     if( a1->action->rule == rule && !a1->action->running )
00823             {
00824                 ns = make1list( ns, a1->action->sources, actions->flags );
00825                 a1->action->running = 1;
00826             }
00827 
00828             /* If doing only updated (or existing) sources, but none have */
00829             /* been updated (or exist), skip this action. */
00830 
00831             if( !ns && ( actions->flags & ( RULE_NEWSRCS | RULE_EXISTING ) ) )
00832             {
00833                 list_free( nt );
00834                 continue;
00835             }
00836 
00837             swap_settings( &settings_module, &settings_target, rule->module, t );
00838             if (!shell)
00839                 shell = var_get( "JAMSHELL" );  /* shell is per-target */
00840                 
00841             /* If we had 'actions xxx bind vars' we bind the vars now */
00842 
00843             boundvars = make1settings( actions->bindlist );
00844             pushsettings( boundvars );
00845 
00846             /*
00847              * Build command, starting with all source args. 
00848              *
00849              * If cmd_new returns 0, it's because the resulting command
00850              * length is > MAXLINE.  In this case, we'll slowly reduce
00851              * the number of source arguments presented until it does
00852              * fit.  This only applies to actions that allow PIECEMEAL 
00853              * commands.
00854              *
00855              * While reducing slowly takes a bit of compute time to get
00856              * things just right, it's worth it to get as close to MAXLINE
00857              * as possible, because launching the commands we're executing 
00858              * is likely to be much more compute intensive!
00859              *
00860              * Note we loop through at least once, for sourceless actions.
00861              */
00862 
00863             start = 0;
00864             chunk = length = list_length( ns );
00865 
00866             do
00867             {
00868                 /* Build cmd: cmd_new consumes its lists. */
00869 
00870                 CMD *cmd = cmd_new( rule, 
00871                         list_copy( L0, nt ), 
00872                         list_sublist( ns, start, chunk ),
00873                         list_copy( L0, shell ) );
00874 
00875                 if( cmd )
00876                 {
00877                     /* It fit: chain it up. */
00878 
00879                     if( !cmds ) cmds = cmd;
00880                     else cmds->tail->next = cmd;
00881                     cmds->tail = cmd;
00882                     start += chunk;
00883                 }
00884                 else if( ( actions->flags & RULE_PIECEMEAL ) && chunk > 1 )
00885                 {
00886                     /* Reduce chunk size slowly. */
00887 
00888                     chunk = chunk * 9 / 10;
00889                 }
00890                 else
00891                 {
00892                     /* Too long and not splittable. */
00893 
00894                     printf( "%s actions too long (max %d):\n", 
00895                         rule->name, MAXLINE );
00896 
00897                     /* Tell the user what didn't fit */
00898                     cmd = cmd_new(
00899                         rule, list_copy( L0, nt ), 
00900                         list_sublist( ns, start, chunk ),
00901                         list_new( L0, newstr( "%" ) ) );
00902 
00903                     printf( cmd->buf );
00904                 
00905                     exit( EXITBAD );
00906                 }
00907             }
00908             while( start < length );
00909 
00910             /* These were always copied when used. */
00911 
00912             list_free( nt );
00913             list_free( ns );
00914 
00915             /* Free the variables whose values were bound by */
00916             /* 'actions xxx bind vars' */
00917 
00918             popsettings( boundvars );
00919             freesettings( boundvars );
00920         }
00921 
00922         swap_settings( &settings_module, &settings_target, 0, 0 );
00923         return cmds;
00924 }
00925 
00926 /*
00927  * make1list() - turn a list of targets into a LIST, for $(<) and $(>)
00928  */
00929 
00930 static LIST *
00931 make1list( 
00932         LIST    *l,
00933         TARGETS *targets,
00934         int     flags )
00935 {
00936     for( ; targets; targets = targets->next )
00937     {
00938         TARGET *t = targets->target;
00939 
00940         /* Sources to 'actions existing' are never in the dependency */
00941         /* graph (if they were, they'd get built and 'existing' would */
00942         /* be superfluous, so throttle warning message about independent */
00943         /* targets. */
00944 
00945         if( t->binding == T_BIND_UNBOUND )
00946             make1bind( t, !( flags & RULE_EXISTING ) );
00947 
00948     if ( ( flags & RULE_EXISTING ) && ( flags & RULE_NEWSRCS ) )
00949     {
00950         if ( t->binding != T_BIND_EXISTS && t->fate <= T_FATE_STABLE)
00951             continue;
00952     }
00953     else
00954     { 
00955         if( ( flags & RULE_EXISTING ) && t->binding != T_BIND_EXISTS )
00956             continue;
00957 
00958         if( ( flags & RULE_NEWSRCS ) && t->fate <= T_FATE_STABLE )
00959             continue;
00960     }
00961 
00962         /* Prohibit duplicates for RULE_TOGETHER */
00963 
00964         if( flags & RULE_TOGETHER )
00965         {
00966             LIST *m;
00967 
00968             for( m = l; m; m = m->next )
00969                 if( !strcmp( m->string, t->boundname ) )
00970                     break;
00971 
00972             if( m )
00973                 continue;
00974         }
00975 
00976         /* Build new list */
00977 
00978         l = list_new( l, copystr( t->boundname ) );
00979     }
00980 
00981     return l;
00982 }
00983 
00984 /*
00985  * make1settings() - for vars that get bound values, build up replacement lists
00986  */
00987 
00988 static SETTINGS *
00989 make1settings( LIST *vars )
00990 {
00991         SETTINGS *settings = 0;
00992 
00993         for( ; vars; vars = list_next( vars ) )
00994         {
00995             LIST *l = var_get( vars->string );
00996             LIST *nl = 0;
00997 
00998             for( ; l; l = list_next( l ) ) 
00999             {
01000                 TARGET *t = bindtarget( l->string );
01001 
01002                 /* Make sure the target is bound, warning if it is not in the */
01003                 /* dependency graph. */
01004 
01005                 if( t->binding == T_BIND_UNBOUND )
01006                     make1bind( t, 1 );
01007 
01008                 /* Build new list */
01009 
01010                 nl = list_new( nl, copystr( t->boundname ) );
01011             }
01012 
01013             /* Add to settings chain */
01014 
01015             settings = addsettings( settings, 0, vars->string, nl );
01016         }
01017 
01018         return settings;
01019 }
01020 
01021 /*
01022  * make1bind() - bind targets that weren't bound in dependency analysis
01023  *
01024  * Spot the kludge!  If a target is not in the dependency tree, it didn't 
01025  * get bound by make0(), so we have to do it here.  Ugly.
01026  */
01027 
01028 static void
01029 make1bind( 
01030         TARGET  *t,
01031         int     warn )
01032 {
01033         if( t->flags & T_FLAG_NOTFILE )
01034             return;
01035 
01036         /* Sources to 'actions existing' are never in the dependency */
01037         /* graph (if they were, they'd get built and 'existing' would */
01038         /* be superfluous, so throttle warning message about independent */
01039         /* targets. */
01040 
01041         if( warn )
01042             printf( "warning: using independent target %s\n", t->name );
01043 
01044         pushsettings( t->settings );
01045         t->boundname = search( t->name, &t->time, 0 );
01046         t->binding = t->time ? T_BIND_EXISTS : T_BIND_MISSING;
01047         popsettings( t->settings );
01048 }

Generated on Mon Nov 8 17:07:41 2004 for MPT by  doxygen 1.3.9.1