Beispiel #1
0
/*-
 *-----------------------------------------------------------------------
 * MakeFindChild  --
 *	Function used by Make_Run to find the pathname of a child
 *	that was already made.
 *
 * Input:
 *	gnp		the node to find
 *
 * Results:
 *	Always returns 0
 *
 * Side Effects:
 *	The path and mtime of the node and the cmgn of the parent are
 *	updated; the unmade children count of the parent is decremented.
 *-----------------------------------------------------------------------
 */
static int
MakeFindChild(void *gnp, void *pgnp)
{
    GNode          *gn = (GNode *)gnp;
    GNode          *pgn = (GNode *)pgnp;

    (void)Dir_MTime(gn, 0);
    Make_TimeStamp(pgn, gn);
    pgn->unmade--;

    return (0);
}
Beispiel #2
0
/*-
 *-----------------------------------------------------------------------
 * Make_Update  --
 *	Perform update on the parents of a node. Used by JobFinish once
 *	a node has been dealt with and by MakeStartJobs if it finds an
 *	up-to-date node.
 *
 * Input:
 *	cgn		the child node
 *
 * Results:
 *	Always returns 0
 *
 * Side Effects:
 *	The unmade field of pgn is decremented and pgn may be placed on
 *	the toBeMade queue if this field becomes 0.
 *
 * 	If the child was made, the parent's flag CHILDMADE field will be
 *	set true.
 *
 *	If the child is not up-to-date and still does not exist,
 *	set the FORCE flag on the parents.
 *
 *	If the child wasn't made, the cmgn field of the parent will be
 *	altered if the child's mtime is big enough.
 *
 *	Finally, if the child is the implied source for the parent, the
 *	parent's IMPSRC variable is set appropriately.
 *
 *-----------------------------------------------------------------------
 */
