📄 make1.c
字号:
/* * Copyright 1993-2002 Christopher Seiwald and Perforce Software, Inc. * * This file is part of Jam - see jam.c for Copyright information. *//* This file is ALSO: * Copyright 2001-2004 David Abrahams. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) *//* * make1.c - execute command to bring targets up to date * * This module contains make1(), the entry point called by make() to * recursively decend the dependency graph executing update actions as * marked by make0(). * * External routines: * * make1() - execute commands to update a TARGET and all its dependents * * Internal routines, the recursive/asynchronous command executors: * * make1a() - recursively traverse target tree, calling make1b() * make1b() - dependents of target built, now build target with make1c() * make1c() - launch target's next command, call make1b() when done * make1d() - handle command execution completion and call back make1c() * * Internal support routines: * * make1cmds() - turn ACTIONS into CMDs, grouping, splitting, etc * make1list() - turn a list of targets into a LIST, for $(<) and $(>) * make1settings() - for vars that get bound values, build up replacement lists * make1bind() - bind targets that weren't bound in dependency analysis * * 04/16/94 (seiwald) - Split from make.c. * 04/21/94 (seiwald) - Handle empty "updated" actions. * 05/04/94 (seiwald) - async multiprocess (-j) support * 06/01/94 (seiwald) - new 'actions existing' does existing sources * 12/20/94 (seiwald) - NOTIME renamed NOTFILE. * 01/19/95 (seiwald) - distinguish between CANTFIND/CANTMAKE targets. * 01/22/94 (seiwald) - pass per-target JAMSHELL down to execcmd(). * 02/28/95 (seiwald) - Handle empty "existing" actions. * 03/10/95 (seiwald) - Fancy counts. */# include "jam.h"# include "lists.h"# include "parse.h"# include "assert.h"# include "variable.h"# include "rules.h"# include "headers.h"# include "search.h"# include "newstr.h"# include "make.h"# include "command.h"# include "execcmd.h"# include "compile.h"# include "output.h"# include <stdlib.h>#if defined(sun) || defined(__sun)#include <unistd.h> /* for unlink */#endifstatic CMD *make1cmds( TARGET *t );static LIST *make1list( LIST *l, TARGETS *targets, int flags );static SETTINGS *make1settings( LIST *vars );static void make1bind( TARGET *t );/* Ugly static - it's too hard to carry it through the callbacks. */static struct { int failed; int skipped; int total; int made;} counts[1] ;/* * Target state - remove recursive calls by just keeping track of state target is in */typedef struct _state{ struct _state *prev; /* previous state on stack */ TARGET *t; /* current target */ TARGET *parent; /* parent argument necessary for make1a() */#define T_STATE_MAKE1A 0 /* make1a() should be called */#define T_STATE_MAKE1ATAIL 1 /* make1atail() should be called */#define T_STATE_MAKE1B 2 /* make1b() should be called */#define T_STATE_MAKE1C 3 /* make1c() should be called */#define T_STATE_MAKE1D 4 /* make1d() should be called */ int curstate; /* current state */ int status;} state;static void make1a( state *pState);static void make1atail(state *pState);static void make1b( state *pState );static void make1c( state *pState );static void make1d( state *pState );static void make_closure(void *closure, int status, timing_info*, char *, char *);typedef struct _stack{ state *stack;} stack;static stack state_stack = { NULL };static state *state_freelist = NULL;static state *alloc_state(){ if(state_freelist != NULL) { state *pState; pState = state_freelist; state_freelist = pState->prev; memset(pState, 0, sizeof(state)); return pState; } else { return (state *)BJAM_MALLOC(sizeof(state)); }}static void free_state(state *pState){ pState->prev = state_freelist; state_freelist = pState;}static void clear_state_freelist(){ while(state_freelist != NULL) { state *pState = state_freelist; state_freelist = state_freelist->prev; BJAM_FREE(pState); }}static state *current_state(stack *pStack){ return pStack->stack;}static void pop_state(stack *pStack){ state *pState; if(pStack->stack != NULL) { pState = pStack->stack->prev; free_state(pStack->stack); pStack->stack = pState; }}static state *push_state(stack *pStack, TARGET *t, TARGET *parent, int curstate){ state *pState; pState = alloc_state(); pState->t = t; pState->parent = parent; pState->prev = pStack->stack; pState->curstate = curstate; pStack->stack = pState; return pStack->stack;}/* pushes a stack onto another stack, effectively reversing the order */static void push_stack_on_stack(stack *pDest, stack *pSrc){ while(pSrc->stack != NULL) { state *pState; pState = pSrc->stack; pSrc->stack = pSrc->stack->prev; pState->prev = pDest->stack; pDest->stack = pState; }}/* * make1() - execute commands to update a TARGET and all its dependents */static int intr = 0;intmake1( TARGET *t ){ state *pState; memset( (char *)counts, 0, sizeof( *counts ) ); /* Recursively make the target and its dependents */ push_state(&state_stack, t, NULL, T_STATE_MAKE1A); do { while((pState = current_state(&state_stack)) != NULL) { if (intr) pop_state(&state_stack); switch(pState->curstate) { case T_STATE_MAKE1A: make1a(pState); break; case T_STATE_MAKE1ATAIL: make1atail(pState); break; case T_STATE_MAKE1B: make1b(pState); break; case T_STATE_MAKE1C: make1c(pState); break; case T_STATE_MAKE1D: make1d(pState); break; default: break; } } /* Wait for any outstanding commands to finish running. */ } while( execwait() ); clear_state_freelist(); /* Talk about it */ if( counts->failed ) printf( "...failed updating %d target%s...\n", counts->failed, counts->failed > 1 ? "s" : "" ); if( DEBUG_MAKE && counts->skipped ) printf( "...skipped %d target%s...\n", counts->skipped, counts->skipped > 1 ? "s" : "" ); if( DEBUG_MAKE && counts->made ) printf( "...updated %d target%s...\n", counts->made, counts->made > 1 ? "s" : "" ); return counts->total != counts->made;}/* * make1a() - recursively traverse target tree, calling make1b() */static voidmake1a( state *pState){ TARGET* t = pState->t; TARGETS *c; TARGETS *inc; /* If the parent is the first to try to build this target */ /* or this target is in the make1c() quagmire, arrange for the */ /* parent to be notified when this target is built. */ if( pState->parent ) switch( pState->t->progress ) { case T_MAKE_INIT: case T_MAKE_ACTIVE: case T_MAKE_RUNNING: pState->t->parents = targetentry( pState->t->parents, pState->parent ); pState->parent->asynccnt++; } if( pState->t->progress != T_MAKE_INIT ) { pop_state(&state_stack); return; } /* Asynccnt counts the dependents preventing this target from */ /* proceeding to make1b() for actual building. We start off with */ /* a count of 1 to prevent anything from happening until we can */ /* call all dependents. This 1 is accounted for when we call */ /* make1b() ourselves, below. */ pState->t->asynccnt = 1; /* Add header node that was created during building process. */ inc = 0; for (c = t->depends; c; c = c->next) { if (c->target->rescanned && c->target->includes) inc = targetentry(inc, c->target->includes); } t->depends = targetchain(t->depends, inc); /* against circular dependency. */ pState->t->progress = T_MAKE_ONSTACK; { stack temp_stack = { NULL }; for( c = t->depends; c && !intr; c = c->next ) push_state(&temp_stack, c->target, pState->t, T_STATE_MAKE1A); /* using stacks reverses the order of execution. Reverse it back */ push_stack_on_stack(&state_stack, &temp_stack); } pState->curstate = T_STATE_MAKE1ATAIL;}static void make1atail(state *pState){ pState->t->progress = T_MAKE_ACTIVE; /* Now that all dependents have bumped asynccnt, we now allow */ /* decrement our reference to asynccnt. */ pState->curstate = T_STATE_MAKE1B;}/* * make1b() - dependents of target built, now build target with make1c() */static voidmake1b( state *pState ){ TARGET *t = pState->t; TARGETS *c; TARGET *failed = 0; char* failed_name = "dependencies"; /* If any dependents are still outstanding, wait until they */ /* call make1b() to signal their completion. */ if( --(pState->t->asynccnt) ) { pop_state(&state_stack); return; } /* Try to aquire a semaphore. If it's locked, wait until the target that locked it is build and signals completition. */#ifdef OPT_SEMAPHORE if( t->semaphore && t->semaphore->asynccnt ) { /* Append 't' to the list of targets waiting on semaphore. */ t->semaphore->parents = targetentry( t->semaphore->parents, t ); t->asynccnt++; if( DEBUG_EXECCMD ) printf( "SEM: %s is busy, delaying launch of %s\n", t->semaphore->name, t->name); pop_state(&state_stack); return; }#endif /* Now ready to build target 't'... if dependents built ok. */ /* Collect status from dependents */ for( c = t->depends; c; c = c->next ) if( c->target->status > t->status && !( c->target->flags & T_FLAG_NOCARE ))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -