Line data Source code
1 : /*
2 : --
3 : -- SYNOPSIS
4 : -- Perform the update of all outdated targets.
5 : --
6 : -- DESCRIPTION
7 : -- This is where we traverse the make graph looking for targets that
8 : -- are out of date, and we try to infer how to make them if we can.
9 : -- The usual make macros are understood, as well as some new ones:
10 : --
11 : -- $$ - expands to $
12 : -- $@ - full target name
13 : -- $* - target name with no suffix, same as $(@:db)
14 : -- or, the value of % in % meta rule recipes
15 : -- $? - list of out of date prerequisites
16 : -- $< - all prerequisites associated with rules line
17 : -- $& - all prerequisites associated with target
18 : -- $> - library name for target (if any)
19 : -- $^ - out of date prerequisites taken from value of $<
20 : --
21 : -- AUTHOR
22 : -- Dennis Vadura, dvadura@dmake.wticorp.com
23 : --
24 : -- WWW
25 : -- http://dmake.wticorp.com/
26 : --
27 : -- COPYRIGHT
28 : -- Copyright (c) 1996,1997 by WTI Corp. All rights reserved.
29 : --
30 : -- This program is NOT free software; you can redistribute it and/or
31 : -- modify it under the terms of the Software License Agreement Provided
32 : -- in the file <distribution-root>/readme/license.txt.
33 : --
34 : -- LOG
35 : -- Use cvs log to obtain detailed change logs.
36 : */
37 :
38 : #include "extern.h"
39 : #include "sysintf.h"
40 :
41 : typedef struct cell {
42 : char *datum;
43 : struct cell *next;
44 : size_t len;
45 : } LISTCELL, *LISTCELLPTR;
46 :
47 : typedef struct {
48 : LISTCELLPTR first;
49 : LISTCELLPTR last;
50 : size_t len;
51 : } LISTSTRING, *LISTSTRINGPTR;
52 :
53 :
54 : static void _drop_mac ANSI((HASHPTR));
55 : static void _set_recipe ANSI((char*, int));
56 : static void _set_tmd ANSI(());
57 : static void _append_file ANSI((STRINGPTR, FILE*, char*, int));
58 : static LINKPTR _dup_prq ANSI((LINKPTR));
59 : static LINKPTR _expand_dynamic_prq ANSI(( LINKPTR, LINKPTR, char * ));
60 : static char* _prefix ANSI((char *, char *));
61 : static char* _pool_lookup ANSI((char *));
62 : static int _explode_graph ANSI((CELLPTR, LINKPTR, CELLPTR));
63 :
64 :
65 : #define RP_GPPROLOG 0
66 : #define RP_RECIPE 1
67 : #define RP_GPEPILOG 2
68 : #define NUM_RECIPES 3
69 :
70 : static STRINGPTR _recipes[NUM_RECIPES];
71 : static LISTCELLPTR _freelist=NULL;
72 :
73 : static LISTCELLPTR
74 89548 : get_cell()
75 : {
76 : LISTCELLPTR cell;
77 :
78 89548 : if (!_freelist) {
79 49854 : if ((cell=MALLOC(1,LISTCELL)) == NULL)
80 0 : No_ram();
81 : }
82 : else {
83 39694 : cell = _freelist;
84 39694 : _freelist = cell->next;
85 : }
86 :
87 89548 : return(cell);
88 : }
89 :
90 :
91 : static void
92 89548 : free_cell(LISTCELLPTR cell)
93 : {
94 89548 : cell->next = _freelist;
95 89548 : _freelist = cell;
96 89548 : }
97 :
98 :
99 : static void
100 163356 : free_list(LISTCELLPTR c)
101 : {
102 163356 : if(c) {
103 64 : free_list(c->next);
104 64 : free_cell(c);
105 : }
106 163356 : }
107 :
108 :
109 : static void
110 176682 : list_init(LISTSTRINGPTR s)
111 : {
112 176682 : s->first = NULL;
113 176682 : s->last = NULL;
114 176682 : s->len = 0;
115 176682 : }
116 :
117 :
118 : static void
119 89548 : list_add(LISTSTRINGPTR s, char *str)
120 : {
121 : LISTCELLPTR p;
122 : int l;
123 :
124 89548 : if ((l = strlen(str)) == 0)
125 89548 : return;
126 :
127 89548 : p = get_cell();
128 89548 : p->datum = str;
129 89548 : p->next = NULL;
130 89548 : p->len = l;
131 :
132 89548 : if(s->first == NULL)
133 13406 : s->first = p;
134 : else
135 76142 : s->last->next = p;
136 :
137 89548 : s->last = p;
138 89548 : s->len += l+1;
139 : }
140 :
141 :
142 : static char *
143 160632 : gen_path_list_string(LISTSTRINGPTR s)/*
144 : =======================================
145 : Take a list of filepaths and create a string from it separating
146 : the filenames by a space.
147 : This function honors the cygwin specific .WINPATH attribute. */
148 : {
149 : LISTCELLPTR next, cell;
150 : int len;
151 : int slen, slen_rest;
152 : char *result;
153 : char *p, *tpath;
154 :
155 160632 : if( (slen_rest = slen = s->len) == 0)
156 147242 : return(NIL(char));
157 :
158 : /* reserve enough space to hold the concated original filenames. */
159 13390 : if((p = result = MALLOC(slen, char)) == NULL) No_ram();
160 :
161 102874 : for (cell=s->first; cell; cell=next) {
162 : #if !defined(__CYGWIN__)
163 89484 : tpath = cell->datum;
164 89484 : len=cell->len;
165 : #else
166 : /* For cygwin with .WINPATH set the lenght of the converted
167 : * filepaths might be longer. Extra checking is needed ... */
168 : tpath = DO_WINPATH(cell->datum);
169 : if( tpath == cell->datum ) {
170 : len=cell->len;
171 : }
172 : else {
173 : /* ... but only if DO_WINPATH() did something. */
174 : len = strlen(tpath);
175 : }
176 : if( len >= slen_rest ) {
177 : /* We need more memory. As DOS paths are usually shorter than the
178 : * original cygwin POSIX paths (exception mounted paths) this should
179 : * rarely happen. */
180 : int p_offset = p - result;
181 : /* Get more than needed. */
182 : slen = slen + len - slen_rest + 128;
183 : if((result = realloc( result, slen ) ) == NULL)
184 : No_ram();
185 : p = result + p_offset;
186 : }
187 : #endif
188 :
189 89484 : memcpy((void *)p, (void *)tpath, len);
190 89484 : p += len;
191 89484 : *p++ = ' ';
192 :
193 : #if defined(__CYGWIN__)
194 : /* slen_rest is only used in the cygwin / .WINPATH case. */
195 : slen_rest = slen - (p - result);
196 : #endif
197 :
198 89484 : next = cell->next;
199 89484 : free_cell(cell);
200 : }
201 :
202 13390 : *--p = '\0';
203 13390 : list_init(s);
204 :
205 13390 : return(result);
206 : }
207 :
208 :
209 : PUBLIC int
210 184 : Make_targets()/*
211 : ================
212 : Actually go and make the targets on the target list */
213 : {
214 : LINKPTR lp;
215 184 : int done = 0;
216 :
217 : DB_ENTER( "Make_targets" );
218 :
219 184 : Read_state();
220 184 : _set_recipe( ".GROUPPROLOG", RP_GPPROLOG );
221 184 : _set_recipe( ".GROUPEPILOG", RP_GPEPILOG );
222 :
223 : /* Prevent recipe inference for .ROOT */
224 184 : if ( Root->ce_recipe == NIL(STRING) ) {
225 0 : TALLOC( Root->ce_recipe, 1, STRING );
226 0 : Root->ce_recipe->st_string = "";
227 : }
228 :
229 : /* Prevent recipe inference for .TARGETS */
230 184 : if ( Targets->ce_recipe == NIL(STRING) ) {
231 184 : TALLOC( Targets->ce_recipe, 1, STRING );
232 184 : Targets->ce_recipe->st_string = "";
233 : }
234 :
235 : /* Make sure that user defined targets are marked as root targets */
236 368 : for( lp = Targets->ce_prq; lp != NIL(LINK); lp = lp->cl_next )
237 184 : lp->cl_prq->ce_attr |= A_ROOT;
238 :
239 597 : while( !done ) {
240 : int rval;
241 :
242 229 : if( (rval = Make(Root, NIL(CELL))) == -1 )
243 0 : DB_RETURN(1);
244 : else
245 229 : done = Root->ce_flag & F_MADE;
246 :
247 229 : if( !rval && !done ) Wait_for_child( FALSE, -1 );
248 : }
249 :
250 368 : for( lp = Targets->ce_prq; lp != NIL(LINK); lp = lp->cl_next ) {
251 184 : CELLPTR tgt = lp->cl_prq;
252 184 : if( !(tgt->ce_attr & A_UPDATED)
253 0 : && (Verbose & V_MAKE) )
254 0 : printf( "`%s' is up to date\n", tgt->CE_NAME );
255 : }
256 :
257 184 : DB_RETURN( 0 );
258 : }
259 :
260 :
261 :
262 : PUBLIC int
263 40823 : Make( cp, setdirroot )/*
264 : ========================
265 : Make target cp. Make() is also called on prerequisites that have no rule
266 : associated (F_TARGET is not set) to verify that they exist. */
267 : CELLPTR cp;
268 : CELLPTR setdirroot;
269 : {
270 : register LINKPTR dp, prev,next;
271 : register CELLPTR tcp;
272 : CELLPTR nsetdirroot;
273 : char *name, *lib;
274 : HASHPTR m_at, m_q, m_b, m_g, m_l, m_bb, m_up;
275 : LISTSTRING all_list, imm_list, outall_list, inf_list;
276 40823 : char *all = NIL(char);
277 40823 : char *inf = NIL(char);
278 40823 : char *outall = NIL(char);
279 40823 : char *imm = NIL(char);
280 40823 : int rval = 0; /* 0==ready, 1==target still running, -1==error */
281 40823 : int push = 0;
282 40823 : int made = F_MADE;
283 : int ignore;
284 40823 : time_t otime = (time_t) 1L; /* Hold time of newest prerequisite. */
285 40823 : int mark_made = FALSE;
286 :
287 : #if defined(__CYGWIN__)
288 : /* static variable to hold .WINPATH status of previously made target.
289 : * 0, 1 are .WINPATH states, -1 indicates the first target. */
290 : static int prev_winpath_attr = -1;
291 : #endif
292 :
293 : DB_ENTER( "Make" );
294 : DB_PRINT( "mem", ("%s:-> mem %ld", cp->CE_NAME, (long) coreleft()) );
295 :
296 : /* Initialize the various temporary storage */
297 40823 : m_q = m_b = m_g = m_l = m_bb = m_up = NIL(HASH);
298 40823 : list_init(&all_list);
299 40823 : list_init(&imm_list);
300 40823 : list_init(&outall_list);
301 40823 : list_init(&inf_list);
302 :
303 40823 : if (cp->ce_set && cp->ce_set != cp) {
304 0 : if( Verbose & V_MAKE )
305 0 : printf( "%s: Building .UPDATEALL representative [%s]\n", Pname,
306 0 : cp->ce_set->CE_NAME );
307 0 : cp = cp->ce_set;
308 : }
309 :
310 : /* If we are supposed to change directories for this target then do so.
311 : * If we do change dir, then modify the setdirroot variable to reflect
312 : * that fact for all of the prerequisites that we will be making. */
313 :
314 40823 : nsetdirroot = setdirroot;
315 40823 : ignore = (((cp->ce_attr|Glob_attr)&A_IGNORE) != 0);
316 :
317 : /* Set the UseWinpath variable to reflect the (global/local) .WINPATH
318 : * attribute. The variable is used by DO_WINPATH() and in some other
319 : * places. */
320 40823 : UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH) != 0);
321 :
322 : /* m_at needs to be defined before going to a "stop_making_it" where
323 : * a _drop_mac( m_at ) would try to free it. */
324 : /* FIXME: m_at can most probably not be changed before the next
325 : * Def_macro("@", ...) command. Check if both this and the next
326 : * call are needed. */
327 40823 : m_at = Def_macro("@", DO_WINPATH(cp->ce_fname), M_MULTI);
328 :
329 40823 : if( cp->ce_attr & A_SETDIR ) {
330 : /* Change directory only if the previous .SETDIR is a different
331 : * directory from the current one. ie. all cells with the same .SETDIR
332 : * attribute are assumed to come from the same directory. */
333 :
334 0 : if( (setdirroot == NIL(CELL) || setdirroot->ce_dir != cp->ce_dir) &&
335 0 : (push = Push_dir(cp->ce_dir,cp->CE_NAME,ignore)) != 0 )
336 0 : setdirroot = cp;
337 : }
338 :
339 : DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
340 :
341 : /* FIXME: F_MULTI targets don't have cp->ce_recipe set but the recipes
342 : * are known nevertheless. It is not necessary to infer them.
343 : * If (cp->ce_flag & F_MULTI) is true the recipes of the corresponding
344 : * subtargets can be used. */
345 40823 : if( cp->ce_recipe == NIL(STRING) ) {
346 34255 : char *dir = cp->ce_dir;
347 :
348 34255 : if( Verbose & V_MAKE )
349 0 : printf( "%s: Infering prerequisite(s) and recipe for [%s]\n", Pname,
350 0 : cp->CE_NAME );
351 :
352 34255 : Infer_recipe( cp, setdirroot );
353 :
354 : /* See if the directory has changed, if it has then make sure we
355 : * push it. */
356 34255 : if( dir != cp->ce_dir ) {
357 0 : if( push ) Pop_dir(FALSE);
358 0 : push = Push_dir( cp->ce_dir, cp->CE_NAME, ignore );
359 0 : setdirroot = cp;
360 : }
361 : }
362 :
363 81646 : for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
364 40823 : tcp = dp->cl_prq;
365 40823 : if( push ) {
366 : /* If we changed the directory because of .SETDIR write Pwd into
367 : * tcp->ce_dir so that it holds an absolute path. */
368 0 : if( !(tcp->ce_attr & A_POOL) && tcp->ce_dir ) FREE( tcp->ce_dir );
369 0 : tcp->ce_dir = _pool_lookup(Pwd);
370 0 : tcp->ce_attr |= A_SETDIR|A_POOL;
371 : }
372 40823 : tcp->ce_setdir = nsetdirroot;
373 : }
374 :
375 : DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
376 : /* If we have not yet statted the target then do so. */
377 40823 : if( !(cp->ce_flag & F_STAT) && !(cp->ce_attr&A_PHONY) ) {
378 32581 : if (cp->ce_parent && (cp->ce_parent->ce_flag & F_MULTI)) {
379 : /* Inherit the stat info from the F_MULTI parent. */
380 0 : cp->ce_time = cp->ce_parent->ce_time;
381 0 : cp->ce_flag |= F_STAT;
382 : /* Propagate the A_PRECIOUS attribute from the parent. */
383 0 : cp->ce_attr |= cp->ce_parent->ce_attr & A_PRECIOUS;
384 : }
385 : else {
386 65162 : for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
387 32581 : tcp = dp->cl_prq;
388 : /* Check if target already exists. */
389 32581 : Stat_target( tcp, 1, FALSE );
390 :
391 32581 : if( tcp->ce_time != (time_t)0L ) {
392 : /* File exists so don't remove it later. */
393 31464 : tcp->ce_attr |= A_PRECIOUS;
394 : }
395 :
396 32581 : if( Verbose & V_MAKE )
397 0 : printf("%s: Time stamp of [%s] is %ld\n",Pname,tcp->CE_NAME,
398 : tcp->ce_time);
399 : }
400 : }
401 : }
402 :
403 : DB_PRINT( "make", ("(%s, %ld, 0x%08x, 0x%04x)", cp->CE_NAME,
404 : cp->ce_time, cp->ce_attr, cp->ce_flag) );
405 :
406 : /* Handle targets without rule and without existing file. */
407 40823 : if( !(cp->ce_flag & F_TARGET) && (cp->ce_time == (time_t) 0L) ) {
408 572 : if( Makemkf ) {
409 554 : rval = -1;
410 554 : goto stop_making_it;
411 : }
412 18 : else if( cp->ce_prq != NIL(LINK)
413 0 : || (STOBOOL(Augmake) && (cp->ce_flag&F_EXPLICIT)))
414 : /* Assume an empty recipe for a target that we have run inference on
415 : * but do not have a set of rules for but for which we have inferred
416 : * a list of prerequisites. */
417 18 : cp->ce_flag |= F_RULES;
418 : else
419 0 : Fatal( "`%s' not found, and can't be made", cp->CE_NAME );
420 : }
421 :
422 : DB_PRINT( "mem", ("%s:-A mem %ld", cp->CE_NAME, (long) coreleft()) );
423 :
424 : /* set value of $* if we have not infered a recipe, in this case $* is
425 : * the same as $(@:db), this allows us to be compatible with BSD make */
426 40269 : if( cp->ce_per == NIL(char) ) cp->ce_per = "$(@:db)";
427 :
428 : /* Search the prerequisite list for dynamic prerequisites and if we find
429 : * them copy the list of prerequisites for potential later re-use. */
430 40269 : if ( cp->ce_prqorg == NIL(LINK) ) {
431 63521 : for( dp = cp->ce_prq; dp != NIL(LINK); dp = dp->cl_next )
432 27886 : if ( strchr(dp->cl_prq->CE_NAME, '$') != NULL )
433 4634 : break;
434 :
435 40269 : if (dp != NIL(LINK)) {
436 4634 : cp->ce_prqorg = _dup_prq(cp->ce_prq);
437 : }
438 : }
439 :
440 : /* Define $@ macro. The only reason for defining it here (that I see ATM)
441 : * is that $@ is already defined in conditional macros. */
442 : /* FIXME: check if both this and the previous Def_macro("@", ...) call
443 : * are needed. */
444 40269 : m_at = Def_macro("@", DO_WINPATH(cp->ce_fname), M_MULTI);
445 :
446 : /* Define conditional macros if any, note this is done BEFORE we process
447 : * prerequisites for the current target. Thus the making of a prerequisite
448 : * is done using the current value of the conditional macro. */
449 80538 : for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
450 40269 : tcp=dp->cl_prq;
451 40269 : if (tcp->ce_cond != NIL(STRING)) {
452 : STRINGPTR sp;
453 :
454 0 : tcp->ce_pushed = NIL(HASH);
455 0 : for(sp=tcp->ce_cond; sp; sp=sp->st_next) {
456 0 : if(Parse_macro(sp->st_string,M_MULTI|M_PUSH)) {
457 : HASHPTR hp;
458 :
459 0 : hp = GET_MACRO(LastMacName);
460 0 : hp->ht_link = tcp->ce_pushed;
461 0 : tcp->ce_pushed = hp;
462 : }
463 : else {
464 0 : Error("Invalid conditional macro expression [%s]",sp->st_string);
465 : }
466 : }
467 : }
468 : }
469 :
470 : /* First round, will be repeated a second time below. */
471 91361 : for( prev=NULL,dp=cp->ce_prq; dp != NIL(LINK); prev=dp, dp=next ) {
472 : int seq;
473 :
474 : /* This loop executes Make() to build prerequisites if needed.
475 : * The only macro that needs to be reset after a Make() was executed
476 : * is $@ as it might be used when expanding potential dynamic
477 : * prerequisites. As UseWinpath is a global variable we also
478 : * need to restore it. */
479 51162 : if (m_at->ht_value == NIL(char)) {
480 : /* This check effectively tests if Make() was run before because
481 : * Make() frees all dynamic macro values at the end. */
482 34271 : UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH) != 0);
483 34271 : m_at = Def_macro("@", DO_WINPATH(cp->ce_fname), M_MULTI);
484 : }
485 :
486 : /* Make the prerequisite, note that if the current target has the
487 : * .LIBRARY attribute set we pass on to the prerequisite the .LIBRARYM
488 : * attribute and pass on the name of the current target as the library
489 : * name, and we take it away when we are done. */
490 51162 : next = dp->cl_next;
491 :
492 51162 : tcp = dp->cl_prq;
493 51162 : if( Verbose & V_MAKE )
494 0 : printf("Checking prerequisite [%s]\n", tcp->CE_NAME);
495 :
496 51162 : seq = (((cp->ce_attr | Glob_attr) & A_SEQ) != 0);
497 :
498 : /* This checks if this prerequisite is still in the making, if yes
499 : * come back later. */
500 51162 : if( tcp->ce_flag & F_VISITED ) {
501 : /* Check if this currently or fully made target has the same
502 : * .SETDIR setting. If yes, continue if it was made or come
503 : * back later otherwise. */
504 11097 : if( _explode_graph(tcp, dp, setdirroot) == 0 ) {
505 : /* didn't blow it up so see if we need to wait for it. */
506 11097 : if( tcp->ce_flag & F_MADE ) {
507 : /* Target was made. */
508 11072 : continue;
509 : }
510 : else
511 : /* Target is still in the making ... */
512 25 : goto stop_making_it;
513 : }
514 : else
515 : /* Use the new prerequisite with the new .SETDIR value. */
516 0 : tcp = dp->cl_prq;
517 : }
518 :
519 : /* If the previous target (prereq) is not yet ready return if
520 : * seq is TRUE. */
521 40065 : if( seq && !made ) goto stop_making_it;
522 :
523 : /* Expand dynamic prerequisites. The F_MARK flag is guarging against
524 : * possible double expandion of dynamic prerequisites containing more
525 : * than one prerequisite. */
526 : /* A new A_DYNAMIC attribute could save a lot of strchr( ,'$') calls. */
527 40040 : if ( tcp && !(tcp->ce_flag & F_MARK) && strchr(tcp->CE_NAME, '$') ) {
528 : /* Replace this dynamic prerequisite with the the real prerequisite,
529 : * and add the additional prerequisites if there are more than one.*/
530 :
531 22862 : name = Expand( tcp->CE_NAME );
532 22862 : if( strcmp(name,cp->CE_NAME) == 0 )
533 0 : Fatal("Detected circular dynamic dependency; generated '%s'",name);
534 :
535 : /* Call helper for dynamic prerequisite expansion to replace the
536 : * prerequisite with the expanded version and add the new
537 : * prerequisites, if the macro expanded to more than one, after
538 : * the current list element. */
539 22862 : dp = _expand_dynamic_prq( cp->ce_prq, dp, name );
540 22862 : FREE( name );
541 :
542 : /* _expand_dynamic_prq() probably changed dp->cl_prq. */
543 22862 : tcp = dp->cl_prq;
544 22862 : if ( tcp ) {
545 22860 : next = dp->cl_next;
546 : }
547 : }
548 :
549 : /* Dynamic expansion results in a NULL cell only when the the new
550 : * prerequisite is already in the prerequisite list or empty. In this
551 : * case delete the cell and continue. */
552 40040 : if ( tcp == NIL(CELL) ) {
553 2 : FREE(dp);
554 2 : if ( prev == NIL(LINK) ) {
555 2 : cp->ce_prq = next;
556 2 : dp = NULL; /* dp will be the new value of prev. */
557 : }
558 : else {
559 0 : prev->cl_next = next;
560 0 : dp = prev;
561 : }
562 2 : continue;
563 : }
564 :
565 : /* Clear F_MARK flag that could have been set by _expand_dynamic_prq(). */
566 40038 : tcp->ce_flag &= ~(F_MARK);
567 :
568 40038 : if( cp->ce_attr & A_LIBRARY ) {
569 0 : tcp->ce_attr |= A_LIBRARYM;
570 0 : tcp->ce_lib = cp->ce_fname;
571 : }
572 :
573 : /* Propagate the parent's F_REMOVE and F_INFER flags to the
574 : * prerequisites. */
575 40038 : tcp->ce_flag |= cp->ce_flag & (F_REMOVE|F_INFER);
576 :
577 : /* Propagate parents A_ROOT attribute to a child if the parent is a
578 : * F_MULTI target. */
579 40038 : if( (cp->ce_flag & F_MULTI) && (cp->ce_attr & A_ROOT) )
580 0 : tcp->ce_attr |= A_ROOT;
581 :
582 40038 : tcp->ce_parent = cp;
583 40038 : rval |= Make(tcp, setdirroot);
584 :
585 40038 : if( cp->ce_attr & A_LIBRARY )
586 0 : tcp->ce_attr ^= A_LIBRARYM;
587 :
588 : /* Return on error or if Make() is still running and A_SEQ is set.
589 : * (All F_MULTI targets have the A_SEQ attribute.) */
590 40038 : if( rval == -1 || (seq && (rval==1)) )
591 : goto stop_making_it;
592 :
593 : /* If tcp is ready, set made = F_MADE. */
594 40018 : made &= tcp->ce_flag & F_MADE;
595 : }
596 :
597 :
598 : /* Do the loop again. We are most definitely going to make the current
599 : * cell now. NOTE: doing this loop here also results in a reduction
600 : * in peak memory usage by the algorithm. */
601 :
602 91119 : for( dp = cp->ce_prq; dp != NIL(LINK); dp = dp->cl_next ) {
603 : int tgflg;
604 50961 : tcp = dp->cl_prq;
605 50961 : if( tcp == NIL(CELL) )
606 0 : Fatal("Internal Error: Found prerequisite list cell without prerequisite!");
607 :
608 50961 : name = tcp->ce_fname;
609 :
610 : /* make certain that all prerequisites are made prior to advancing. */
611 50961 : if( !(tcp->ce_flag & F_MADE) ) goto stop_making_it;
612 :
613 : /* If the target is a library, then check to make certain that a member
614 : * is newer than an object file sitting on disk. If the disk version
615 : * is newer then set the time stamps so that the archived member is
616 : * replaced. */
617 50920 : if( cp->ce_attr & A_LIBRARY )
618 0 : if( tcp->ce_time <= cp->ce_time ) {
619 0 : time_t mtime = Do_stat( name, tcp->ce_lib, NIL(char *), FALSE );
620 0 : if( mtime < tcp->ce_time ) tcp->ce_time = cp->ce_time+1L;
621 : }
622 :
623 : /* Set otime to the newest time stamp of all prereqs or 1 if there
624 : * are no prerequisites. */
625 50920 : if( tcp->ce_time > otime ) otime = tcp->ce_time;
626 :
627 50920 : list_add(&all_list, name);
628 50920 : if( (tgflg = (dp->cl_flag & F_TARGET)) != 0 )
629 35472 : list_add(&inf_list, name);
630 :
631 50920 : if((cp->ce_time<tcp->ce_time) || ((tcp->ce_flag & F_TARGET) && Force)) {
632 2226 : list_add(&outall_list, name);
633 2226 : if( tgflg )
634 930 : list_add(&imm_list, name);
635 : }
636 : }
637 :
638 : /* If we are building a F_MULTI target inherit the time from
639 : * its children. */
640 40158 : if( (cp->ce_flag & F_MULTI) )
641 0 : cp->ce_time = otime;
642 :
643 : /* All prerequisites are made, now make the current target. */
644 :
645 : /* Restore UseWinpath and $@ if needed, see above for an explanation. */
646 40158 : if (m_at->ht_value == NIL(char)) {
647 : /* This check effectively tests if Make() was run before because
648 : * Make() frees all dynamic macro values at the end. */
649 5706 : UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH) != 0);
650 5706 : m_at = Def_macro("@", DO_WINPATH(cp->ce_fname), M_MULTI);
651 : }
652 :
653 : /* Create a string with all concatenate filenames. The function
654 : * respects .WINPATH. Note that gen_path_list_string empties its
655 : * parameter :( */
656 40158 : all = gen_path_list_string(&all_list);
657 40158 : imm = gen_path_list_string(&imm_list);
658 40158 : outall = gen_path_list_string(&outall_list);
659 40158 : inf = gen_path_list_string(&inf_list);
660 :
661 : DB_PRINT( "mem", ("%s:-C mem %ld", cp->CE_NAME, (long) coreleft()) );
662 : DB_PRINT( "make", ("I make '%s' if %ld > %ld", cp->CE_NAME, otime,
663 : cp->ce_time) );
664 :
665 40158 : if( Verbose & V_MAKE ) {
666 0 : printf( "%s: >>>> Making ", Pname );
667 : /* Also print the F_MULTI master target. */
668 0 : if( cp->ce_flag & F_MULTI )
669 0 : printf( "(::-\"master\" target) " );
670 0 : if( cp->ce_count != 0 )
671 0 : printf( "[%s::{%d}]\n", cp->CE_NAME, cp->ce_count );
672 : else
673 0 : printf( "[%s]\n", cp->CE_NAME );
674 : }
675 :
676 :
677 : /* Only PWD, TMD, MAKEDIR and the dynamic macros are affected by
678 : * .WINPATH. $@ is handled earlier, do the rest now. */
679 : #if defined(__CYGWIN__)
680 : /* This is only relevant for cygwin. */
681 : if( UseWinpath != prev_winpath_attr ) {
682 : Def_macro( "MAKEDIR", Makedir, M_FORCE | M_EXPANDED );
683 : /* If push is TRUE (Push_dir() was used) PWD and TMD are already
684 : * set. */
685 : if( !push ) {
686 : Def_macro( "PWD", Pwd, M_FORCE | M_EXPANDED );
687 : _set_tmd();
688 : }
689 : }
690 : prev_winpath_attr = UseWinpath;
691 : #endif
692 :
693 : /* Set the remaining dynamic macros $*, $>, $?, $<, $& and $^. */
694 :
695 : /* $* is either expanded as the result of a % inference or defined to
696 : * $(@:db) and hence unexpanded otherwise. The latter doesn't start
697 : * with / and will therefore not be touched by DO_WINPATH(). */
698 40158 : m_bb = Def_macro( "*", DO_WINPATH(cp->ce_per), M_MULTI );
699 :
700 : /* This is expanded. */
701 40158 : m_g = Def_macro( ">", DO_WINPATH(cp->ce_lib), M_MULTI|M_EXPANDED );
702 : /* These strings are generated with gen_path_list_string() and honor
703 : * .WINPATH */
704 40158 : m_q = Def_macro( "?", outall, M_MULTI|M_EXPANDED );
705 40158 : m_b = Def_macro( "<", inf, M_MULTI|M_EXPANDED );
706 40158 : m_l = Def_macro( "&", all, M_MULTI|M_EXPANDED );
707 40158 : m_up = Def_macro( "^", imm, M_MULTI|M_EXPANDED );
708 :
709 40158 : _recipes[ RP_RECIPE ] = cp->ce_recipe;
710 :
711 : /* We attempt to make the target if
712 : * 1. it has a newer prerequisite
713 : * 2. It is a target and Force is set
714 : * 3. It's set of recipe lines has changed.
715 : */
716 40158 : if( Check_state(cp, _recipes, NUM_RECIPES )
717 40158 : || (cp->ce_time < otime)
718 38684 : || ((cp->ce_flag & F_TARGET) && Force)
719 : ) {
720 :
721 1474 : if( Measure & M_TARGET )
722 0 : Do_profile_output( "s", M_TARGET, cp );
723 :
724 : /* Only checking so stop as soon as we determine we will make
725 : * something */
726 1474 : if( Check ) {
727 0 : rval = -1;
728 0 : goto stop_making_it;
729 : }
730 :
731 1474 : if( Verbose & V_MAKE )
732 0 : printf( "%s: Updating [%s], (%ld > %ld)\n", Pname,
733 0 : cp->CE_NAME, otime, cp->ce_time );
734 :
735 : /* In order to check if a targets time stamp was properly updated
736 : * after the target was made and to keep the dependency chain valid
737 : * for targets without recipes we store the minimum required file
738 : * time. If the target time stamp is older than the newest
739 : * prerequisite use that time, otherwise the current time. (This
740 : * avoids the call to Do_time() for every target, still checks
741 : * if the target time is new enough for the given prerequisite and
742 : * mintime is also the newest time of the given prerequisites and
743 : * can be used for targets without recipes.)
744 : * We reuse the ce_time member to store this minimum time until
745 : * the target is finished by Update_time_stamp(). This function
746 : * checks if the file time was updated properly and warns if it was
747 : * not. (While making a target this value does not change.) */
748 1474 : cp->ce_time = ( cp->ce_time < otime ? otime : Do_time() );
749 : DB_PRINT( "make", ("Set ce_time (mintime) to: %ld", cp->ce_time) );
750 :
751 2948 : if( Touch ) {
752 0 : name = cp->ce_fname;
753 0 : lib = cp->ce_lib;
754 :
755 0 : if( (!(Glob_attr & A_SILENT) || !Trace) && !(cp->ce_attr & A_PHONY) ) {
756 0 : if( lib == NIL(char) )
757 0 : printf("touch(%s)", name );
758 0 : else if( cp->ce_attr & A_SYMBOL )
759 0 : printf("touch(%s((%s)))", lib, name );
760 : else
761 0 : printf("touch(%s(%s))", lib, name );
762 : }
763 :
764 0 : if( !Trace && !(cp->ce_attr & A_PHONY) )
765 0 : if( Do_touch( name, lib,
766 0 : (cp->ce_attr & A_SYMBOL) ? &name : NIL(char *) ) != 0 )
767 0 : printf( " not touched - non-existant" );
768 :
769 0 : if( (!(Glob_attr & A_SILENT) || !Trace) && !(cp->ce_attr & A_PHONY) )
770 0 : printf( "\n" );
771 :
772 0 : Update_time_stamp( cp );
773 : }
774 1474 : else if( cp->ce_recipe != NIL(STRING) ) {
775 : /* If a recipe is found use it. Note this misses F_MULTI targets. */
776 1284 : if( !(cp->ce_flag & F_SINGLE) ) /* Execute the recipes once ... */
777 1284 : rval = Exec_commands( cp );
778 : /* Update_time_stamp() is called inside Exec_commands() after the
779 : * last recipe line is finished. (In _finished_child()) */
780 : else { /* or for every out of date dependency
781 : * if the ruleop ! was used. */
782 : TKSTR tk;
783 :
784 : /* We will redefine $? to be the prerequisite that the recipes
785 : * are currently evaluated for. */
786 0 : _drop_mac( m_q );
787 :
788 : /* Execute recipes for each out out of date prerequisites.
789 : * WARNING! If no prerequisite is given the recipes are not
790 : * executed at all! */
791 0 : if( outall && *outall ) {
792 : /* Wait for each prerequisite to finish, save the status
793 : * of Wait_for_completion. */
794 0 : int wait_for_completion_status = Wait_for_completion;
795 0 : Wait_for_completion = TRUE;
796 :
797 0 : SET_TOKEN( &tk, outall );
798 :
799 : /* No need to update the target timestamp/removing temporary
800 : * prerequisites (Update_time_stamp() in _finished_child())
801 : * until all prerequisites are done. */
802 0 : Doing_bang = TRUE;
803 0 : name = Get_token( &tk, "", FALSE );
804 : /* This loop might fail if outall contains filenames with
805 : * spaces. */
806 : do {
807 : /* Set $? to current prerequisite. */
808 0 : m_q->ht_value = name;
809 :
810 0 : rval = Exec_commands( cp );
811 : /* Thanks to Wait_for_completion = TRUE we are allowed
812 : * to remove the temp files here. */
813 0 : Unlink_temp_files(cp);
814 : }
815 0 : while( *(name = Get_token( &tk, "", FALSE )) != '\0' );
816 0 : Wait_for_completion = wait_for_completion_status;
817 0 : Doing_bang = FALSE;
818 : }
819 :
820 0 : Update_time_stamp( cp );
821 : /* Erase $? again. Don't free the pointer, it was part of outall. */
822 0 : m_q->ht_value = NIL(char);
823 : }
824 : }
825 362 : else if( !(cp->ce_flag & F_RULES) && !(cp->ce_flag & F_STAT) &&
826 344 : (!(cp->ce_attr & A_ROOT) || !(cp->ce_flag & F_EXPLICIT)) &&
827 0 : !(cp->ce_count) )
828 : /* F_MULTI subtargets should evaluate its parents F_RULES value
829 : * but _make_multi always sets the F_RULES value of the master
830 : * target. Assume F_RULES is set for subtargets. This might not
831 : * be true if there are no prerequisites and no recipes in any
832 : * of the subtargets. (FIXME) */
833 0 : Fatal( "Don't know how to make `%s'",cp->CE_NAME );
834 : else {
835 : /* Empty recipe, set the flag as MADE and update the time stamp */
836 : /* This might be a the master cell of a F_MULTI target. */
837 190 : Update_time_stamp( cp );
838 : }
839 : }
840 : else {
841 38684 : if( Verbose & V_MAKE )
842 0 : printf( "%s: Up to date [%s], prq time = %ld , target time = %ld)\n", Pname,
843 0 : cp->CE_NAME, otime, cp->ce_time );
844 38684 : mark_made = TRUE;
845 : }
846 :
847 : /* If mark_made == TRUE the target is up-to-date otherwise it is
848 : * currently in the making. */
849 :
850 : /* Update all targets in .UPDATEALL rule / only target cp. */
851 80316 : for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
852 40158 : tcp=dp->cl_prq;
853 :
854 : /* Set the time stamp of those prerequisites without rule to the current
855 : * time if Force is TRUE to make sure that targets depending on those
856 : * prerequisites get remade. */
857 40158 : if( !(tcp->ce_flag & F_TARGET) && Force ) tcp->ce_time = Do_time();
858 40158 : if( mark_made ) {
859 38684 : tcp->ce_flag |= F_MADE;
860 38684 : if( tcp->ce_flag & F_MULTI ) {
861 : LINKPTR tdp;
862 0 : for( tdp = tcp->ce_prq; tdp != NIL(LINK); tdp = tdp->cl_next )
863 0 : tcp->ce_attr |= tdp->cl_prq->ce_attr & A_UPDATED;
864 : }
865 : }
866 :
867 : /* Note that the target is in the making. */
868 40158 : tcp->ce_flag |= F_VISITED;
869 :
870 : /* Note: If the prerequisite was made using a .SETDIR= attribute
871 : * directory then we will include the directory in the fname
872 : * of the target. */
873 40158 : if( push ) {
874 0 : char *dir = nsetdirroot ? nsetdirroot->ce_dir : Makedir;
875 : /* get relative path from current SETDIR to new SETDIR. */
876 : /* Attention, even with .WINPATH set this has to be a POSIX
877 : * path as ce_fname neeed to be POSIX. */
878 0 : char *pref = _prefix( dir, tcp->ce_dir );
879 0 : char *nname = Build_path(pref, tcp->ce_fname);
880 :
881 0 : FREE(pref);
882 0 : if( (tcp->ce_attr & A_FFNAME) && (tcp->ce_fname != NIL(char)) )
883 0 : FREE( tcp->ce_fname );
884 :
885 0 : tcp->ce_fname = DmStrDup(nname);
886 0 : tcp->ce_attr |= A_FFNAME;
887 : }
888 : }
889 :
890 : stop_making_it:
891 40823 : _drop_mac( m_g );
892 40823 : _drop_mac( m_q );
893 40823 : _drop_mac( m_b );
894 40823 : _drop_mac( m_l );
895 40823 : _drop_mac( m_bb );
896 40823 : _drop_mac( m_up );
897 40823 : _drop_mac( m_at );
898 :
899 : /* undefine conditional macros if any */
900 81646 : for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
901 40823 : tcp=dp->cl_prq;
902 :
903 81646 : while (tcp->ce_pushed != NIL(HASH)) {
904 0 : HASHPTR cur = tcp->ce_pushed;
905 0 : tcp->ce_pushed = cur->ht_link;
906 :
907 0 : Pop_macro(cur);
908 0 : FREE(cur->ht_name);
909 0 : if(cur->ht_value)
910 0 : FREE(cur->ht_value);
911 0 : FREE(cur);
912 : }
913 : }
914 :
915 40823 : if( push )
916 0 : Pop_dir(FALSE);
917 :
918 : /* Undefine the strings that we used for constructing inferred
919 : * prerequisites. */
920 40823 : if( inf != NIL(char) ) FREE( inf );
921 40823 : if( all != NIL(char) ) FREE( all );
922 40823 : if( imm != NIL(char) ) FREE( imm );
923 40823 : if( outall != NIL(char) ) FREE( outall );
924 40823 : free_list(all_list.first);
925 40823 : free_list(imm_list.first);
926 40823 : free_list(outall_list.first);
927 40823 : free_list(inf_list.first);
928 :
929 : DB_PRINT( "mem", ("%s:-< mem %ld", cp->CE_NAME, (long) coreleft()) );
930 40823 : DB_RETURN(rval);
931 : }
932 :
933 :
934 : static char *
935 0 : _prefix( pfx, pat )/*
936 : =====================
937 : Return the relative path from pfx to pat. Both paths have to be absolute
938 : paths. If the paths are on different resources or drives (if applicable)
939 : or only share a relative path going up to the root dir and down again
940 : return pat. */
941 : char *pfx;
942 : char *pat;
943 : {
944 0 : char *cmp1=pfx;
945 0 : char *cmp2=pat;
946 0 : char *tpat=pat; /* Keep pointer to original pat. */
947 : char *result;
948 : char *up;
949 0 : int first = 1;
950 0 : int samerootdir = 1; /* Marks special treatment for the root dir. */
951 : #ifdef HAVE_DRIVE_LETTERS
952 : int pfxdl = 0;
953 : int patdl = 0;
954 : #endif
955 :
956 : /* Micro optimization return immediately if pfx and pat are equal. */
957 0 : if( strcmp(pfx, pat) == 0 )
958 0 : return(DmStrDup(""));
959 :
960 : #ifdef HAVE_DRIVE_LETTERS
961 : /* remove the drive letters to avoid getting them into the relative
962 : * path later. */
963 : if( *pfx && pfx[1] == ':' && isalpha(*pfx) ) {
964 : pfxdl = 1;
965 : cmp1 = DmStrSpn(pfx+2, DirBrkStr);
966 : }
967 : if( *pat && pat[1] == ':' && isalpha(*pat) ) {
968 : patdl = 1;
969 : cmp2 = DmStrSpn(pat+2, DirBrkStr);
970 : }
971 : /* If the drive letters are different use the abs. path. */
972 : if( pfxdl && patdl && (tolower(*pfx) != tolower(*pat)) )
973 : return(DmStrDup(pat));
974 :
975 : /* If only one has a drive letter also use the abs. path. */
976 : if( pfxdl != patdl )
977 : return(DmStrDup(pat));
978 : else if( pfxdl )
979 : /* If both are the same drive letter, disable the special top
980 : * dir treatment. */
981 : samerootdir = 0;
982 :
983 : /* Continue without the drive letters. (Either none was present,
984 : * or both were the same. This also solves the problem that the
985 : * case of the drive letters sometimes depends on the shell.
986 : * (cmd.exe vs. cygwin bash) */
987 : pfx = cmp1;
988 : pat = cmp2;
989 : #endif
990 :
991 : /* Cut off equal leading parts of pfx, pat. Both have to be abs. paths. */
992 0 : while(*pfx && *pat) {
993 : /* skip leading dir. separators. */
994 0 : pfx = DmStrSpn(cmp1, DirBrkStr);
995 0 : pat = DmStrSpn(cmp2, DirBrkStr);
996 :
997 : /* Only check in the first run of the loop. Leading slashes can only
998 : * mean POSIX paths or Windows resources (two) slashes. Drive letters
999 : * have no leading slash. In any case, if the number of slashes are
1000 : * not equal there can be no relative path from one two the other.
1001 : * In this case return the absolute path. */
1002 0 : if( first ) {
1003 0 : if( cmp1-pfx != cmp2-pat ) {
1004 0 : return(DmStrDup(tpat));
1005 : }
1006 0 : first = 0;
1007 : }
1008 :
1009 : /* find next dir. separator (or ""). */
1010 0 : cmp1 = DmStrPbrk(pfx, DirBrkStr);
1011 0 : cmp2 = DmStrPbrk(pat, DirBrkStr);
1012 :
1013 : /* if length of directory name is equal compare the strings. If equal
1014 : * go into next loop. If not equal and directory names in the root
1015 : * dir are compared return the absolut path otherwise break the loop
1016 : * and construct the relative path from pfx to pat. */
1017 0 : if ( (cmp1-pfx) != (cmp2-pat) || strncmp(pfx,pat,cmp1-pfx) != 0 ) {
1018 0 : if( samerootdir ) {
1019 0 : return(DmStrDup(tpat));
1020 : }
1021 0 : break;
1022 : }
1023 :
1024 0 : if( samerootdir ) {
1025 : #if __CYGWIN__
1026 : /* If the toplevel directory is /cygdrive (or the equivalent prefix)
1027 : * treat the following level also as rootdir. If we are here cmp1-pfx
1028 : * cannot be zero so we won't compare with an empty cygdrive prefix. */
1029 : if ( (cmp1-pfx) == CygDrvPreLen && strncmp(pfx,CygDrvPre,CygDrvPreLen) == 0 )
1030 : samerootdir = 1;
1031 : else
1032 : #endif
1033 0 : samerootdir = 0;
1034 : }
1035 : }
1036 :
1037 0 : result = DmStrDup("");
1038 0 : up = DmStrJoin("..",DirSepStr,-1,FALSE);
1039 0 : cmp1 = pfx;
1040 : /* Add "../" for each directory in pfx */
1041 0 : while ( *(pfx=DmStrSpn(cmp1,DirBrkStr)) != '\0' ) {
1042 0 : cmp1 = DmStrPbrk(pfx,DirBrkStr);
1043 0 : result = DmStrJoin(result,up,-1,TRUE);
1044 : }
1045 0 : FREE(up);
1046 :
1047 0 : pat = DmStrSpn(pat,DirBrkStr);
1048 : /* Append pat to result. */
1049 0 : if( *pat != '\0' ) {
1050 0 : cmp2 = DmStrDup(Build_path(result, pat));
1051 0 : FREE(result);
1052 0 : result = cmp2;
1053 : } else {
1054 : /* if pat is empty and result exists remove the trailing slash
1055 : * from the last "../". */
1056 0 : if( *result ) {
1057 0 : result[strlen(result)-1] = '\0';
1058 : }
1059 : }
1060 :
1061 0 : return(result);
1062 : }
1063 :
1064 :
1065 : static LINKPTR
1066 32120 : _dup_prq( lp )
1067 : LINKPTR lp;
1068 : {
1069 : LINKPTR tlp;
1070 :
1071 32120 : if( lp == NIL(LINK) ) return(lp);
1072 :
1073 27486 : TALLOC(tlp, 1, LINK);
1074 27486 : tlp->cl_prq = lp->cl_prq;
1075 27486 : tlp->cl_flag = lp->cl_flag;
1076 27486 : tlp->cl_next = _dup_prq( lp->cl_next );
1077 :
1078 27486 : return(tlp);
1079 : }
1080 :
1081 :
1082 : static LINKPTR
1083 22862 : _expand_dynamic_prq( head, lp, name )/*
1084 : =======================================
1085 : The string name can contain one or more target names. Check if these are
1086 : already a prerequisite for the current target. If not add them to the list
1087 : of prerequisites. If no prerequisites were added set lp->cl_prq to NULL.
1088 : Set the F_MARK flag to indicate that the prerequisite was expanded.
1089 : Use cl_flag instead?? */
1090 : LINKPTR head;
1091 : LINKPTR lp;
1092 : char *name;
1093 : {
1094 22862 : CELLPTR cur = lp->cl_prq;
1095 :
1096 22862 : if( !(*name) ) {
1097 : /* If name is empty this leaves lp->cl_prq unchanged -> No prerequisite added. */
1098 : ;
1099 : }
1100 22860 : else if ( strchr(name, ' ') == NIL(char) ) {
1101 : /* If condition above is true, no space is found. */
1102 22828 : CELLPTR prq = Def_cell(name);
1103 : LINKPTR tmp;
1104 :
1105 : /* Check if prq already exists. */
1106 22828 : for(tmp=head;tmp != NIL(LINK) && tmp->cl_prq != prq;tmp=tmp->cl_next);
1107 :
1108 : /* If tmp is NULL then the prerequisite is new and is added to the list. */
1109 22828 : if ( !tmp ) {
1110 : /* replace the prerequisite with the expanded version. */
1111 22828 : lp->cl_prq = prq;
1112 22828 : lp->cl_prq->ce_flag |= F_MARK;
1113 : }
1114 : }
1115 : else {
1116 32 : LINKPTR tlp = lp;
1117 32 : LINKPTR next = lp->cl_next;
1118 : TKSTR token;
1119 : char *p;
1120 32 : int first=TRUE;
1121 :
1122 : /* Handle more than one prerequisite. */
1123 32 : SET_TOKEN(&token, name);
1124 584 : while (*(p=Get_token(&token, "", FALSE)) != '\0') {
1125 520 : CELLPTR prq = Def_cell(p);
1126 : LINKPTR tmp;
1127 :
1128 520 : for(tmp=head;tmp != NIL(LINK) && tmp->cl_prq != prq;tmp=tmp->cl_next);
1129 :
1130 : /* If tmp is not NULL the prerequisite already exists. */
1131 520 : if ( tmp ) continue;
1132 :
1133 : /* Add list elements behind the first if more then one new
1134 : * prerequisite is found. */
1135 520 : if ( first ) {
1136 32 : first = FALSE;
1137 : }
1138 : else {
1139 488 : TALLOC(tlp->cl_next,1,LINK);
1140 488 : tlp = tlp->cl_next;
1141 488 : tlp->cl_flag |= F_TARGET;
1142 488 : tlp->cl_next = next;
1143 : }
1144 :
1145 520 : tlp->cl_prq = prq;
1146 520 : tlp->cl_prq->ce_flag |= F_MARK;
1147 : }
1148 32 : CLEAR_TOKEN( &token );
1149 : }
1150 :
1151 : /* If the condition is true no new prerequisits were found. */
1152 22862 : if ( lp->cl_prq == cur ) {
1153 2 : lp->cl_prq = NIL(CELL);
1154 2 : lp->cl_flag = 0;
1155 : }
1156 :
1157 : /* Is returned unchanged. */
1158 22862 : return(lp);
1159 : }
1160 :
1161 :
1162 : static void
1163 285761 : _drop_mac( hp )/*
1164 : ================ set a macro value to zero. */
1165 : HASHPTR hp;
1166 : {
1167 285761 : if( hp && hp->ht_value != NIL(char) ) {
1168 94310 : FREE( hp->ht_value );
1169 94310 : hp->ht_value = NIL(char);
1170 : }
1171 285761 : }
1172 :
1173 :
1174 :
1175 : static int
1176 11097 : _explode_graph( cp, parent, setdirroot )/*
1177 : ==========================================
1178 : Check to see if we have made the node already. If so then don't do
1179 : it again, except if the cell's ce_setdir field is set to something other
1180 : than the value of setdirroot. If they differ then, and we have made it
1181 : already, then make it again and set the cell's stat bit to off so that
1182 : we do the stat again. */
1183 : CELLPTR cp;
1184 : LINKPTR parent;
1185 : CELLPTR setdirroot;
1186 : {
1187 : static CELLPTR removecell = NIL(CELL);
1188 :
1189 11097 : if ( removecell == NIL(CELL) )
1190 184 : removecell = Def_cell(".REMOVE");
1191 :
1192 : /* we may return if we made it already from the same setdir location,
1193 : * or if it is not a library member whose lib field is non NULL. (if
1194 : * it is such a member then we have a line of the form:
1195 : * lib1 lib2 .LIBRARY : member_list...
1196 : * and we have to make sure all members are up to date in both libs. */
1197 :
1198 11097 : if ( setdirroot == removecell )
1199 0 : return( 0 );
1200 :
1201 22194 : if( cp->ce_setdir == setdirroot &&
1202 11097 : !((cp->ce_attr & A_LIBRARYM) && (cp->ce_lib != NIL(char))) )
1203 11097 : return( 0 );
1204 :
1205 : /* We check to make sure that we are comming from a truly different
1206 : * directory, ie. ".SETDIR=joe : a.c b.c d.c" are all assumed to come
1207 : * from the same directory, even though setdirroot is different when
1208 : * making dependents of each of these targets. */
1209 :
1210 0 : if( cp->ce_setdir != NIL(CELL) &&
1211 0 : setdirroot != NIL(CELL) &&
1212 0 : cp->ce_dir &&
1213 0 : setdirroot->ce_dir &&
1214 0 : !strcmp(cp->ce_dir, setdirroot->ce_dir) )
1215 0 : return( 0 );
1216 :
1217 0 : if( Max_proc > 1 ) {
1218 : LINKPTR dp;
1219 :
1220 0 : TALLOC(parent->cl_prq, 1, CELL);
1221 0 : *parent->cl_prq = *cp;
1222 0 : cp = parent->cl_prq;
1223 0 : cp->ce_prq = _dup_prq(cp->ce_prqorg);
1224 0 : cp->ce_all.cl_prq = cp;
1225 0 : CeNotMe(cp) = _dup_prq(CeNotMe(cp));
1226 :
1227 0 : for(dp=CeNotMe(cp);dp;dp=dp->cl_next) {
1228 0 : CELLPTR tcp = dp->cl_prq;
1229 0 : TALLOC(dp->cl_prq,1,CELL);
1230 0 : *dp->cl_prq = *tcp;
1231 0 : dp->cl_prq->ce_flag &= ~(F_STAT|F_VISITED|F_MADE);
1232 0 : dp->cl_prq->ce_set = cp;
1233 : }
1234 : }
1235 0 : cp->ce_flag &= ~(F_STAT|F_VISITED|F_MADE);
1236 :
1237 : /* Indicate that we exploded the graph and that the current node should
1238 : * be made. */
1239 0 : return(1);
1240 : }
1241 :
1242 :
1243 :
1244 : PUBLIC int
1245 1668 : Exec_commands( cp )/*
1246 : =====================
1247 : Execute the commands one at a time that are pointed to by the rules pointer
1248 : of the target cp if normal (non-group) recipes are defined. If a group recipe
1249 : is found all commands are written into a temporary file first and this
1250 : (group-) shell script is executed all at once.
1251 : If a group is indicated, then the ce_attr determines .IGNORE and .SILENT
1252 : treatment for the group.
1253 :
1254 : The function returns 0, if the command is executed and has successfully
1255 : returned, and it returns 1 if the command is executing but has not yet
1256 : returned or -1 if an error occurred (Return value from Do_cmnd()).
1257 :
1258 : Macros that are found in recipe lines are expanded in this function, in
1259 : parallel builds this can mean they are expanded before the previous recipe
1260 : lines are finished. (Exception: $(shell ..) waits until all previous recipe
1261 : lines are done.)
1262 :
1263 : The F_MADE bit in the cell is guaranteed set when the command has
1264 : successfully completed. */
1265 : CELLPTR cp;
1266 : {
1267 : static HASHPTR useshell = NIL(HASH);
1268 : static HASHPTR command = NIL(HASH);
1269 : static int read_cmnd = 0;
1270 : register STRINGPTR rp;
1271 : STRINGPTR orp;
1272 : char *cmnd;
1273 : char *groupfile;
1274 1668 : FILE *tmpfile = 0;
1275 : int do_it;
1276 : t_attr attr;
1277 : int group;
1278 : int trace;
1279 1668 : int rval = 0;
1280 :
1281 : DB_ENTER( "Exec_commands" );
1282 :
1283 1668 : if( cp->ce_recipe == NIL(STRING) )
1284 0 : Fatal("Internal Error: No recipe found!");
1285 :
1286 1668 : attr = Glob_attr | cp->ce_attr;
1287 1668 : trace = Trace || !(attr & A_SILENT);
1288 1668 : group = cp->ce_flag & F_GROUP;
1289 :
1290 : /* Do it again here for those that call us from places other than Make()
1291 : * above. */
1292 1668 : orp = _recipes[ RP_RECIPE ];
1293 1668 : _recipes[ RP_RECIPE ] = cp->ce_recipe;
1294 :
1295 1668 : if( group ) {
1296 : /* Leave this assignment of Current_target here. It is needed just
1297 : * incase the user hits ^C after the tempfile for the group recipe
1298 : * has been opened. */
1299 0 : Current_target = cp;
1300 0 : trace = Trace || !(attr & A_SILENT);
1301 :
1302 0 : if( !Trace ) tmpfile = Start_temp( Grp_suff, cp, &groupfile );
1303 0 : if( trace ) fputs( "[\n", stdout );
1304 :
1305 : /* Emit group prolog */
1306 0 : if( attr & A_PROLOG )
1307 0 : _append_file( _recipes[RP_GPPROLOG], tmpfile, cp->CE_NAME, trace );
1308 : }
1309 :
1310 1668 : if( !useshell )
1311 184 : useshell=Def_macro("USESHELL",NIL(char),M_MULTI|M_EXPANDED);
1312 :
1313 1668 : if( !read_cmnd ) {
1314 184 : command = GET_MACRO("COMMAND");
1315 184 : read_cmnd = 1;
1316 : }
1317 :
1318 : /* Process commands in recipe. If in group, merely append to file.
1319 : * Otherwise, run them. */
1320 3852 : for( rp=_recipes[RP_RECIPE]; rp != NIL(STRING); rp=rp->st_next) {
1321 2184 : t_attr a_attr = A_DEFAULT;
1322 : t_attr l_attr;
1323 : char *p;
1324 2184 : int new_attr = FALSE;
1325 : int shell; /* True if the recipe shall run in shell. */
1326 :
1327 : /* Reset it for each recipe line otherwise tempfiles don't get removed.
1328 : * Since processing of $(mktmp ...) depends on Current_target being
1329 : * correctly set. */
1330 2184 : Current_target = cp;
1331 :
1332 : /* Only check for +,-,%,@ if the recipe line begins with a '$' macro
1333 : * expansion. Otherwise there is no way it is going to find these
1334 : * now. */
1335 2184 : if( *rp->st_string == '$' && !group ) {
1336 876 : t_attr s_attr = Glob_attr;
1337 876 : Glob_attr |= A_SILENT;
1338 876 : Suppress_temp_file = TRUE;
1339 876 : cmnd = Expand(rp->st_string);
1340 876 : Suppress_temp_file = FALSE;
1341 876 : a_attr |= Rcp_attribute(cmnd);
1342 876 : FREE(cmnd);
1343 876 : ++new_attr;
1344 876 : Glob_attr = s_attr;
1345 : }
1346 :
1347 2184 : l_attr = attr|a_attr|rp->st_attr;
1348 2184 : shell = ((l_attr & A_SHELL) != 0);
1349 2184 : useshell->ht_value = (group||shell)?"yes":"no";
1350 :
1351 : /* All macros are expanded before putting them in the "process queue".
1352 : * Nothing in Expand() should be able to change dynamic macros. */
1353 2184 : cmnd = Expand( rp->st_string );
1354 :
1355 2184 : if( new_attr && (p = DmStrSpn(cmnd," \t\n+-@%")) != cmnd ) {
1356 4 : size_t len = strlen(p)+1;
1357 4 : memmove(cmnd,p,len);
1358 : }
1359 :
1360 : /* COMMAND macro is set to "$(CMNDNAME) $(CMNDARGS)" by default, it is
1361 : * possible for the user to reset it to, for example
1362 : * COMMAND = $(CMNDNAME) @$(mktmp $(CMNDARGS))
1363 : * in order to get a different interface for his command execution. */
1364 2184 : if( command != NIL(HASH) && !group ) {
1365 0 : char *cname = cmnd;
1366 : char cmndbuf[30];
1367 :
1368 0 : if ( *(p=DmStrPbrk(cmnd," \t\n")) != '\0' ) {
1369 0 : *p = '\0';
1370 0 : (void)Def_macro("CMNDARGS",DmStrSpn(p+1," \t\n"),M_MULTI|M_EXPANDED);
1371 : }
1372 : else
1373 0 : (void) Def_macro("CMNDARGS","",M_MULTI|M_EXPANDED);
1374 :
1375 0 : (void) Def_macro("CMNDNAME",cname,M_MULTI|M_EXPANDED);
1376 :
1377 0 : strcpy(cmndbuf, "$(COMMAND)");
1378 0 : cmnd = Expand(cmndbuf);
1379 0 : FREE(cname); /* cname == cmnd at this point. */
1380 :
1381 : /* Collect up any new attributes */
1382 0 : l_attr |= Rcp_attribute(cmnd);
1383 0 : shell = ((l_attr & A_SHELL) != 0);
1384 :
1385 : /* clean up the attributes that we may have just added. */
1386 0 : if( (p = DmStrSpn(cmnd," \t\n+-@%")) != cmnd ) {
1387 0 : size_t len = strlen(p)+1;
1388 0 : memmove(cmnd,p,len);
1389 : }
1390 : }
1391 :
1392 : #if defined(MSDOS)
1393 : Swap_on_exec = ((l_attr & A_SWAP) != 0); /* Swapping for DOS only */
1394 : #endif
1395 2184 : do_it = !Trace;
1396 :
1397 : /* We force execution of the recipe if we are tracing and the .EXECUTE
1398 : * attribute was given or if the it is not a group recipe and the
1399 : * recipe line contains the string $(MAKE). Wait_for_completion might
1400 : * be changed gobaly but this is without consequences as we wait for
1401 : * every recipe with .EXECUTE and don't start anything else. */
1402 2184 : if( Trace
1403 0 : && ((l_attr & A_EXECUTE)||(!group && DmStrStr(rp->st_string,"$(MAKE)")))
1404 : ) {
1405 0 : Wait_for_completion |= Trace;
1406 0 : do_it = TRUE;
1407 : }
1408 :
1409 2184 : if( group )
1410 : /* Append_line() calls Print_cmnd(). */
1411 0 : Append_line( cmnd, TRUE, tmpfile, cp->CE_NAME, trace, 0 );
1412 : else {
1413 : /* Don't print empty recipe lines. .ROOT and .TARGETS
1414 : * deliberately might have empty "" recipes and we don't want
1415 : * to output empty recipe lines for them. */
1416 2184 : if ( *cmnd ) {
1417 : /* Print command and remove continuation sequence from cmnd. */
1418 1094 : Print_cmnd(cmnd, !(do_it && (l_attr & A_SILENT)), 0);
1419 : }
1420 2184 : rval=Do_cmnd(&cmnd,FALSE,do_it,cp,l_attr,
1421 2184 : rp->st_next == NIL(STRING) );
1422 : }
1423 :
1424 2184 : FREE(cmnd);
1425 : }
1426 :
1427 : /* If it is a group then output the EPILOG if required and possibly
1428 : * execute the command */
1429 1668 : if( group && !(cp->ce_attr & A_ERROR) ) {
1430 0 : if( attr & A_EPILOG ) /* emit epilog */
1431 0 : _append_file( _recipes[RP_GPEPILOG], tmpfile, cp->CE_NAME, trace );
1432 :
1433 0 : if( trace ) fputs("]\n", stdout);
1434 :
1435 0 : do_it = !Trace;
1436 0 : if( do_it )
1437 : {
1438 0 : Close_temp( cp, tmpfile );
1439 : #if defined(UNIX)
1440 :
1441 : chmod(groupfile,0700);
1442 : #endif
1443 : }
1444 0 : rval = Do_cmnd(&groupfile, TRUE, do_it, cp, attr | A_SHELL, TRUE);
1445 : }
1446 :
1447 1668 : _recipes[ RP_RECIPE ] = orp;
1448 1668 : cp->ce_attr &= ~A_ERROR;
1449 1668 : DB_RETURN( rval );
1450 : }
1451 :
1452 :
1453 : PUBLIC void
1454 1456 : Print_cmnd( cmnd, echo, map )/*
1455 : ================================
1456 : This routine is called to print out the command to stdout. If echo is
1457 : false the printing to stdout is supressed.
1458 : The routine is also used to remove the line continuation sequence
1459 : \<nl> from the command string and convert escape sequences if the
1460 : map flag is set.
1461 : The changed string is used later to actually to execute the command. */
1462 : char *cmnd;
1463 : int echo;
1464 : int map;
1465 : {
1466 : register char *p;
1467 : register char *n;
1468 : char tmp[3];
1469 :
1470 : DB_ENTER( "Print_cmnd" );
1471 :
1472 1456 : if( echo ) {
1473 6 : printf( "%s\n", cmnd );
1474 6 : fflush(stdout);
1475 : }
1476 :
1477 1456 : tmp[0] = ESCAPE_CHAR;
1478 1456 : tmp[1] = CONTINUATION_CHAR;
1479 1456 : tmp[2] = '\0';
1480 :
1481 2912 : for( p=cmnd; *(n = DmStrPbrk(p,tmp)) != '\0'; )
1482 : /* Remove the \<nl> sequences. */
1483 0 : if(*n == CONTINUATION_CHAR && n[1] == '\n') {
1484 0 : size_t len = strlen(n+2)+1;
1485 : DB_PRINT( "make", ("fixing [%s]", p) );
1486 0 : memmove( n, n+2, len );
1487 0 : p = n;
1488 : }
1489 : /* Look for an escape sequence and replace it by it's corresponding
1490 : * character value. */
1491 : else {
1492 0 : if( *n == ESCAPE_CHAR && map ) Map_esc( n );
1493 0 : p = n+1;
1494 : }
1495 :
1496 1456 : DB_VOID_RETURN;
1497 : }
1498 :
1499 :
1500 :
1501 : /* These routines are used to maintain a stack of directories when making
1502 : * the targets. If a target cd's to the directory then it is assumed that
1503 : * it will undo it when it is finished making itself. */
1504 :
1505 : static STRINGPTR dir_stack = NIL(STRING);
1506 :
1507 : PUBLIC int
1508 0 : Push_dir( dir, name, ignore )/*
1509 : ===============================
1510 : Change the current working directory to dir and save the current
1511 : working directory on the stack so that we can come back.
1512 :
1513 : If ignore is TRUE then do not complain about _ch_dir if not possible.
1514 :
1515 : Return 1 if the directory change was successfull and 0 otherwise. */
1516 : char *dir;
1517 : char *name;
1518 : int ignore;
1519 : {
1520 : STRINGPTR new_dir;
1521 :
1522 : DB_ENTER( "Push_dir" );
1523 :
1524 0 : if( dir == NIL(char) || *dir == '\0' ) dir = Pwd;
1525 0 : if( *dir == '\'' && dir[strlen(dir)-1] == '\'' ) {
1526 0 : dir = DmStrDup(dir+1);
1527 0 : dir[strlen(dir)-1]='\0';
1528 : }
1529 0 : else if (strchr(dir,'$') != NIL(char))
1530 0 : dir = Expand(dir);
1531 : else
1532 0 : dir = DmStrDup(dir);
1533 :
1534 0 : if( Set_dir(dir) ) {
1535 0 : if( !ignore )
1536 0 : Fatal( "Unable to change to directory `%s', target is [%s]",
1537 : dir, name );
1538 0 : FREE(dir);
1539 0 : DB_RETURN( 0 );
1540 : }
1541 :
1542 : DB_PRINT( "dir", ("Push: [%s]", dir) );
1543 0 : if( Verbose & V_DIR_SET )
1544 0 : printf( "%s: Changed to directory [%s]\n", Pname, dir );
1545 :
1546 0 : FREE( dir );
1547 0 : TALLOC( new_dir, 1, STRING );
1548 0 : new_dir->st_next = dir_stack;
1549 0 : dir_stack = new_dir;
1550 0 : new_dir->st_string = DmStrDup( Pwd );
1551 :
1552 0 : Def_macro( "PWD", Get_current_dir(), M_FORCE | M_EXPANDED );
1553 0 : _set_tmd();
1554 :
1555 0 : DB_RETURN( 1 );
1556 : }
1557 :
1558 :
1559 :
1560 : PUBLIC void
1561 0 : Pop_dir(ignore)/*
1562 : =================
1563 : Change the current working directory to the previous saved dir. */
1564 : int ignore;
1565 : {
1566 : STRINGPTR old_dir;
1567 : char *dir;
1568 :
1569 : DB_ENTER( "Pop_dir" );
1570 :
1571 0 : if( dir_stack == NIL(STRING) ) {
1572 0 : if( ignore ) {
1573 0 : DB_VOID_RETURN;
1574 : }
1575 : else
1576 0 : Error( "Directory stack empty for return from .SETDIR" );
1577 : }
1578 :
1579 0 : if( Set_dir(dir = dir_stack->st_string) )
1580 0 : Fatal( "Could not change to directory `%s'", dir );
1581 :
1582 0 : Def_macro( "PWD", dir, M_FORCE | M_EXPANDED );
1583 : DB_PRINT( "dir", ("Pop: [%s]", dir) );
1584 0 : if( Verbose & V_DIR_SET )
1585 0 : printf( "%s: Changed back to directory [%s]\n", Pname, dir);
1586 :
1587 0 : old_dir = dir_stack;
1588 0 : dir_stack = dir_stack->st_next;
1589 :
1590 0 : FREE( old_dir->st_string );
1591 0 : FREE( old_dir );
1592 0 : _set_tmd();
1593 :
1594 0 : DB_VOID_RETURN;
1595 : }
1596 :
1597 :
1598 :
1599 : static void
1600 0 : _set_tmd()/*
1601 : ============
1602 : Set the TMD Macro and the Tmd global variable. TMD stands for "To MakeDir"
1603 : and is the path from the present directory (value of $(PWD)) to the directory
1604 : dmake was started up in (value of $(MAKEDIR)). As _prefix() can return absolute
1605 : paths some special .WINPATH treatment is needed.
1606 : */
1607 : {
1608 : char *tmd;
1609 :
1610 0 : if( Tmd )
1611 0 : FREE(Tmd);
1612 :
1613 0 : tmd = _prefix(Pwd, Makedir);
1614 0 : if( *tmd ) {
1615 0 : Def_macro( "TMD", DO_WINPATH(tmd), M_FORCE | M_EXPANDED );
1616 0 : Tmd = DmStrDup(tmd);
1617 : } else {
1618 0 : Def_macro( "TMD", ".", M_FORCE | M_EXPANDED );
1619 0 : Tmd = DmStrDup(".");
1620 : }
1621 0 : FREE( tmd );
1622 0 : }
1623 :
1624 :
1625 : static void
1626 368 : _set_recipe( target, ind )/*
1627 : ============================
1628 : Set up the _recipes static variable so that the slot passed in points
1629 : at the rules corresponding to the target supplied. */
1630 : char *target;
1631 : int ind;
1632 : {
1633 : CELLPTR cp;
1634 : HASHPTR hp;
1635 :
1636 368 : if( (hp = Get_name(target, Defs, FALSE)) != NIL(HASH) ) {
1637 0 : cp = hp->CP_OWNR;
1638 0 : _recipes[ ind ] = cp->ce_recipe;
1639 : }
1640 : else
1641 368 : _recipes[ ind ] = NIL(STRING);
1642 368 : }
1643 :
1644 :
1645 :
1646 : PUBLIC void
1647 362 : Append_line( cmnd, newline, tmpfile, name, printit, map )
1648 : char *cmnd;
1649 : int newline;
1650 : FILE *tmpfile;
1651 : char *name;
1652 : int printit;
1653 : int map;
1654 : {
1655 362 : Print_cmnd( cmnd, printit, map );
1656 :
1657 724 : if( Trace ) return;
1658 :
1659 362 : fputs(cmnd, tmpfile);
1660 362 : if( newline ) fputc('\n', tmpfile);
1661 362 : fflush(tmpfile);
1662 :
1663 362 : if( ferror(tmpfile) )
1664 0 : Fatal("Write error on temporary file, while processing `%s'", name);
1665 : }
1666 :
1667 :
1668 :
1669 : static void
1670 0 : _append_file( rp, tmpfile, name, printit )
1671 : register STRINGPTR rp;
1672 : FILE *tmpfile;
1673 : char *name;
1674 : int printit;
1675 : {
1676 : char *cmnd;
1677 :
1678 0 : while( rp != NIL(STRING) ) {
1679 0 : Append_line(cmnd = Expand(rp->st_string), TRUE, tmpfile, name, printit,0);
1680 0 : FREE(cmnd);
1681 0 : rp = rp->st_next;
1682 : }
1683 0 : }
1684 :
1685 :
1686 : #define NUM_BUCKETS 20
1687 :
1688 : typedef struct strpool {
1689 : char *string; /* a pointer to the string value */
1690 : uint32 keyval; /* the strings hash value */
1691 : struct strpool *next; /* hash table link pointer */
1692 : } POOL, *POOLPTR;
1693 :
1694 : static POOLPTR strings[ NUM_BUCKETS ];
1695 :
1696 : static char *
1697 0 : _pool_lookup( str )/*
1698 : =====================
1699 : Scan down the list of chained strings and see if one of them matches
1700 : the string we are looking for. */
1701 : char *str;
1702 : {
1703 : register POOLPTR key;
1704 : uint32 keyval;
1705 : uint16 hv;
1706 : uint16 keyindex;
1707 : char *string;
1708 :
1709 : DB_ENTER( "_pool_lookup" );
1710 :
1711 0 : if( str == NIL(char) ) DB_RETURN("");
1712 :
1713 0 : hv = Hash(str, &keyval);
1714 0 : key = strings[ keyindex = (hv % NUM_BUCKETS) ];
1715 :
1716 0 : while( key != NIL(POOL) )
1717 0 : if( (key->keyval != keyval) || strcmp(str, key->string) )
1718 0 : key = key->next;
1719 : else
1720 : break;
1721 :
1722 0 : if( key == NIL(POOL) ) {
1723 : DB_PRINT( "pool", ("Adding string [%s]", str) );
1724 0 : TALLOC( key, 1, POOL ); /* not found so add string */
1725 :
1726 0 : key->string = string = DmStrDup(str);
1727 0 : key->keyval = keyval;
1728 :
1729 0 : key->next = strings[ keyindex ];
1730 0 : strings[ keyindex ] = key;
1731 : }
1732 : else {
1733 : DB_PRINT( "pool", ("Found string [%s], key->string") );
1734 0 : string = key->string;
1735 : }
1736 :
1737 0 : DB_RETURN( string );
1738 : }
1739 :
1740 :
1741 : void
1742 4 : Unmake( cp )/*
1743 : ==============
1744 : Remove flags indicating that a target was previously made. This
1745 : is used for infered makefiles. */
1746 : CELLPTR cp;
1747 : {
1748 : LINKPTR dp, ep;
1749 : CELLPTR tcp, pcp;
1750 :
1751 : DB_ENTER( "Unmake" );
1752 :
1753 8 : for(dp=CeMeToo(cp); dp; dp=dp->cl_next) {
1754 4 : tcp = dp->cl_prq;
1755 :
1756 : /* Unmake the prerequisites. */
1757 6 : for( ep = tcp->ce_prq; ep != NIL(LINK); ep = ep->cl_next ) {
1758 2 : pcp = ep->cl_prq;
1759 :
1760 2 : Unmake(pcp);
1761 : }
1762 : DB_PRINT( "unmake", ("Unmake [%s]", tcp->CE_NAME) );
1763 :
1764 4 : tcp->ce_flag &= ~(F_MADE|F_VISITED|F_STAT);
1765 4 : tcp->ce_time = (time_t)0L;
1766 : }
1767 :
1768 4 : DB_VOID_RETURN;
1769 : }
|