void
Make_Update(GNode *cgn)
{
    GNode 	*pgn;	/* the parent node */
    char  	*cname;	/* the child's name */
    LstNode	ln; 	/* Element in parents and iParents lists */
    time_t	mtime = -1;
    char	*p1;
    Lst		parents;
    GNode	*centurion;

    /* It is save to re-examine any nodes again */
    checked++;

    cname = Var_Value(TARGET, cgn, &p1);
    free(p1);

    if (DEBUG(MAKE))
	fprintf(debug_file, "Make_Update: %s%s\n", cgn->name, cgn->cohort_num);

    /*
     * If the child was actually made, see what its modification time is
     * now -- some rules won't actually update the file. If the file still
     * doesn't exist, make its mtime now.
     */
    if (cgn->made != UPTODATE) {
	mtime = Make_Recheck(cgn);
    }

    /*
     * If this is a `::' node, we must consult its first instance
     * which is where all parents are linked.
     */
    if ((centurion = cgn->centurion) != NULL) {
	if (!Lst_IsEmpty(cgn->parents))
		Punt("%s%s: cohort has parents", cgn->name, cgn->cohort_num);
	centurion->unmade_cohorts -= 1;
	if (centurion->unmade_cohorts < 0)
	    Error("Graph cycles through centurion %s", centurion->name);
    } else {
	centurion = cgn;
    }
    parents = centurion->parents;

    /* If this was a .ORDER node, schedule the RHS */
    Lst_ForEach(centurion->order_succ, MakeBuildParent, Lst_First(toBeMade));

    /* Now mark all the parents as having one less unmade child */
    if (Lst_Open(parents) == SUCCESS) {
	while ((ln = Lst_Next(parents)) != NULL) {
	    pgn = (GNode *)Lst_Datum(ln);
	    if (DEBUG(MAKE))
		fprintf(debug_file, "inspect parent %s%s: flags %x, "
			    "type %x, made %d, unmade %d ",
			pgn->name, pgn->cohort_num, pgn->flags,
			pgn->type, pgn->made, pgn->unmade-1);

	    if (!(pgn->flags & REMAKE)) {
		/* This parent isn't needed */
		if (DEBUG(MAKE))
		    fprintf(debug_file, "- not needed\n");
		continue;
	    }
	    if (mtime == 0 && !(cgn->type & OP_WAIT))
		pgn->flags |= FORCE;

	    /*
	     * If the parent has the .MADE attribute, its timestamp got
	     * updated to that of its newest child, and its unmake
	     * child count got set to zero in Make_ExpandUse().
	     * However other things might cause us to build one of its
	     * children - and so we mustn't do any processing here when
	     * the child build finishes.
	     */
	    if (pgn->type & OP_MADE) {
		if (DEBUG(MAKE))
		    fprintf(debug_file, "- .MADE\n");
		continue;
	    }

	    if ( ! (cgn->type & (OP_EXEC|OP_USE|OP_USEBEFORE))) {
		if (cgn->made == MADE)
		    pgn->flags |= CHILDMADE;
		(void)Make_TimeStamp(pgn, cgn);
	    }

	    /*
	     * A parent must wait for the completion of all instances
	     * of a `::' dependency.
	     */
	    if (centurion->unmade_cohorts != 0 || centurion->made < MADE) {
		if (DEBUG(MAKE))
		    fprintf(debug_file,
			    "- centurion made %d, %d unmade cohorts\n",
			    centurion->made, centurion->unmade_cohorts);
		continue;
	    }

	    /* One more child of this parent is now made */
	    pgn->unmade -= 1;
	    if (pgn->unmade < 0) {
		if (DEBUG(MAKE)) {
		    fprintf(debug_file, "Graph cycles through %s%s\n",
			pgn->name, pgn->cohort_num);
		    Targ_PrintGraph(2);
		}
		Error("Graph cycles through %s%s", pgn->name, pgn->cohort_num);
	    }

	    /* We must always rescan the parents of .WAIT and .ORDER nodes. */
	    if (pgn->unmade != 0 && !(centurion->type & OP_WAIT)
		    && !(centurion->flags & DONE_ORDER)) {
		if (DEBUG(MAKE))
		    fprintf(debug_file, "- unmade children\n");
		continue;
	    }
	    if (pgn->made != DEFERRED) {
		/*
		 * Either this parent is on a different branch of the tree,
		 * or it on the RHS of a .WAIT directive
		 * or it is already on the toBeMade list.
		 */
		if (DEBUG(MAKE))
		    fprintf(debug_file, "- not deferred\n");
		continue;
	    }
	    if (pgn->order_pred
		    && Lst_ForEach(pgn->order_pred, MakeCheckOrder, 0)) {
		/* A .ORDER rule stops us building this */
		continue;
	    }
	    if (DEBUG(MAKE)) {
		static int two = 2;
		fprintf(debug_file, "- %s%s made, schedule %s%s (made %d)\n",
			cgn->name, cgn->cohort_num,
			pgn->name, pgn->cohort_num, pgn->made);
		Targ_PrintNode(pgn, &two);
	    }
	    /* Ok, we can schedule the parent again */
	    pgn->made = REQUESTED;
	    (void)Lst_EnQueue(toBeMade, pgn);
	}
	Lst_Close(parents);
    }

    /*
     * Set the .PREFIX and .IMPSRC variables for all the implied parents
     * of this node.
     */
    if (Lst_Open(cgn->iParents) == SUCCESS) {
	char	*cpref = Var_Value(PREFIX, cgn, &p1);

	while ((ln = Lst_Next(cgn->iParents)) != NULL) {
	    pgn = (GNode *)Lst_Datum(ln);
	    if (pgn->flags & REMAKE) {
		Var_Set(IMPSRC, cname, pgn, 0);
		if (cpref != NULL)
		    Var_Set(PREFIX, cpref, pgn, 0);
	    }
	}
	free(p1);
	Lst_Close(cgn->iParents);
    }
}
Beispiel #3
0
/*
 * Input:
 *	pgn		the current parent
 *	cgn		the child we've just examined
 *
 */
