Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#include        "mk.h"

int runerrs;

void
mk(char *target)
{
        Node *node;
        int did = 0;

        nproc();                /* it can be updated dynamically */
        nrep();                 /* it can be updated dynamically */
        runerrs = 0;
        node = graph(target);
        if(DEBUG(D_GRAPH)){
                dumpn("new target\n", node);
                Bflush(&bout);
        }
        clrmade(node);
        while(node->flags&NOTMADE){
                if(work(node, (Node *)0, (Arc *)0))
                        did = 1;        /* found something to do */
                else {
                        if(waitup(1, (int *)0) > 0){
                                if(node->flags&(NOTMADE|BEINGMADE)){
                                        assert(/*must be run errors*/ runerrs);
                                        break;  /* nothing more waiting */
                                }
                        }
                }
        }
        if(node->flags&BEINGMADE)
                waitup(-1, (int *)0);
        while(jobs)
                waitup(-2, (int *)0);
        assert(/*target didnt get done*/ runerrs || (node->flags&MADE));
        if(did == 0)
                Bprint(&bout, "mk: '%s' is up to date\n", node->name);
}

void
clrmade(Node *n)
{
        Arc *a;

        n->flags &= ~(CANPRETEND|PRETENDING);
        if(strchr(n->name, '(') ==0 || n->time)
                n->flags |= CANPRETEND;
        MADESET(n, NOTMADE);
        for(a = n->prereqs; a; a = a->next)
                if(a->n)
                        clrmade(a->n);
}

static void
unpretend(Node *n)
{
        MADESET(n, NOTMADE);
        n->flags &= ~(CANPRETEND|PRETENDING);
        n->time = 0;
}

int
work(Node *node, Node *p, Arc *parc)
{
        Arc *a, *ra;
        int weoutofdate;
        int ready;
        int did = 0;
        char cwd[256];

        /*print("work(%s) flags=0x%x time=%lud\n", node->name, node->flags, node->time);/**/
        if(node->flags&BEINGMADE)
                return(did);
        if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p, parc, 0)){
                if(explain)
                        fprint(1, "unpretending %s(%lud) because %s is out of date(%lud)\n",
                                node->name, node->time, p->name, p->time);
                unpretend(node);
        }
        /*
                have a look if we are pretending in case
                someone has been unpretended out from underneath us
        */
        if(node->flags&MADE){
                if(node->flags&PRETENDING){
                        node->time = 0;
                }else
                        return(did);
        }
        /* consider no prerequisite case */
        if(node->prereqs == 0){
                if(node->time == 0){
                        if(getwd(cwd, sizeof cwd))
                                fprint(2, "mk: don't know how to make '%s' in directory %s\n", node->name, cwd);
                        else
                                fprint(2, "mk: don't know how to make '%s'\n", node->name);
                        if(kflag){
                                node->flags |= BEINGMADE;
                                runerrs++;
                        } else
                                Exit();
                } else
                        MADESET(node, MADE);
                return(did);
        }
        /*
                now see if we are out of date or what
        */
        ready = 1;
        weoutofdate = aflag;
        ra = 0;
        for(a = node->prereqs; a; a = a->next)
                if(a->n){
                        did = work(a->n, node, a) || did;
                        if(a->n->flags&(NOTMADE|BEINGMADE))
                                ready = 0;
                        if(outofdate(node, a, 0)){
                                weoutofdate = 1;
                                if((ra == 0) || (ra->n == 0)
                                                || (ra->n->time < a->n->time))
                                        ra = a;
                        }
                } else {
                        if(node->time == 0){
                                if(ra == 0)
                                        ra = a;
                                weoutofdate = 1;
                        }
                }
        if(ready == 0)  /* can't do anything now */
                return(did);
        if(weoutofdate == 0){
                MADESET(node, MADE);
                return(did);
        }
        /*
                can we pretend to be made?
        */
        if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPRETEND))
                        && p && ra->n && !outofdate(p, ra, 0)){
                node->flags &= ~CANPRETEND;
                MADESET(node, MADE);
                if(explain && ((node->flags&PRETENDING) == 0))
                        fprint(1, "pretending %s has time %lud\n", node->name, node->time);
                node->flags |= PRETENDING;
                return(did);
        }
        /*
                node is out of date and we REALLY do have to do something.
                quickly rescan for pretenders
        */
        for(a = node->prereqs; a; a = a->next)
                if(a->n && (a->n->flags&PRETENDING)){
                        if(explain)
                                Bprint(&bout, "unpretending %s because of %s because of %s\n",
                                a->n->name, node->name, ra->n? ra->n->name : "rule with no prerequisites");

                        unpretend(a->n);
                        did = work(a->n, node, a) || did;
                        ready = 0;
                }
        if(ready == 0)  /* try later unless nothing has happened for -k's sake */
                return(did || work(node, p, parc));
        did = dorecipe(node) || did;
        return(did);
}

void
update(int fake, Node *node)
{
        Arc *a;

        MADESET(node, fake? BEINGMADE : MADE);
        if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){
                node->time = timeof(node->name, 1);
                node->flags &= ~(CANPRETEND|PRETENDING);
                for(a = node->prereqs; a; a = a->next)
                        if(a->prog)
                                outofdate(node, a, 1);
        } else {
                node->time = 1;
                for(a = node->prereqs; a; a = a->next)
                        if(a->n && outofdate(node, a, 1))
                                node->time = a->n->time;
        }
/*      print("----node %s time=%lud flags=0x%x\n", node->name, node->time, node->flags);/**/
}

static
pcmp(char *prog, char *p, char *q)
{
        char buf[3*NAMEBLOCK];
        int pid;

        Bflush(&bout);
        snprint(buf, sizeof buf, "%s '%s' '%s'\n", prog, p, q);
        pid = pipecmd(buf, 0, 0);
        while(waitup(-3, &pid) >= 0)
                ;
        return(pid? 2:1);
}

int
outofdate(Node *node, Arc *arc, int eval)
{
        char buf[3*NAMEBLOCK], *str;
        Symtab *sym;
        int ret;

        str = 0;
        if(arc->prog){
                snprint(buf, sizeof buf, "%s%c%s", node->name, 0377,
                        arc->n->name);
                sym = symlook(buf, S_OUTOFDATE, 0);
                if(sym == 0 || eval){
                        if(sym == 0)
                                str = strdup(buf);
                        ret = pcmp(arc->prog, node->name, arc->n->name);
                        if(sym)
                                sym->u.value = ret;
                        else
                                symlook(str, S_OUTOFDATE, (void *)ret);
                } else
                        ret = sym->u.value;
                return(ret-1);
        } else if(strchr(arc->n->name, '(') && arc->n->time == 0)  /* missing archive member */
                return 1;
        else
                /*
                 * Treat equal times as out-of-date.
                 * It's a race, and the safer option is to do
                 * extra building rather than not enough.
                 */
                return node->time <= arc->n->time;
}