make.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1984-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* make target proof algorithm
*/
#include "make.h"
#define PREVIEW(r,x) do{if(r->preview>x->preview&&(r->scan&&r->scan==x->scan||!r->scan&&!((r->property|x->property)&P_virtual)))r->preview=x->preview;}while(0)
/*
* make scan prereqs
*/
static int
{
register Rule_t* s;
register Rule_t* u;
register List_t* p;
List_t* q;
int errors = 0;
Time_t t;
for (p = q; p; p = p->next)
{
s = p->rule;
}
if (tevent < t)
tevent = t;
return errors;
}
/*
* insert|append global g prereqs to r
*/
static void
{
register List_t* p;
register List_t* q;
register List_t* t;
register List_t* u;
Rule_t* x;
if (p = x->prereqs)
{
for (q = t = 0; p; p = p->next)
if (p->rule != r)
{
newlist(u);
if (t)
t->next = u;
else
q = u;
}
if (q)
{
t->next = 0;
dynamic(r);
}
}
}
/*
* undo alias of a -> r in preparation for update()
* return unaliased a
*/
static Rule_t*
{
if (a == r)
{
}
else
{
}
oldname(a);
return a;
}
/*
* prepare for update and execute action
* r is the target (possibly with explicit action)
* a is the implicit action rule
* arg for P_functional
*/
static int
{
register List_t* p;
register Rule_t* u;
int errors;
char* s;
errors = 0;
{
/*
* save explicit target generation for non-override runs
*/
if (r == a && r->time && (!(r->property & P_target) || !(r->property & (P_archive|P_command|P_make))))
{
r->dynamic |= D_triggered;
{
r->dynamic |= D_membertoo;
}
return errors;
}
}
{
u = p->rule;
{
u->dynamic |= D_membertoo;
}
a = u;
{
if (u->uname)
{
if (u->view)
{
u->view = 0;
}
oldname(u);
}
else if (u->view)
{
if (r == a)
u->view = 0;
{
u->view = 0;
{
if (state.expandview)
{
mount(u->name, sfstrbase(internal.tmp), FS3D_GET|FS3D_VIEW|FS3D_SIZE(sfstrsize(internal.tmp)), NiL);
}
else
}
}
else
{
int n;
/*
* this condition is definitely a bug
* this fix will have to do until the
* place that set u->uname=0 is found
*/
n = 0;
s = u->name;
while (s = strchr(s, '/'))
{
n++;
if (getrule(++s) == u)
{
u->view = 0;
break;
}
}
if (!s)
{
if (!n)
u->view = 0;
else if (!(u->property & P_dontcare))
}
}
}
}
}
{
r->dynamic |= D_triggered;
statetime(r, 1);
}
else
{
}
return errors;
}
/*
* top level make
* p temporarily or'd into r->property
* arg for P_functional
*
* r->status determines the status of each rule:
*
* NOTYET nothing done yet
* UPDATE rule in process of being updated
* MAKING rule action being executed
* TOUCH archive member to be touched
* EXISTS rule has already been made
* IGNORE rule make failed but ignore errors
* FAILED rule make failed
*/
void
{
Time_t t;
Flags_t o;
#if _HUH_2004_06_20
if ((p & (P_force|P_repeat)) == (P_force|P_repeat) && (r->property & (P_functional|P_make)) == P_make)
{
register Rule_t* a;
if (a->prereqs)
r = a;
}
#endif
o = r->property & p;
r->property |= p;
if (p & P_ignore)
r->property &= ~p;
r->property |= o;
}
/*
* intermediate level make
*/
int
{
register List_t* p;
Time_t t;
char* s;
char* v;
char* r3name;
int errors;
int explicit;
int must;
int otargetview;
int pop;
List_t* q;
trap();
errors = 0;
*ttarget = 0;
return errors;
{
return errors;
}
{
/*
* r->use rules modify the parent
*/
return errors;
{
/*
* check if the action changed
*/
{
}
}
#if DEBUG
#endif
/*
* append the prerequisites
*/
{
dynamic(r);
}
p = r->prereqs;
r->prereqs = q;
if (r->property & P_metarule)
for (; p; p = p->next)
{
{
if (tevent < t)
tevent = t;
}
{
}
{
if (tevent < t)
tevent = t;
}
}
/*
* propagate the attributes
*/
if (!(r->property & P_metarule))
{
}
return errors;
}
else if (r->semaphore)
/*
* check if rule has been or is in the process of being made
*/
error_info.indent++;
r3 = r;
for (;;)
{
{
{
r0 = 0;
{
{
{
makescan(r, &t);
if (tevent < t)
else
}
}
{
}
}
{
if (r->dynamic & D_aliaschanged)
else if (!(r->dynamic & D_triggered) && parent->scan == SCAN_IGNORE && (r0 || (r0 = staterule(RULE, r, NiL, 0))) && tevent < r0->time)
}
{
errors = 0;
}
error_info.indent--;
}
}
break;
{
break;
}
r = r1;
}
if ((r3 == r || (r->property & P_target) && !(r3->property & P_target)) && (!(r->dynamic & D_alias) || r3name == unbound(r)))
r3 = 0;
{
{
{
else
{
}
}
}
}
dynamic(r);
{
}
/*
* check for file changes since the last make
* the changes take a few forms:
*
* o the file modify time has changed since the
* last make
*
* o the file is from a different directory than
* the last make -- this is checked by using
* the modify time of the file which may fail
* (low probability) if the two source files
* in question have both the same (base) name
* and the same modify time -- this avoids
* saving the full bound names in the state file
*
* notice that this technique detects when an old source
* file is reinstated and forces updating just as if
* the file had been touched
*/
must = 0;
tevent = 0;
{
r0 = 0;
{
}
}
else
{
must = 0;
{
if (!state.intermediate && !r->time && r0->time && r0->event && (r0->dynamic & D_built) && !(parent->property & P_state) && (r2 = staterule(RULE, parent, NiL, 0)) && (r2->dynamic & D_built))
{
must = 1;
r->dynamic |= D_intermediate;
r->must++;
}
{
{
if (r->dynamic & D_aliaschanged)
else
{
else
}
must = 1;
r->must++;
}
{
s = r->uname;
r->uname = 0;
r->uname = s;
{
}
else
{
}
}
else
{
}
}
{
else if (!r->time)
else
}
else
}
}
/*
* check global insert|append pattern prerequisites
*/
/*
* check explicit prerequisites
*/
explicit = 0;
p = r->prereqs;
while (p)
{
r->dynamic |= D_hasscope;
{
r->dynamic |= D_hasscope;
if (tevent < t)
tevent = t;
}
{
r->dynamic |= D_hasafter;
}
r->dynamic |= D_hasbefore;
r->dynamic |= D_hassemaphore;
{
explicit = 1;
if (tevent < t)
tevent = t;
r->must++;
{
q = 0;
{
else if (q)
else
}
{
unsigned long u = 0;
unsigned long n = 0;
/*
* mutually dependent requirements can
* get us into a loop -- this limits
* the total number to half the square
* of the number of unique non-virtual
* prereqs
*/
{
n++;
{
u++;
}
}
if (u < 4)
u = 4;
if (n > (u * u) / 2)
{
else
for (q = p; q; q = q->next)
{
p = q;
message((-2, "require loop avoidance skips to %s [total=%lu uniqe=%lu]", q->next ? q->next->rule->name : "END", n, u));
break;
}
}
}
}
}
p = p->next;
}
/*
* check metarule prerequisites
*/
if (!errors && !(r->property & (P_attribute|P_functional|P_operator|P_state|P_virtual)) && ((r->property & P_implicit) || !r->action && !explicit))
{
#if DEBUG
if (!r->active)
{
}
#endif
if ((r2 = metaget(r, r->active, stem, &r4)) && !(state.questionable & 0x00100000) && ((state.questionable & 0x00200000) || !(r->property & P_implicit)) && strchr(unbound(r), '/') && !strchr(r4->name, '/'))
r2 = 0;
if (r2)
{
{
}
if (mam)
sfprintf(mam, "%smeta %s %s %s %s\n", state.mam.label, mamname(r), r4->name, state.mam.statix ? localview(r2) : r2->name, stem);
/*
* primary metarule match
*/
{
tevent = 0;
r->must = 0;
must = 0;
}
{
r->must++;
must = 1;
}
/*
* check the implicit source prerequisite
*/
{
if (tevent < t)
tevent = t;
r->must++;
{
r->dynamic |= D_hasafter;
}
{
r->dynamic |= D_hasbefore;
}
/*
* check joint metarule targets
*/
{
Rule_t* x;
int i;
{
x = makerule(s);
else
{
}
if (x != r)
{
error_info.indent++;
/*
* NOTE: some joint targets may not be generated
*/
else if (t)
{
}
else
if (!i)
{
reason((1, "joint metarule target %s [%s] changed [%s]", s, timestr(r4 ? r4->time : (Time_t)0), timestr(r5 ? r5->time : (Time_t)0)));
}
{
errors = 0;
}
error_info.indent--;
{
}
}
}
}
/*
* check the metarule
*/
if (!errors)
{
/*UNDENT*/
if (tevent < t)
tevent = t;
r->must++;
/*
* check the explicit action
*/
if ((r->property & P_implicit) && r->action && r->action == r->active->action && (!r0->action || !streq(r0->action, r->action)))
{
{
r->must++;
}
}
if ((state.questionable & 0x00000010) && r->view > r->preview && !(r->property & P_accept) && (!(r4 = staterule(PREREQS, r, NiL, 0)) || !r4->time))
{
r->must++;
}
/*
* check for update
*/
if (must || r->time < tevent && (!(r4 = staterule(PREREQS, r, NiL, 0)) || r4->time < tevent) || (r->property & P_force) || prereqchange(r, r->prereqs, r0, r0->prereqs) || state.force)
{
/*
* trigger the action
*/
if (r3)
{
if (r0)
}
}
/*INDENT*/
}
}
}
{
errors++;
}
}
else
r2 = 0;
/*
* determine the update rule if no metarule applied
*/
if (r2)
{
r1 = 0;
}
else if (r->action)
{
r1 = r;
if (r0)
{
{
{
r->must++;
}
}
}
}
else
{
r1 = 0;
if (r0)
{
{
}
/*
* at this point we accept the target as terminal source
*/
/*
* ... unless it doesn't exist
*/
r->time = 0;
}
}
if (r1)
{
if ((state.questionable & 0x00000010) && r->view > r->preview && !(r->property & P_accept) && (!(r4 = staterule(PREREQS, r, NiL, 0)) || !r4->time))
{
must = 1;
r->must++;
}
else if ((r->property & (P_attribute|P_functional|P_ignore|P_target)) == P_target && (state.force || r0 && !r0->time))
{
/*
* this takes care of non-file targets
*/
must = 1;
r->must++;
}
}
/*
* do the explicit action
*/
message((-2, "[%s] : [%s]%s%s%s", timestr(r->time), timestr(tevent), errors ? " ERRORS" : null, errors && state.unwind >= error_info.indent ? " ignored" : null, must ? " must" : null));
else
{
if (!errors && !(r->dynamic & D_triggered) && r->status == UPDATE && (r1 && must || r->time < tevent && (!(r4 = staterule(PREREQS, r, NiL, 0)) || r4->time < tevent) || !r->time || !r2 && ((r->property & P_force) || r0 && (r->prereqs || r->action) && prereqchange(r, r->prereqs, r0, r0->prereqs))))
{
if (r1)
{
if (r3)
{
if (r0)
}
}
else if (r->property & P_dontcare)
{
statetime(r, 0);
tevent = 0;
}
{
{
{
/*
* the attribute test handles rules in
* make object files that have since
* become attributes, e.g., .READONLY
*/
if ((r->property & P_attribute) || (r1 = associate(internal.dontcare_p, r, NiL, NiL)) && call(r1, r->name))
{
statetime(r, 0);
tevent = 0;
}
else
{
errors++;
error(state.keepgoing || state.unwind ? 1 : 3, "don't know how to make %s", sfstruse(internal.tmp));
}
}
}
{
statetime(r, 0);
if (!(r->property & P_terminal))
tevent = 0;
}
}
}
if (!(r->dynamic & D_triggered))
}
if (r->property & P_statevar)
{
if (state.targetview >= 0)
{
{
}
}
}
{
{
{
if (tevent < t)
tevent = t;
}
}
else
{
if (r->property & P_parameter)
{
{
#if _HUH_1992_09_30 /* this test is insufficient */
#endif
}
}
}
if (p->rule != r)
{
}
{
if (!r0)
}
}
errors++;
{
}
{
}
/*
* restore and return
*/
{
{
}
if (r1 != r)
{
}
}
{
errors = 0;
}
error_info.indent--;
{
t = r->time;
{
}
else if ((parent->property & P_archive) && (r->dynamic & D_regular) && (parent->dynamic & D_entries) && !(r->dynamic & D_member) && !(r->property & (P_archive|P_command|P_dontcare|P_ignore|P_state|P_virtual)))
t = CURTIME;
*ttarget = t;
}
return errors;
}
/*
* make explicit before prerequisites if r's action will trigger
*/
int
makebefore(register Rule_t* r)
{
register List_t* p;
register int errors;
Time_t t;
errors = 0;
{
r->dynamic &= ~D_hasbefore;
}
return errors;
}
/*
* make explicit after prerequisites if r's action triggered
*/
int
{
register List_t* p;
register int errors;
Time_t t;
errors = 0;
{
statetime(r, -1);
message((-2, "check explicit %safter `prerequisites'", (property & P_dontcare) ? "dontcare " : null));
}
return errors;
}