static int
MakeTimeStamp(void *pgn, void *cgn)
{
    return Make_TimeStamp((GNode *)pgn, (GNode *)cgn);
}
Beispiel #4
0
/*-
 *-----------------------------------------------------------------------
 * Make_Update	--
 *	Perform update on the parents of a node. Used by JobFinish once
 *	a node has been dealt with and by MakeStartJobs if it finds an
 *	up-to-date node.
 *
 * Results:
 *	Always returns 0
 *
 * Side Effects:
 *	The unmade field of pgn is decremented and pgn may be placed on
 *	the toBeMade queue if this field becomes 0.
 *
 *	If the child was made, the parent's childMade field will be set true
 *	and its cmtime set to now.
 *
 *	If the child wasn't made, the cmtime field of the parent will be
 *	altered if the child's mtime is big enough.
 *
 *-----------------------------------------------------------------------
 */
void
Make_Update(GNode *cgn)	/* the child node */
{
	GNode	*pgn;	/* the parent node */
	LstNode	ln;	/* Element in parents list */

	/*
	 * If the child was actually made, see what its modification time is
	 * now -- some rules won't actually update the file. If the file still
	 * doesn't exist, make its mtime now.
	 */
	if (cgn->built_status != UPTODATE) {
		/*
		 * This is what Make does and it's actually a good thing, as it
		 * allows rules like
		 *
		 *	cmp -s y.tab.h parse.h || cp y.tab.h parse.h
		 *
		 * to function as intended. Unfortunately, thanks to the
		 * stateless nature of NFS, there are times when the
		 * modification time of a file created on a remote machine
		 * will not be modified before the local stat() implied by
		 * the Dir_MTime occurs, thus leading us to believe that the
		 * file is unchanged, wreaking havoc with files that depend
		 * on this one.
		 */
		if (noExecute || is_out_of_date(Dir_MTime(cgn)))
			ts_set_from_now(cgn->mtime);
		if (DEBUG(MAKE))
			printf("update time: %s\n", time_to_string(cgn->mtime));
	}

	/* SIB: this is where I should mark the build as finished */
	cgn->build_lock = false;
	for (ln = Lst_First(&cgn->parents); ln != NULL; ln = Lst_Adv(ln)) {
		pgn = (GNode *)Lst_Datum(ln);
		/* SIB: there should be a siblings loop there */
		pgn->unmade--;
		if (pgn->must_make) {
			if (DEBUG(MAKE))
				printf("%s--=%d ", 
				    pgn->name, pgn->unmade);

			if ( ! (cgn->type & (OP_EXEC|OP_USE))) {
				if (cgn->built_status == MADE) {
					pgn->childMade = true;
					if (is_strictly_before(pgn->cmtime,
					    cgn->mtime))
						pgn->cmtime = cgn->mtime;
				} else {
					(void)Make_TimeStamp(pgn, cgn);
				}
			}
			if (pgn->unmade == 0) {
				/*
				 * Queue the node up -- any unmade
				 * predecessors will be dealt with in
				 * MakeStartJobs.
				 */
				if (DEBUG(MAKE))
					printf("QUEUING ");
				Array_Push(&toBeMade, pgn);
			} else if (pgn->unmade < 0) {
				Error("Child %s discovered graph cycles through %s", cgn->name, pgn->name);
			}
		}
	}
	if (DEBUG(MAKE))
		printf("\n");
	requeue_successors(cgn);
}
Beispiel #5
0
/*-
 *-----------------------------------------------------------------------
 * Compat_Make --
 *	Make a target.
 *
 * Input:
 *	gnp		The node to make
 *	pgnp		Parent to abort if necessary
 *
 * Results:
 *	0
 *
 * Side Effects:
 *	If an error is detected and not being ignored, the process exits.
 *
 *-----------------------------------------------------------------------
 */
