⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 make.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	 * I have decided it is better to make too much than to make too	 * little, so this stuff is commented out unless you're sure it's ok.	 * -- ardeb 1/12/88	 */	/*	 * Christos, 4/9/92: If we are  saving commands pretend that	 * the target is made now. Otherwise archives with ... rules	 * don't work!	 */	if (noExecute || (cgn->type & OP_SAVE_CMDS) || Dir_MTime(cgn) == 0) {	    cgn->mtime = now;	}	if (DEBUG(MAKE)) {	    printf("update time: %s\n", Targ_FmtTime(cgn->mtime));	}#endif    }        if (Lst_Open (cgn->parents) == SUCCESS) {	while ((ln = Lst_Next (cgn->parents)) != NILLNODE) {	    pgn = (GNode *)Lst_Datum (ln);	    if (pgn->make) {		pgn->unmade -= 1;		if ( ! (cgn->type & (OP_EXEC|OP_USE))) {		    if (cgn->made == MADE) {			pgn->childMade = TRUE;			if (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.		     */		    (void)Lst_EnQueue (toBeMade, (ClientData)pgn);		} else if (pgn->unmade < 0) {		    Error ("Graph cycles through %s", pgn->name);		}	    }	}	Lst_Close (cgn->parents);    }    /*     * 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 queue,     * it means we need to place it in the queue as it restrained itself     * before.     */    for (ln = Lst_First(cgn->successors); ln != NILLNODE; ln = Lst_Succ(ln)) {	GNode	*succ = (GNode *)Lst_Datum(ln);	if (succ->make && succ->unmade == 0 && succ->made == UNMADE &&	    Lst_Member(toBeMade, (ClientData)succ) == NILLNODE)	{	    (void)Lst_EnQueue(toBeMade, (ClientData)succ);	}    }        /*     * 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);	while ((ln = Lst_Next (cgn->iParents)) != NILLNODE) {	    pgn = (GNode *)Lst_Datum (ln);	    if (pgn->make) {		Var_Set (IMPSRC, cname, pgn);		Var_Set (PREFIX, cpref, pgn);	    }	}	Lst_Close (cgn->iParents);    }}/*- *----------------------------------------------------------------------- * MakeAddAllSrc -- *	Add a child's name to the ALLSRC and OODATE variables of the given *	node. Called from Make_DoAllVar via Lst_ForEach. A child is added only *	if it has not been given the .EXEC, .USE or .INVISIBLE attributes. *	.EXEC and .USE children are very rarely going to be files, so... *	A child is added to the OODATE variable if its modification time is *	later than that of its parent, as defined by Make, except if the *	parent is a .JOIN node. In that case, it is only added to the OODATE *	variable if it was actually made (since .JOIN nodes don't have *	modification times, the comparison is rather unfair...).. * * Results: *	Always returns 0 * * Side Effects: *	The ALLSRC variable for the given node is extended. *----------------------------------------------------------------------- */static intMakeAddAllSrc (cgn, pgn)    GNode	*cgn;	/* The child to add */    GNode	*pgn;	/* The parent to whose ALLSRC variable it should be */			/* added */{    if ((cgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) {	register char *child;	child = Var_Value(TARGET, cgn);	Var_Append (ALLSRC, child, pgn);	if (pgn->type & OP_JOIN) {	    if (cgn->made == MADE) {		Var_Append(OODATE, child, pgn);	    }	} else if ((pgn->mtime < cgn->mtime) ||		   (cgn->mtime >= now && cgn->made == MADE))	{	    /*	     * It goes in the OODATE variable if the parent is younger than the	     * child or if the child has been modified more recently than	     * the start of the make. This is to keep pmake from getting	     * confused if something else updates the parent after the	     * make starts (shouldn't happen, I know, but sometimes it	     * does). In such a case, if we've updated the kid, the parent	     * is likely to have a modification time later than that of	     * the kid and anything that relies on the OODATE variable will	     * be hosed.	     *	     * XXX: This will cause all made children to go in the OODATE	     * variable, even if they're not touched, if RECHECK isn't defined,	     * since cgn->mtime is set to now in Make_Update. According to	     * some people, this is good...	     */	    Var_Append(OODATE, child, pgn);	}    }    return (0);}/*- *----------------------------------------------------------------------- * Make_DoAllVar -- *	Set up the ALLSRC and OODATE variables. Sad to say, it must be *	done separately, rather than while traversing the graph. This is *	because Make defined OODATE to contain all sources whose modification *	times were later than that of the target, *not* those sources that *	were out-of-date. Since in both compatibility and native modes, *	the modification time of the parent isn't found until the child *	has been dealt with, we have to wait until now to fill in the *	variable. As for ALLSRC, the ordering is important and not *	guaranteed when in native mode, so it must be set here, too. * * Results: *	None * * Side Effects: *	The ALLSRC and OODATE variables of the given node is filled in. *	If the node is a .JOIN node, its TARGET variable will be set to * 	match its ALLSRC variable. *----------------------------------------------------------------------- */voidMake_DoAllVar (gn)    GNode	*gn;{    Lst_ForEach (gn->children, MakeAddAllSrc, gn);    if (!Var_Exists (OODATE, gn)) {	Var_Set (OODATE, "", gn);    }    if (!Var_Exists (ALLSRC, gn)) {	Var_Set (ALLSRC, "", gn);    }    if (gn->type & OP_JOIN) {	Var_Set (TARGET, Var_Value (ALLSRC, gn), gn);    }}/*- *----------------------------------------------------------------------- * MakeStartJobs -- *	Start as many jobs as possible. * * Results: *	If the query flag was given to pmake, no job will be started, *	but as soon as an out-of-date target is found, this function *	returns TRUE. At all other times, this function returns FALSE. * * Side Effects: *	Nodes are removed from the toBeMade queue and job table slots *	are filled. * *----------------------------------------------------------------------- */static BooleanMakeStartJobs (){    register GNode	*gn;        while (!Job_Full() && !Lst_IsEmpty (toBeMade)) {	gn = (GNode *) Lst_DeQueue (toBeMade);	if (DEBUG(MAKE)) {	    printf ("Examining %s...", gn->name);	}	/*	 * Make sure any and all predecessors that are going to be made,	 * have been.	 */	if (!Lst_IsEmpty(gn->preds)) {	    LstNode ln;	    for (ln = Lst_First(gn->preds); ln != NILLNODE; ln = Lst_Succ(ln)){		GNode	*pgn = (GNode *)Lst_Datum(ln);		if (pgn->make && pgn->made == UNMADE) {		    if (DEBUG(MAKE)) {			printf("predecessor %s not made yet.\n", pgn->name);		    }		    break;		}	    }	    /*	     * If ln isn't nil, there's a predecessor as yet unmade, so we	     * just drop this node on the floor. When the node in question	     * has been made, it will notice this node as being ready to	     * make but as yet unmade and will place the node on the queue.	     */	    if (ln != NILLNODE) {		continue;	    }	}		numNodes--;	if (Make_OODate (gn)) {	    if (DEBUG(MAKE)) {		printf ("out-of-date\n");	    }	    if (queryFlag) {		return (TRUE);	    }	    Make_DoAllVar (gn);	    Job_Make (gn);	} else {	    if (DEBUG(MAKE)) {		printf ("up-to-date\n");	    }	    gn->made = UPTODATE;	    if (gn->type & OP_JOIN) {		/*		 * Even for an up-to-date .JOIN node, we need it to have its		 * context variables so references to it get the correct		 * value for .TARGET when building up the context variables		 * of its parent(s)...		 */		Make_DoAllVar (gn);	    }	    	    Make_Update (gn);	}    }    return (FALSE);}/*- *----------------------------------------------------------------------- * MakePrintStatus -- *	Print the status of a top-level node, viz. it being up-to-date *	already or not created due to an error in a lower level. *	Callback function for Make_Run via Lst_ForEach. * * Results: *	Always returns 0. * * Side Effects: *	A message may be printed. * *----------------------------------------------------------------------- */static intMakePrintStatus(gn, cycle)    GNode   	*gn;	    /* Node to examine */    Boolean 	cycle;	    /* True if gn->unmade being non-zero implies			     * a cycle in the graph, not an error in an			     * inferior */{    if (gn->made == UPTODATE) {	printf ("`%s' is up to date.\n", gn->name);    } else if (gn->unmade != 0) {	if (cycle) {	    /*	     * If printing cycles and came to one that has unmade children,	     * print out the cycle by recursing on its children. Note a	     * cycle like:	     *	a : b	     *	b : c	     *	c : b	     * will cause this to erroneously complain about a being in	     * the cycle, but this is a good approximation.	     */	    if (gn->made == CYCLE) {		Error("Graph cycles through `%s'", gn->name);		gn->made = ENDCYCLE;		Lst_ForEach(gn->children, MakePrintStatus, (ClientData)TRUE);		gn->made = UNMADE;	    } else if (gn->made != ENDCYCLE) {		gn->made = CYCLE;		Lst_ForEach(gn->children, MakePrintStatus, (ClientData)TRUE);	    }	} else {	    printf ("`%s' not remade because of errors.\n", gn->name);	}    }    return (0);}/*- *----------------------------------------------------------------------- * Make_Run -- *	Initialize the nodes to remake and the list of nodes which are *	ready to be made by doing a breadth-first traversal of the graph *	starting from the nodes in the given list. Once this traversal *	is finished, all the 'leaves' of the graph are in the toBeMade *	queue. *	Using this queue and the Job module, work back up the graph, *	calling on MakeStartJobs to keep the job table as full as *	possible. * * Results: *	TRUE if work was done. FALSE otherwise. * * Side Effects: *	The make field of all nodes involved in the creation of the given *	targets is set to 1. The toBeMade list is set to contain all the *	'leaves' of these subgraphs. *----------------------------------------------------------------------- */BooleanMake_Run (targs)    Lst             targs;	/* the initial list of targets */{    register GNode  *gn;	/* a temporary pointer */    register Lst    examine; 	/* List of targets to examine */    int	    	    errors; 	/* Number of errors the Job module reports */    toBeMade = Lst_Init (FALSE);    examine = Lst_Duplicate(targs, NOCOPY);    numNodes = 0;        /*     * 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     * 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     * be looked at in a minute, otherwise we add its children to our queue     * and go on about our business.      */    while (!Lst_IsEmpty (examine)) {	gn = (GNode *) Lst_DeQueue (examine);		if (!gn->make) {	    gn->make = TRUE;	    numNodes++;	    	    /*	     * Apply any .USE rules before looking for implicit dependencies	     * to make sure everything has commands that should...	     */	    Lst_ForEach (gn->children, Make_HandleUse, (ClientData)gn);	    Suff_FindDeps (gn);	    if (gn->unmade != 0) {		Lst_ForEach (gn->children, MakeAddChild, (ClientData)examine);	    } else {		(void)Lst_EnQueue (toBeMade, (ClientData)gn);	    }	}    }        Lst_Destroy (examine, NOFREE);    if (queryFlag) {	/*	 * We wouldn't do any work unless we could start some jobs in 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)	 */	return (MakeStartJobs());    } else {	/*	 * Initialization. At the moment, no jobs are running and until some	 * get started, nothing will happen since the remaining upward	 * traversal of the graph is performed by the routines 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. 	 */	(void) MakeStartJobs();    }    /*     * Main Loop: The idea here is that the ending of jobs will take     * care of the maintenance of data structures and the waiting for output     * will cause us to be idle most of the time while our children run as     * 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     * 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 the     * keepgoing flag was given.     */    while (!Job_Empty ()) {	Job_CatchOutput ();	Job_CatchChildren (!usePipes);	(void)MakeStartJobs();    }    errors = Job_End();    /*     * Print the final status of each target. E.g. if it wasn't made     * because some inferior reported an error.     */    Lst_ForEach(targs, MakePrintStatus,		(ClientData)((errors == 0) && (numNodes != 0)));        return (TRUE);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -