version 1.40, 2007/09/17 08:53:59 |
version 1.41, 2007/09/17 09:28:36 |
|
|
* |
* |
* cmp -s y.tab.h parse.h || cp y.tab.h parse.h |
* cmp -s y.tab.h parse.h || cp y.tab.h parse.h |
* |
* |
* to function as intended. Unfortunately, thanks to the |
* to function as intended. Unfortunately, thanks to the |
* stateless nature of NFS, there are times when the |
* stateless nature of NFS, there are times when the |
* modification time of a file created on a remote machine |
* modification time of a file created on a remote machine |
* will not be modified before the local stat() implied by |
* will not be modified before the local stat() implied by |
* the Dir_MTime occurs, thus leading us to believe that the |
* the Dir_MTime occurs, thus leading us to believe that the |
* file is unchanged, wreaking havoc with files that depend |
* file is unchanged, wreaking havoc with files that depend |
* on this one. |
* on this one. |
* XXX If we are saving commands pretend that |
* XXX If we are saving commands pretend that |
* the target is made now. Otherwise archives with ... rules |
* the target is made now. Otherwise archives with ... rules |
|
|
if ( ! (cgn->type & (OP_EXEC|OP_USE))) { |
if ( ! (cgn->type & (OP_EXEC|OP_USE))) { |
if (cgn->made == MADE) { |
if (cgn->made == MADE) { |
pgn->childMade = true; |
pgn->childMade = true; |
if (is_strictly_before(pgn->cmtime, |
if (is_strictly_before(pgn->cmtime, |
cgn->mtime)) |
cgn->mtime)) |
pgn->cmtime = cgn->mtime; |
pgn->cmtime = cgn->mtime; |
} else { |
} else { |
|
|
} |
} |
if (pgn->unmade == 0) { |
if (pgn->unmade == 0) { |
/* |
/* |
* Queue the node up -- any unmade |
* Queue the node up -- any unmade |
* predecessors will be dealt with in |
* predecessors will be dealt with in |
* MakeStartJobs. |
* MakeStartJobs. |
*/ |
*/ |
Lst_EnQueue(&toBeMade, pgn); |
Lst_EnQueue(&toBeMade, pgn); |
|
|
} |
} |
} |
} |
} |
} |
/* Deal with successor nodes. If any is marked for making and has an |
/* Deal with successor nodes. If any is marked for making and has an |
* unmade count of 0, has not been made and isn't in the examination |
* unmade count of 0, has not been made and isn't in the examination |
* queue, it means we need to place it in the queue as it restrained |
* queue, it means we need to place it in the queue as it restrained |
* itself before. */ |
* itself before. */ |
for (ln = Lst_First(&cgn->successors); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(&cgn->successors); ln != NULL; ln = Lst_Adv(ln)) { |
GNode *succ = (GNode *)Lst_Datum(ln); |
GNode *succ = (GNode *)Lst_Datum(ln); |
|
|
if (!Lst_IsEmpty(&gn->preds)) { |
if (!Lst_IsEmpty(&gn->preds)) { |
LstNode ln; |
LstNode ln; |
|
|
for (ln = Lst_First(&gn->preds); ln != NULL; |
for (ln = Lst_First(&gn->preds); ln != NULL; |
ln = Lst_Adv(ln)){ |
ln = Lst_Adv(ln)){ |
GNode *pgn = (GNode *)Lst_Datum(ln); |
GNode *pgn = (GNode *)Lst_Datum(ln); |
|
|
|
|
} |
} |
} |
} |
/* |
/* |
* If ln isn't NULL, there's a predecessor as yet |
* If ln isn't NULL, there's a predecessor as yet |
* unmade, so we just drop this node on the floor. When |
* unmade, so we just drop this node on the floor. When |
* the node in question has been made, it will notice |
* the node in question has been made, it will notice |
* this node as being ready to make but as yet unmade |
* this node as being ready to make but as yet unmade |
* and will place the node on the queue. |
* and will place the node on the queue. |
*/ |
*/ |
if (ln != NULL) |
if (ln != NULL) |
|
|
gn->made = UPTODATE; |
gn->made = UPTODATE; |
if (gn->type & OP_JOIN) { |
if (gn->type & OP_JOIN) { |
/* |
/* |
* Even for an up-to-date .JOIN node, we need it |
* Even for an up-to-date .JOIN node, we need it |
* to have its context variables so references |
* to have its context variables so references |
* to it get the correct value for .TARGET when |
* to it get the correct value for .TARGET when |
* building up the context variables of its |
* building up the context variables of its |
* parent(s)... |
* parent(s)... |
*/ |
*/ |
Make_DoAllVar(gn); |
Make_DoAllVar(gn); |
|
|
if (cycle) { |
if (cycle) { |
bool t = true; |
bool t = true; |
/* |
/* |
* If printing cycles and came to one that has unmade |
* If printing cycles and came to one that has unmade |
* children, print out the cycle by recursing on its |
* children, print out the cycle by recursing on its |
* children. Note a cycle like: |
* children. Note a cycle like: |
* a : b |
* a : b |
* b : c |
* b : c |
* c : b |
* c : b |
* will cause this to erroneously complain about a |
* will cause this to erroneously complain about a |
* being in the cycle, but this is a good approximation. |
* being in the cycle, but this is a good approximation. |
*/ |
*/ |
if (gn->made == CYCLE) { |
if (gn->made == CYCLE) { |
|
|
Lst_ForEach(&gn->children, MakePrintStatus, &t); |
Lst_ForEach(&gn->children, MakePrintStatus, &t); |
} |
} |
} else { |
} else { |
printf("`%s' not remade because of errors.\n", |
printf("`%s' not remade because of errors.\n", |
gn->name); |
gn->name); |
} |
} |
} |
} |
|
|
numNodes = 0; |
numNodes = 0; |
|
|
/* |
/* |
* Make an initial downward pass over the graph, marking nodes to be |
* Make an initial downward pass over the graph, marking nodes to be |
* made as we go down. We call Suff_FindDeps to find where a node is and |
* made as we go down. We call Suff_FindDeps to find where a node is and |
* to get some children for it if it has none and also has no commands. |
* to get some children for it if it has none and also has no commands. |
* If the node is a leaf, we stick it on the toBeMade queue to |
* If the node is a leaf, we stick it on the toBeMade queue to |
|
|
numNodes++; |
numNodes++; |
|
|
/* |
/* |
* Apply any .USE rules before looking for implicit |
* Apply any .USE rules before looking for implicit |
* dependencies to make sure everything that should have |
* dependencies to make sure everything that should have |
* commands has commands ... |
* commands has commands ... |
*/ |
*/ |
|
|
Suff_FindDeps(gn); |
Suff_FindDeps(gn); |
|
|
if (gn->unmade != 0) |
if (gn->unmade != 0) |
Lst_ForEach(&gn->children, MakeAddChild, |
Lst_ForEach(&gn->children, MakeAddChild, |
&examine); |
&examine); |
else |
else |
Lst_EnQueue(&toBeMade, gn); |
Lst_EnQueue(&toBeMade, gn); |
|
|
|
|
if (queryFlag) { |
if (queryFlag) { |
/* |
/* |
* We wouldn't do any work unless we could start some jobs in |
* We wouldn't do any work unless we could start some jobs in |
* the next loop... (we won't actually start any, of course, |
* the next loop... (we won't actually start any, of course, |
* this is just to see if any of the targets was out of date) |
* this is just to see if any of the targets was out of date) |
*/ |
*/ |
return MakeStartJobs(); |
return MakeStartJobs(); |
|
|
/* |
/* |
* Initialization. At the moment, no jobs are running and until |
* Initialization. At the moment, no jobs are running and until |
* some get started, nothing will happen since the remaining |
* some get started, nothing will happen since the remaining |
* upward traversal of the graph is performed by the routines |
* upward traversal of the graph is performed by the routines |
* in job.c upon the finishing of a job. So we fill the Job |
* in job.c upon the finishing of a job. So we fill the Job |
* table as much as we can before going into our loop. |
* table as much as we can before going into our loop. |
*/ |
*/ |
(void)MakeStartJobs(); |
(void)MakeStartJobs(); |
|
|
* much as possible. Because the job table is kept as full as possible, |
* much as possible. Because the job table is kept as full as possible, |
* the only time when it will be empty is when all the jobs which need |
* the only time when it will be empty is when all the jobs which need |
* running have been run, so that is the end condition of this loop. |
* running have been run, so that is the end condition of this loop. |
* Note that the Job module will exit if there were any errors unless |
* Note that the Job module will exit if there were any errors unless |
* the keepgoing flag was given. |
* the keepgoing flag was given. |
*/ |
*/ |
while (!Job_Empty()) { |
while (!Job_Empty()) { |