int
Compat_Make(void *gnp, void *pgnp)
{
    GNode *gn = (GNode *)gnp;
    GNode *pgn = (GNode *)pgnp;

    if (!meta[0])		/* we came here from jobs */
	Compat_Init();
    if (gn->made == UNMADE && (gn == pgn || (pgn->type & OP_MADE) == 0)) {
	/*
	 * First mark ourselves to be made, then apply whatever transformations
	 * the suffix module thinks are necessary. Once that's done, we can
	 * descend and make all our children. If any of them has an error
	 * but the -k flag was given, our 'make' field will be set FALSE again.
	 * This is our signal to not attempt to do anything but abort our
	 * parent as well.
	 */
	gn->flags |= REMAKE;
	gn->made = BEINGMADE;
	if ((gn->type & OP_MADE) == 0)
	    Suff_FindDeps(gn);
	Lst_ForEach(gn->children, Compat_Make, gn);
	if ((gn->flags & REMAKE) == 0) {
	    gn->made = ABORTED;
	    pgn->flags &= ~REMAKE;
	    goto cohorts;
	}

	if (Lst_Member(gn->iParents, pgn) != NULL) {
	    char *p1;
	    Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0);
	    if (p1)
		free(p1);
	}

	/*
	 * All the children were made ok. Now cmgn->mtime contains the
	 * modification time of the newest child, we need to find out if we
	 * exist and when we were modified last. The criteria for datedness
	 * are defined by the Make_OODate function.
	 */
	if (DEBUG(MAKE)) {
	    fprintf(debug_file, "Examining %s...", gn->name);
	}
	if (! Make_OODate(gn)) {
	    gn->made = UPTODATE;
	    if (DEBUG(MAKE)) {
		fprintf(debug_file, "up-to-date.\n");
	    }
	    goto cohorts;
	} else if (DEBUG(MAKE)) {
	    fprintf(debug_file, "out-of-date.\n");
	}

	/*
	 * If the user is just seeing if something is out-of-date, exit now
	 * to tell him/her "yes".
	 */
	if (queryFlag) {
	    exit(1);
	}

	/*
	 * We need to be re-made. We also have to make sure we've got a $?
	 * variable. To be nice, we also define the $> variable using
	 * Make_DoAllVar().
	 */
	Make_DoAllVar(gn);

	/*
	 * Alter our type to tell if errors should be ignored or things
	 * should not be printed so CompatRunCommand knows what to do.
	 */
	if (Targ_Ignore(gn)) {
	    gn->type |= OP_IGNORE;
	}
	if (Targ_Silent(gn)) {
	    gn->type |= OP_SILENT;
	}

	if (Job_CheckCommands(gn, Fatal)) {
	    /*
	     * Our commands are ok, but we still have to worry about the -t
	     * flag...
	     */
	    if (!touchFlag || (gn->type & OP_MAKE)) {
		curTarg = gn;
#ifdef USE_META
		if (useMeta && !NoExecute(gn)) {
		    meta_job_start(NULL, gn);
		}
#endif
		Lst_ForEach(gn->commands, CompatRunCommand, gn);
		curTarg = NULL;
	    } else {
		Job_Touch(gn, gn->type & OP_SILENT);
	    }
	} else {
	    gn->made = ERROR;
	}
#ifdef USE_META
	if (useMeta && !NoExecute(gn)) {
	    meta_job_finish(NULL);
	}
#endif

	if (gn->made != ERROR) {
	    /*
	     * If the node was made successfully, mark it so, update
	     * its modification time and timestamp all its parents. Note
	     * that for .ZEROTIME targets, the timestamping isn't done.
	     * This is to keep its state from affecting that of its parent.
	     */
	    gn->made = MADE;
	    pgn->flags |= Make_Recheck(gn) == 0 ? FORCE : 0;
	    if (!(gn->type & OP_EXEC)) {
		pgn->flags |= CHILDMADE;
		Make_TimeStamp(pgn, gn);
	    }
	} else if (keepgoing) {
	    pgn->flags &= ~REMAKE;
	} else {
	    PrintOnError(gn, "\n\nStop.");
	    exit(1);
	}
    } else if (gn->made == ERROR) {
	/*
	 * Already had an error when making this beastie. Tell the parent
	 * to abort.
	 */
	pgn->flags &= ~REMAKE;
    } else {
	if (Lst_Member(gn->iParents, pgn) != NULL) {
	    char *p1;
	    Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), pgn, 0);
	    if (p1)
		free(p1);
	}
	switch(gn->made) {
	    case BEINGMADE:
		Error("Graph cycles through %s", gn->name);
		gn->made = ERROR;
		pgn->flags &= ~REMAKE;
		break;
	    case MADE:
		if ((gn->type & OP_EXEC) == 0) {
		    pgn->flags |= CHILDMADE;
		    Make_TimeStamp(pgn, gn);
		}
		break;
	    case UPTODATE:
		if ((gn->type & OP_EXEC) == 0) {
		    Make_TimeStamp(pgn, gn);
		}
		break;
	    default:
		break;
	}
    }

cohorts:
    Lst_ForEach(gn->cohorts, Compat_Make, pgnp);
    return (0);
}
Beispiel #6
0
/* Wrapper to call Make_TimeStamp from a forEach loop.	*/
static void
MakeTimeStamp(void *parent, void *child)
{
    Make_TimeStamp((GNode *)parent, (GNode *)child);
}
Beispiel #7
0
/*-
 *-----------------------------------------------------------------------
 * CompatMake --
 *	Make a target.
 *
 * Side Effects:
 *	If an error is detected and not being ignored, the process exits.
 *-----------------------------------------------------------------------
 */
static void
CompatMake(void *gnp,	/* The node to make */
    void *pgnp)		/* Parent to abort if necessary */
{
	GNode *gn = (GNode *)gnp;
	GNode *pgn = (GNode *)pgnp;

	GNode *sib;
	bool cmdsOk;

	if (DEBUG(MAKE))
		printf("CompatMake(%s, %s)\n", pgn ? pgn->name : "NULL",
		    gn->name);

	/* XXX some loops are not loops, people write dependencies
	 * between siblings to make sure they get built.
	 * Also, we don't recognize direct loops.
	 */
	if (gn == pgn)
		return;
	/* handle .USE right away */
	if (gn->type & OP_USE) {
		Make_HandleUse(gn, pgn);
		return;
	}

	look_harder_for_target(gn);

	if (pgn != NULL && is_sibling(gn, pgn))
		return;

	if (pgn == NULL)
		pgn = gn;

	if (pgn->type & OP_MADE) {
		sib = gn;
		do {
			sib->mtime = gn->mtime;
			sib->built_status = UPTODATE;
			sib = sib->sibling;
		} while (sib != gn);
	}

	switch(gn->built_status) {
	case UNKNOWN: 
		/* First mark ourselves to be made, then apply whatever
		 * transformations the suffix module thinks are necessary.
		 * Once that's done, we can descend and make all our children.
		 * If any of them has an error but the -k flag was given,
		 * our 'must_make' field will be set false again.  This is our
		 * signal to not attempt to do anything but abort our
		 * parent as well.  */
		gn->must_make = true;
		gn->built_status = BEINGMADE;
		/* note that, in case we have siblings, we only check all
		 * children for all siblings, but we don't try to apply
		 * any other rule.
		 */
		sib = gn;
		do {
			Suff_FindDeps(sib);
			Lst_ForEach(&sib->children, CompatMake, gn);
			sib = sib->sibling;
		} while (sib != gn);

		if (!gn->must_make) {
			Error("Build for %s aborted", gn->name);
			gn->built_status = ABORTED;
			pgn->must_make = false;
			return;
		}

		/* All the children were made ok. Now youngest points to
		 * the newest child, we need to find out
		 * if we exist and when we were modified last. The criteria
		 * for datedness are defined by the Make_OODate function.  */
		if (DEBUG(MAKE))
			printf("Examining %s...", gn->name);
		if (!Make_OODate(gn)) {
			gn->built_status = UPTODATE;
			if (DEBUG(MAKE))
				printf("up-to-date.\n");
			return;
		} else if (DEBUG(MAKE))
			printf("out-of-date.\n");

		/* If the user is just seeing if something is out-of-date,
		 * exit now to tell him/her "yes".  */
		if (queryFlag)
			exit(1);

		/* normally, we run the job, but if we can't find any
		 * commands, we defer to siblings instead.
		 */
		sib = gn;
		do {
			/* We need to be re-made. We also have to make sure
			 * we've got a $?  variable. To be nice, we also define
			 * the $> variable using Make_DoAllVar().
			 */
			Make_DoAllVar(sib);
			cmdsOk = node_find_valid_commands(sib);
			if (cmdsOk || (gn->type & OP_OPTIONAL))
				break;

			sib = sib->sibling;
		} while (sib != gn);

		if (cmdsOk) {
			/* Our commands are ok, but we still have to worry
			 * about the -t flag...	*/
			if (!touchFlag)
				run_gnode(sib);
			else {
				Job_Touch(sib);
				if (gn != sib)
					Job_Touch(gn);
			}
		} else {
			node_failure(gn);
			sib->built_status = ERROR;
		}

		/* copy over what we just did */
		gn->built_status = sib->built_status;

		if (gn->built_status != ERROR) {
			/* If the node was made successfully, mark it so,
			 * update its modification time and timestamp all
			 * its parents.
			 * This is to keep its state from affecting that of
			 * its parent.  */
			gn->built_status = MADE;
			sib->built_status = MADE;
			/* This is what Make does and it's actually a good
			 * thing, as it allows rules like
			 *
			 *	cmp -s y.tab.h parse.h || cp y.tab.h parse.h
			 *
			 * to function as intended. Unfortunately, thanks to
			 * the stateless nature of NFS (and the speed of
			 * this program), there are times when the
			 * modification time of a file created on a remote
			 * machine will not be modified before the stat()
			 * implied by the Dir_MTime occurs, thus leading us
			 * to believe that the file is unchanged, wreaking
			 * havoc with files that depend on this one.
			 */
			if (noExecute || is_out_of_date(Dir_MTime(gn)))
				clock_gettime(CLOCK_REALTIME, &gn->mtime);
			if (is_strictly_before(gn->mtime, gn->youngest->mtime))
				gn->mtime = gn->youngest->mtime;
			if (sib != gn) {
				if (noExecute || is_out_of_date(Dir_MTime(sib)))
					clock_gettime(CLOCK_REALTIME, 
					    &sib->mtime);
				if (is_strictly_before(sib->mtime, 
				    sib->youngest->mtime))
					sib->mtime = sib->youngest->mtime;
			}
			if (DEBUG(MAKE))
				printf("update time: %s\n",
				    time_to_string(&gn->mtime));
			if (!(gn->type & OP_EXEC)) {
				pgn->childMade = true;
				Make_TimeStamp(pgn, gn);
			}
		} else if (keepgoing)
			pgn->must_make = false;
		else {
			print_errors();
			exit(1);
		}
		break;
	case ERROR:
		/* Already had an error when making this beastie. Tell the
		 * parent to abort.  */
		pgn->must_make = false;
		break;
	case BEINGMADE:
		Error("Graph cycles through %s", gn->name);
		gn->built_status = ERROR;
		pgn->must_make = false;
		break;
	case MADE:
		if ((gn->type & OP_EXEC) == 0) {
			pgn->childMade = true;
			Make_TimeStamp(pgn, gn);
		}
		break;
	case UPTODATE:
		if ((gn->type & OP_EXEC) == 0)
			Make_TimeStamp(pgn, gn);
		break;
	default:
		break;
	}
}