File: | dmake/make.c |
Location: | line 1726, column 7 |
Description: | Access to field 'string' results in a dereference of a null pointer (loaded from variable 'key') |
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))(HASHPTR); | |||
55 | static void _set_recipe ANSI((char*, int))(char*, int); | |||
56 | static void _set_tmd ANSI(())(); | |||
57 | static void _append_file ANSI((STRINGPTR, FILE*, char*, int))(STRINGPTR, FILE*, char*, int); | |||
58 | static LINKPTR _dup_prq ANSI((LINKPTR))(LINKPTR); | |||
59 | static LINKPTR _expand_dynamic_prq ANSI(( LINKPTR, LINKPTR, char * ))( LINKPTR, LINKPTR, char * ); | |||
60 | static char* _prefix ANSI((char *, char *))(char *, char *); | |||
61 | static char* _pool_lookup ANSI((char *))(char *); | |||
62 | static int _explode_graph ANSI((CELLPTR, LINKPTR, CELLPTR))(CELLPTR, LINKPTR, CELLPTR); | |||
63 | ||||
64 | ||||
65 | #define RP_GPPROLOG0 0 | |||
66 | #define RP_RECIPE1 1 | |||
67 | #define RP_GPEPILOG2 2 | |||
68 | #define NUM_RECIPES3 3 | |||
69 | ||||
70 | static STRINGPTR _recipes[NUM_RECIPES3]; | |||
71 | static LISTCELLPTR _freelist=NULL((void*)0); | |||
72 | ||||
73 | static LISTCELLPTR | |||
74 | get_cell() | |||
75 | { | |||
76 | LISTCELLPTR cell; | |||
77 | ||||
78 | if (!_freelist) { | |||
79 | if ((cell=MALLOC(1,LISTCELL)(LISTCELL*) malloc((unsigned int)(1)*(size_t)sizeof(LISTCELL) )) == NULL((void*)0)) | |||
80 | No_ram(); | |||
81 | } | |||
82 | else { | |||
83 | cell = _freelist; | |||
84 | _freelist = cell->next; | |||
85 | } | |||
86 | ||||
87 | return(cell); | |||
88 | } | |||
89 | ||||
90 | ||||
91 | static void | |||
92 | free_cell(LISTCELLPTR cell) | |||
93 | { | |||
94 | cell->next = _freelist; | |||
95 | _freelist = cell; | |||
96 | } | |||
97 | ||||
98 | ||||
99 | static void | |||
100 | free_list(LISTCELLPTR c) | |||
101 | { | |||
102 | if(c) { | |||
103 | free_list(c->next); | |||
104 | free_cell(c); | |||
105 | } | |||
106 | } | |||
107 | ||||
108 | ||||
109 | static void | |||
110 | list_init(LISTSTRINGPTR s) | |||
111 | { | |||
112 | s->first = NULL((void*)0); | |||
113 | s->last = NULL((void*)0); | |||
114 | s->len = 0; | |||
115 | } | |||
116 | ||||
117 | ||||
118 | static void | |||
119 | list_add(LISTSTRINGPTR s, char *str) | |||
120 | { | |||
121 | LISTCELLPTR p; | |||
122 | int l; | |||
123 | ||||
124 | if ((l = strlen(str)) == 0) | |||
125 | return; | |||
126 | ||||
127 | p = get_cell(); | |||
128 | p->datum = str; | |||
129 | p->next = NULL((void*)0); | |||
130 | p->len = l; | |||
131 | ||||
132 | if(s->first == NULL((void*)0)) | |||
133 | s->first = p; | |||
134 | else | |||
135 | s->last->next = p; | |||
136 | ||||
137 | s->last = p; | |||
138 | s->len += l+1; | |||
139 | } | |||
140 | ||||
141 | ||||
142 | static char * | |||
143 | 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 | if( (slen_rest = slen = s->len) == 0) | |||
156 | return(NIL(char)((char*)((void*)0))); | |||
157 | ||||
158 | /* reserve enough space to hold the concated original filenames. */ | |||
159 | if((p = result = MALLOC(slen, char)(char*) malloc((unsigned int)(slen)*(size_t)sizeof(char))) == NULL((void*)0)) No_ram(); | |||
160 | ||||
161 | for (cell=s->first; cell; cell=next) { | |||
162 | #if !defined(__CYGWIN__) | |||
163 | tpath = cell->datum; | |||
164 | 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)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((void*)0)) | |||
184 | No_ram(); | |||
185 | p = result + p_offset; | |||
186 | } | |||
187 | #endif | |||
188 | ||||
189 | memcpy((void *)p, (void *)tpath, len); | |||
190 | p += len; | |||
191 | *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 | next = cell->next; | |||
199 | free_cell(cell); | |||
200 | } | |||
201 | ||||
202 | *--p = '\0'; | |||
203 | list_init(s); | |||
204 | ||||
205 | return(result); | |||
206 | } | |||
207 | ||||
208 | ||||
209 | PUBLIC int | |||
210 | Make_targets()/* | |||
211 | ================ | |||
212 | Actually go and make the targets on the target list */ | |||
213 | { | |||
214 | LINKPTR lp; | |||
215 | int done = 0; | |||
216 | ||||
217 | DB_ENTER( "Make_targets" ); | |||
218 | ||||
219 | Read_state(); | |||
220 | _set_recipe( ".GROUPPROLOG", RP_GPPROLOG0 ); | |||
221 | _set_recipe( ".GROUPEPILOG", RP_GPEPILOG2 ); | |||
222 | ||||
223 | /* Prevent recipe inference for .ROOT */ | |||
224 | if ( Root->ce_recipe == NIL(STRING)((STRING*)((void*)0)) ) { | |||
225 | TALLOC( Root->ce_recipe, 1, STRING )if ((Root->ce_recipe = (STRING*) calloc((unsigned int)(1), (size_t)sizeof(STRING))) == (STRING*)0) {No_ram();}; | |||
226 | Root->ce_recipe->st_string = ""; | |||
227 | } | |||
228 | ||||
229 | /* Prevent recipe inference for .TARGETS */ | |||
230 | if ( Targets->ce_recipe == NIL(STRING)((STRING*)((void*)0)) ) { | |||
231 | TALLOC( Targets->ce_recipe, 1, STRING )if ((Targets->ce_recipe = (STRING*) calloc((unsigned int)( 1), (size_t)sizeof(STRING))) == (STRING*)0) {No_ram();}; | |||
232 | Targets->ce_recipe->st_string = ""; | |||
233 | } | |||
234 | ||||
235 | /* Make sure that user defined targets are marked as root targets */ | |||
236 | for( lp = Targets->ce_prq; lp != NIL(LINK)((LINK*)((void*)0)); lp = lp->cl_next ) | |||
237 | lp->cl_prq->ce_attr |= A_ROOT0x01000000; | |||
238 | ||||
239 | while( !done ) { | |||
240 | int rval; | |||
241 | ||||
242 | if( (rval = Make(Root, NIL(CELL)((CELL*)((void*)0)))) == -1 ) | |||
243 | DB_RETURN(1)return (1); | |||
244 | else | |||
245 | done = Root->ce_flag & F_MADE0x8000; | |||
246 | ||||
247 | if( !rval && !done ) Wait_for_child( FALSE0, -1 ); | |||
248 | } | |||
249 | ||||
250 | for( lp = Targets->ce_prq; lp != NIL(LINK)((LINK*)((void*)0)); lp = lp->cl_next ) { | |||
251 | CELLPTR tgt = lp->cl_prq; | |||
252 | if( !(tgt->ce_attr & A_UPDATED0x800000) | |||
253 | && (Verbose & V_MAKE0x10) ) | |||
254 | printf( "`%s' is up to date\n", tgt->CE_NAMEce_name->ht_name ); | |||
255 | } | |||
256 | ||||
257 | DB_RETURN( 0 )return (0); | |||
258 | } | |||
259 | ||||
260 | ||||
261 | ||||
262 | PUBLIC int | |||
263 | 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 | char *all = NIL(char)((char*)((void*)0)); | |||
277 | char *inf = NIL(char)((char*)((void*)0)); | |||
278 | char *outall = NIL(char)((char*)((void*)0)); | |||
279 | char *imm = NIL(char)((char*)((void*)0)); | |||
280 | int rval = 0; /* 0==ready, 1==target still running, -1==error */ | |||
281 | int push = 0; | |||
282 | int made = F_MADE0x8000; | |||
283 | int ignore; | |||
284 | time_t otime = (time_t) 1L; /* Hold time of newest prerequisite. */ | |||
285 | int mark_made = FALSE0; | |||
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 | m_q = m_b = m_g = m_l = m_bb = m_up = NIL(HASH)((HASH*)((void*)0)); | |||
298 | list_init(&all_list); | |||
299 | list_init(&imm_list); | |||
300 | list_init(&outall_list); | |||
301 | list_init(&inf_list); | |||
302 | ||||
303 | if (cp->ce_set && cp->ce_set != cp) { | |||
304 | if( Verbose & V_MAKE0x10 ) | |||
305 | printf( "%s: Building .UPDATEALL representative [%s]\n", Pname, | |||
306 | cp->ce_set->CE_NAMEce_name->ht_name ); | |||
307 | 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 | nsetdirroot = setdirroot; | |||
315 | ignore = (((cp->ce_attr|Glob_attr)&A_IGNORE0x00020) != 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 | UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH0x01000) != 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 | m_at = Def_macro("@", DO_WINPATH(cp->ce_fname)cp->ce_fname, M_MULTI0x0004); | |||
328 | ||||
329 | if( cp->ce_attr & A_SETDIR0x00400 ) { | |||
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 | if( (setdirroot == NIL(CELL)((CELL*)((void*)0)) || setdirroot->ce_dir != cp->ce_dir) && | |||
335 | (push = Push_dir(cp->ce_dir,cp->CE_NAMEce_name->ht_name,ignore)) != 0 ) | |||
336 | 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 | if( cp->ce_recipe == NIL(STRING)((STRING*)((void*)0)) ) { | |||
346 | char *dir = cp->ce_dir; | |||
347 | ||||
348 | if( Verbose & V_MAKE0x10 ) | |||
349 | printf( "%s: Infering prerequisite(s) and recipe for [%s]\n", Pname, | |||
350 | cp->CE_NAMEce_name->ht_name ); | |||
351 | ||||
352 | Infer_recipe( cp, setdirroot ); | |||
353 | ||||
354 | /* See if the directory has changed, if it has then make sure we | |||
355 | * push it. */ | |||
356 | if( dir != cp->ce_dir ) { | |||
357 | if( push ) Pop_dir(FALSE0); | |||
358 | push = Push_dir( cp->ce_dir, cp->CE_NAMEce_name->ht_name, ignore ); | |||
359 | setdirroot = cp; | |||
360 | } | |||
361 | } | |||
362 | ||||
363 | for(dp=CeMeToo(cp)&((cp)->ce_all); dp; dp=dp->cl_next) { | |||
364 | tcp = dp->cl_prq; | |||
365 | 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 | if( !(tcp->ce_attr & A_POOL0x08000000) && tcp->ce_dir ) FREE( tcp->ce_dir )free((char*)(tcp->ce_dir)); | |||
369 | tcp->ce_dir = _pool_lookup(Pwd); | |||
370 | tcp->ce_attr |= A_SETDIR0x00400|A_POOL0x08000000; | |||
371 | } | |||
372 | 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 | if( !(cp->ce_flag & F_STAT0x0040) && !(cp->ce_attr&A_PHONY0x04000) ) { | |||
378 | if (cp->ce_parent && (cp->ce_parent->ce_flag & F_MULTI0x0002)) { | |||
379 | /* Inherit the stat info from the F_MULTI parent. */ | |||
380 | cp->ce_time = cp->ce_parent->ce_time; | |||
381 | cp->ce_flag |= F_STAT0x0040; | |||
382 | /* Propagate the A_PRECIOUS attribute from the parent. */ | |||
383 | cp->ce_attr |= cp->ce_parent->ce_attr & A_PRECIOUS0x00001; | |||
384 | } | |||
385 | else { | |||
386 | for(dp=CeMeToo(cp)&((cp)->ce_all); dp; dp=dp->cl_next) { | |||
387 | tcp = dp->cl_prq; | |||
388 | /* Check if target already exists. */ | |||
389 | Stat_target( tcp, 1, FALSE0 ); | |||
390 | ||||
391 | if( tcp->ce_time != (time_t)0L ) { | |||
392 | /* File exists so don't remove it later. */ | |||
393 | tcp->ce_attr |= A_PRECIOUS0x00001; | |||
394 | } | |||
395 | ||||
396 | if( Verbose & V_MAKE0x10 ) | |||
397 | printf("%s: Time stamp of [%s] is %ld\n",Pname,tcp->CE_NAMEce_name->ht_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 | if( !(cp->ce_flag & F_TARGET0x0008) && (cp->ce_time == (time_t) 0L) ) { | |||
408 | if( Makemkf ) { | |||
409 | rval = -1; | |||
410 | goto stop_making_it; | |||
411 | } | |||
412 | else if( cp->ce_prq != NIL(LINK)((LINK*)((void*)0)) | |||
413 | || (STOBOOL(Augmake)(Augmake && ((*Augmake | 0x20) == 'y')) && (cp->ce_flag&F_EXPLICIT0x0400))) | |||
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 | cp->ce_flag |= F_RULES0x0010; | |||
418 | else | |||
419 | Fatal( "`%s' not found, and can't be made", cp->CE_NAMEce_name->ht_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 | if( cp->ce_per == NIL(char)((char*)((void*)0)) ) 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 | if ( cp->ce_prqorg == NIL(LINK)((LINK*)((void*)0)) ) { | |||
431 | for( dp = cp->ce_prq; dp != NIL(LINK)((LINK*)((void*)0)); dp = dp->cl_next ) | |||
432 | if ( strchr(dp->cl_prq->CE_NAMEce_name->ht_name, '$') != NULL((void*)0) ) | |||
433 | break; | |||
434 | ||||
435 | if (dp != NIL(LINK)((LINK*)((void*)0))) { | |||
436 | 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 | m_at = Def_macro("@", DO_WINPATH(cp->ce_fname)cp->ce_fname, M_MULTI0x0004); | |||
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 | for(dp=CeMeToo(cp)&((cp)->ce_all); dp; dp=dp->cl_next) { | |||
450 | tcp=dp->cl_prq; | |||
451 | if (tcp->ce_cond != NIL(STRING)((STRING*)((void*)0))) { | |||
452 | STRINGPTR sp; | |||
453 | ||||
454 | tcp->ce_pushed = NIL(HASH)((HASH*)((void*)0)); | |||
455 | for(sp=tcp->ce_cond; sp; sp=sp->st_next) { | |||
456 | if(Parse_macro(sp->st_string,M_MULTI0x0004|M_PUSH0x0100)) { | |||
457 | HASHPTR hp; | |||
458 | ||||
459 | hp = GET_MACRO(LastMacName)Get_name(LastMacName, Macs, 0); | |||
460 | hp->ht_link = tcp->ce_pushed; | |||
461 | tcp->ce_pushed = hp; | |||
462 | } | |||
463 | else { | |||
464 | 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 | for( prev=NULL((void*)0),dp=cp->ce_prq; dp != NIL(LINK)((LINK*)((void*)0)); 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 | if (m_at->ht_value == NIL(char)((char*)((void*)0))) { | |||
480 | /* This check effectively tests if Make() was run before because | |||
481 | * Make() frees all dynamic macro values at the end. */ | |||
482 | UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH0x01000) != 0); | |||
483 | m_at = Def_macro("@", DO_WINPATH(cp->ce_fname)cp->ce_fname, M_MULTI0x0004); | |||
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 | next = dp->cl_next; | |||
491 | ||||
492 | tcp = dp->cl_prq; | |||
493 | if( Verbose & V_MAKE0x10 ) | |||
494 | printf("Checking prerequisite [%s]\n", tcp->CE_NAMEce_name->ht_name); | |||
495 | ||||
496 | seq = (((cp->ce_attr | Glob_attr) & A_SEQ0x00200) != 0); | |||
497 | ||||
498 | /* This checks if this prerequisite is still in the making, if yes | |||
499 | * come back later. */ | |||
500 | if( tcp->ce_flag & F_VISITED0x0080 ) { | |||
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 | if( _explode_graph(tcp, dp, setdirroot) == 0 ) { | |||
505 | /* didn't blow it up so see if we need to wait for it. */ | |||
506 | if( tcp->ce_flag & F_MADE0x8000 ) { | |||
507 | /* Target was made. */ | |||
508 | continue; | |||
509 | } | |||
510 | else | |||
511 | /* Target is still in the making ... */ | |||
512 | goto stop_making_it; | |||
513 | } | |||
514 | else | |||
515 | /* Use the new prerequisite with the new .SETDIR value. */ | |||
516 | tcp = dp->cl_prq; | |||
517 | } | |||
518 | ||||
519 | /* If the previous target (prereq) is not yet ready return if | |||
520 | * seq is TRUE. */ | |||
521 | 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 | if ( tcp && !(tcp->ce_flag & F_MARK0x0001) && strchr(tcp->CE_NAMEce_name->ht_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 | name = Expand( tcp->CE_NAMEce_name->ht_name ); | |||
532 | if( strcmp(name,cp->CE_NAMEce_name->ht_name) == 0 ) | |||
533 | 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 | dp = _expand_dynamic_prq( cp->ce_prq, dp, name ); | |||
540 | FREE( name )free((char*)(name)); | |||
541 | ||||
542 | /* _expand_dynamic_prq() probably changed dp->cl_prq. */ | |||
543 | tcp = dp->cl_prq; | |||
544 | if ( tcp ) { | |||
545 | 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 | if ( tcp == NIL(CELL)((CELL*)((void*)0)) ) { | |||
553 | FREE(dp)free((char*)(dp)); | |||
554 | if ( prev == NIL(LINK)((LINK*)((void*)0)) ) { | |||
555 | cp->ce_prq = next; | |||
556 | dp = NULL((void*)0); /* dp will be the new value of prev. */ | |||
557 | } | |||
558 | else { | |||
559 | prev->cl_next = next; | |||
560 | dp = prev; | |||
561 | } | |||
562 | continue; | |||
563 | } | |||
564 | ||||
565 | /* Clear F_MARK flag that could have been set by _expand_dynamic_prq(). */ | |||
566 | tcp->ce_flag &= ~(F_MARK0x0001); | |||
567 | ||||
568 | if( cp->ce_attr & A_LIBRARY0x00004 ) { | |||
569 | tcp->ce_attr |= A_LIBRARYM0x80000; | |||
570 | tcp->ce_lib = cp->ce_fname; | |||
571 | } | |||
572 | ||||
573 | /* Propagate the parent's F_REMOVE and F_INFER flags to the | |||
574 | * prerequisites. */ | |||
575 | tcp->ce_flag |= cp->ce_flag & (F_REMOVE0x1000|F_INFER0x4000); | |||
576 | ||||
577 | /* Propagate parents A_ROOT attribute to a child if the parent is a | |||
578 | * F_MULTI target. */ | |||
579 | if( (cp->ce_flag & F_MULTI0x0002) && (cp->ce_attr & A_ROOT0x01000000) ) | |||
580 | tcp->ce_attr |= A_ROOT0x01000000; | |||
581 | ||||
582 | tcp->ce_parent = cp; | |||
583 | rval |= Make(tcp, setdirroot); | |||
584 | ||||
585 | if( cp->ce_attr & A_LIBRARY0x00004 ) | |||
586 | tcp->ce_attr ^= A_LIBRARYM0x80000; | |||
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 | if( rval == -1 || (seq && (rval==1)) ) | |||
591 | goto stop_making_it; | |||
592 | ||||
593 | /* If tcp is ready, set made = F_MADE. */ | |||
594 | made &= tcp->ce_flag & F_MADE0x8000; | |||
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 | for( dp = cp->ce_prq; dp != NIL(LINK)((LINK*)((void*)0)); dp = dp->cl_next ) { | |||
603 | int tgflg; | |||
604 | tcp = dp->cl_prq; | |||
605 | if( tcp == NIL(CELL)((CELL*)((void*)0)) ) | |||
606 | Fatal("Internal Error: Found prerequisite list cell without prerequisite!"); | |||
607 | ||||
608 | name = tcp->ce_fname; | |||
609 | ||||
610 | /* make certain that all prerequisites are made prior to advancing. */ | |||
611 | if( !(tcp->ce_flag & F_MADE0x8000) ) 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 | if( cp->ce_attr & A_LIBRARY0x00004 ) | |||
618 | if( tcp->ce_time <= cp->ce_time ) { | |||
619 | time_t mtime = Do_stat( name, tcp->ce_lib, NIL(char *)((char **)((void*)0)), FALSE0 ); | |||
620 | 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 | if( tcp->ce_time > otime ) otime = tcp->ce_time; | |||
626 | ||||
627 | list_add(&all_list, name); | |||
628 | if( (tgflg = (dp->cl_flag & F_TARGET0x0008)) != 0 ) | |||
629 | list_add(&inf_list, name); | |||
630 | ||||
631 | if((cp->ce_time<tcp->ce_time) || ((tcp->ce_flag & F_TARGET0x0008) && Force)) { | |||
632 | list_add(&outall_list, name); | |||
633 | if( tgflg ) | |||
634 | 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 | if( (cp->ce_flag & F_MULTI0x0002) ) | |||
641 | 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 | if (m_at->ht_value == NIL(char)((char*)((void*)0))) { | |||
647 | /* This check effectively tests if Make() was run before because | |||
648 | * Make() frees all dynamic macro values at the end. */ | |||
649 | UseWinpath = (((cp->ce_attr|Glob_attr)&A_WINPATH0x01000) != 0); | |||
650 | m_at = Def_macro("@", DO_WINPATH(cp->ce_fname)cp->ce_fname, M_MULTI0x0004); | |||
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 | all = gen_path_list_string(&all_list); | |||
657 | imm = gen_path_list_string(&imm_list); | |||
658 | outall = gen_path_list_string(&outall_list); | |||
659 | 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 | if( Verbose & V_MAKE0x10 ) { | |||
666 | printf( "%s: >>>> Making ", Pname ); | |||
667 | /* Also print the F_MULTI master target. */ | |||
668 | if( cp->ce_flag & F_MULTI0x0002 ) | |||
669 | printf( "(::-\"master\" target) " ); | |||
670 | if( cp->ce_count != 0 ) | |||
671 | printf( "[%s::{%d}]\n", cp->CE_NAMEce_name->ht_name, cp->ce_count ); | |||
672 | else | |||
673 | printf( "[%s]\n", cp->CE_NAMEce_name->ht_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_FORCE0x0080 | M_EXPANDED0x0008 ); | |||
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_FORCE0x0080 | M_EXPANDED0x0008 ); | |||
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 | m_bb = Def_macro( "*", DO_WINPATH(cp->ce_per)cp->ce_per, M_MULTI0x0004 ); | |||
699 | ||||
700 | /* This is expanded. */ | |||
701 | m_g = Def_macro( ">", DO_WINPATH(cp->ce_lib)cp->ce_lib, M_MULTI0x0004|M_EXPANDED0x0008 ); | |||
702 | /* These strings are generated with gen_path_list_string() and honor | |||
703 | * .WINPATH */ | |||
704 | m_q = Def_macro( "?", outall, M_MULTI0x0004|M_EXPANDED0x0008 ); | |||
705 | m_b = Def_macro( "<", inf, M_MULTI0x0004|M_EXPANDED0x0008 ); | |||
706 | m_l = Def_macro( "&", all, M_MULTI0x0004|M_EXPANDED0x0008 ); | |||
707 | m_up = Def_macro( "^", imm, M_MULTI0x0004|M_EXPANDED0x0008 ); | |||
708 | ||||
709 | _recipes[ RP_RECIPE1 ] = 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 | if( Check_state(cp, _recipes, NUM_RECIPES3 ) | |||
717 | || (cp->ce_time < otime) | |||
718 | || ((cp->ce_flag & F_TARGET0x0008) && Force) | |||
719 | ) { | |||
720 | ||||
721 | if( Measure & M_TARGET0x01 ) | |||
722 | Do_profile_output( "s", M_TARGET0x01, cp ); | |||
723 | ||||
724 | /* Only checking so stop as soon as we determine we will make | |||
725 | * something */ | |||
726 | if( Check ) { | |||
727 | rval = -1; | |||
728 | goto stop_making_it; | |||
729 | } | |||
730 | ||||
731 | if( Verbose & V_MAKE0x10 ) | |||
732 | printf( "%s: Updating [%s], (%ld > %ld)\n", Pname, | |||
733 | cp->CE_NAMEce_name->ht_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 | 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 | if( Touch ) { | |||
752 | name = cp->ce_fname; | |||
753 | lib = cp->ce_lib; | |||
754 | ||||
755 | if( (!(Glob_attr & A_SILENT0x00002) || !Trace) && !(cp->ce_attr & A_PHONY0x04000) ) { | |||
756 | if( lib == NIL(char)((char*)((void*)0)) ) | |||
757 | printf("touch(%s)", name ); | |||
758 | else if( cp->ce_attr & A_SYMBOL0x00040 ) | |||
759 | printf("touch(%s((%s)))", lib, name ); | |||
760 | else | |||
761 | printf("touch(%s(%s))", lib, name ); | |||
762 | } | |||
763 | ||||
764 | if( !Trace && !(cp->ce_attr & A_PHONY0x04000) ) | |||
765 | if( Do_touch( name, lib, | |||
766 | (cp->ce_attr & A_SYMBOL0x00040) ? &name : NIL(char *)((char **)((void*)0)) ) != 0 ) | |||
767 | printf( " not touched - non-existant" ); | |||
768 | ||||
769 | if( (!(Glob_attr & A_SILENT0x00002) || !Trace) && !(cp->ce_attr & A_PHONY0x04000) ) | |||
770 | printf( "\n" ); | |||
771 | ||||
772 | Update_time_stamp( cp ); | |||
773 | } | |||
774 | else if( cp->ce_recipe != NIL(STRING)((STRING*)((void*)0)) ) { | |||
775 | /* If a recipe is found use it. Note this misses F_MULTI targets. */ | |||
776 | if( !(cp->ce_flag & F_SINGLE0x0004) ) /* Execute the recipes once ... */ | |||
777 | 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 | _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 | if( outall && *outall ) { | |||
792 | /* Wait for each prerequisite to finish, save the status | |||
793 | * of Wait_for_completion. */ | |||
794 | int wait_for_completion_status = Wait_for_completion; | |||
795 | Wait_for_completion = TRUE1; | |||
796 | ||||
797 | SET_TOKEN( &tk, outall )(&tk)->tk_str = (outall); (&tk)->tk_cchar = *(outall ); (&tk)->tk_quote = 1;; | |||
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 | Doing_bang = TRUE1; | |||
803 | name = Get_token( &tk, "", FALSE0 ); | |||
804 | /* This loop might fail if outall contains filenames with | |||
805 | * spaces. */ | |||
806 | do { | |||
807 | /* Set $? to current prerequisite. */ | |||
808 | m_q->ht_value = name; | |||
809 | ||||
810 | rval = Exec_commands( cp ); | |||
811 | /* Thanks to Wait_for_completion = TRUE we are allowed | |||
812 | * to remove the temp files here. */ | |||
813 | Unlink_temp_files(cp); | |||
814 | } | |||
815 | while( *(name = Get_token( &tk, "", FALSE0 )) != '\0' ); | |||
816 | Wait_for_completion = wait_for_completion_status; | |||
817 | Doing_bang = FALSE0; | |||
818 | } | |||
819 | ||||
820 | Update_time_stamp( cp ); | |||
821 | /* Erase $? again. Don't free the pointer, it was part of outall. */ | |||
822 | m_q->ht_value = NIL(char)((char*)((void*)0)); | |||
823 | } | |||
824 | } | |||
825 | else if( !(cp->ce_flag & F_RULES0x0010) && !(cp->ce_flag & F_STAT0x0040) && | |||
826 | (!(cp->ce_attr & A_ROOT0x01000000) || !(cp->ce_flag & F_EXPLICIT0x0400)) && | |||
827 | !(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 | Fatal( "Don't know how to make `%s'",cp->CE_NAMEce_name->ht_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 | Update_time_stamp( cp ); | |||
838 | } | |||
839 | } | |||
840 | else { | |||
841 | if( Verbose & V_MAKE0x10 ) | |||
842 | printf( "%s: Up to date [%s], prq time = %ld , target time = %ld)\n", Pname, | |||
843 | cp->CE_NAMEce_name->ht_name, otime, cp->ce_time ); | |||
844 | mark_made = TRUE1; | |||
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 | for(dp=CeMeToo(cp)&((cp)->ce_all); dp; dp=dp->cl_next) { | |||
852 | 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 | if( !(tcp->ce_flag & F_TARGET0x0008) && Force ) tcp->ce_time = Do_time(); | |||
858 | if( mark_made ) { | |||
859 | tcp->ce_flag |= F_MADE0x8000; | |||
860 | if( tcp->ce_flag & F_MULTI0x0002 ) { | |||
861 | LINKPTR tdp; | |||
862 | for( tdp = tcp->ce_prq; tdp != NIL(LINK)((LINK*)((void*)0)); tdp = tdp->cl_next ) | |||
863 | tcp->ce_attr |= tdp->cl_prq->ce_attr & A_UPDATED0x800000; | |||
864 | } | |||
865 | } | |||
866 | ||||
867 | /* Note that the target is in the making. */ | |||
868 | tcp->ce_flag |= F_VISITED0x0080; | |||
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 | if( push ) { | |||
874 | 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 | char *pref = _prefix( dir, tcp->ce_dir ); | |||
879 | char *nname = Build_path(pref, tcp->ce_fname); | |||
880 | ||||
881 | FREE(pref)free((char*)(pref)); | |||
882 | if( (tcp->ce_attr & A_FFNAME0x400000) && (tcp->ce_fname != NIL(char)((char*)((void*)0))) ) | |||
883 | FREE( tcp->ce_fname )free((char*)(tcp->ce_fname)); | |||
884 | ||||
885 | tcp->ce_fname = DmStrDup(nname); | |||
886 | tcp->ce_attr |= A_FFNAME0x400000; | |||
887 | } | |||
888 | } | |||
889 | ||||
890 | stop_making_it: | |||
891 | _drop_mac( m_g ); | |||
892 | _drop_mac( m_q ); | |||
893 | _drop_mac( m_b ); | |||
894 | _drop_mac( m_l ); | |||
895 | _drop_mac( m_bb ); | |||
896 | _drop_mac( m_up ); | |||
897 | _drop_mac( m_at ); | |||
898 | ||||
899 | /* undefine conditional macros if any */ | |||
900 | for(dp=CeMeToo(cp)&((cp)->ce_all); dp; dp=dp->cl_next) { | |||
901 | tcp=dp->cl_prq; | |||
902 | ||||
903 | while (tcp->ce_pushed != NIL(HASH)((HASH*)((void*)0))) { | |||
904 | HASHPTR cur = tcp->ce_pushed; | |||
905 | tcp->ce_pushed = cur->ht_link; | |||
906 | ||||
907 | Pop_macro(cur); | |||
908 | FREE(cur->ht_name)free((char*)(cur->ht_name)); | |||
909 | if(cur->ht_value) | |||
910 | FREE(cur->ht_value)free((char*)(cur->ht_value)); | |||
911 | FREE(cur)free((char*)(cur)); | |||
912 | } | |||
913 | } | |||
914 | ||||
915 | if( push ) | |||
916 | Pop_dir(FALSE0); | |||
917 | ||||
918 | /* Undefine the strings that we used for constructing inferred | |||
919 | * prerequisites. */ | |||
920 | if( inf != NIL(char)((char*)((void*)0)) ) FREE( inf )free((char*)(inf)); | |||
921 | if( all != NIL(char)((char*)((void*)0)) ) FREE( all )free((char*)(all)); | |||
922 | if( imm != NIL(char)((char*)((void*)0)) ) FREE( imm )free((char*)(imm)); | |||
923 | if( outall != NIL(char)((char*)((void*)0)) ) FREE( outall )free((char*)(outall)); | |||
924 | free_list(all_list.first); | |||
925 | free_list(imm_list.first); | |||
926 | free_list(outall_list.first); | |||
927 | free_list(inf_list.first); | |||
928 | ||||
929 | DB_PRINT( "mem", ("%s:-< mem %ld", cp->CE_NAME, (long) coreleft()) ); | |||
930 | DB_RETURN(rval)return (rval); | |||
931 | } | |||
932 | ||||
933 | ||||
934 | static char * | |||
935 | _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 | char *cmp1=pfx; | |||
945 | char *cmp2=pat; | |||
946 | char *tpat=pat; /* Keep pointer to original pat. */ | |||
947 | char *result; | |||
948 | char *up; | |||
949 | int first = 1; | |||
950 | 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 | if( strcmp(pfx, pat) == 0 ) | |||
958 | 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)((*__ctype_b_loc ())[(int) ((*pfx))] & (unsigned short int ) _ISalpha) ) { | |||
964 | pfxdl = 1; | |||
965 | cmp1 = DmStrSpn(pfx+2, DirBrkStr); | |||
966 | } | |||
967 | if( *pat && pat[1] == ':' && isalpha(*pat)((*__ctype_b_loc ())[(int) ((*pat))] & (unsigned short int ) _ISalpha) ) { | |||
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 | while(*pfx && *pat) { | |||
993 | /* skip leading dir. separators. */ | |||
994 | pfx = DmStrSpn(cmp1, DirBrkStr); | |||
995 | 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 | if( first ) { | |||
1003 | if( cmp1-pfx != cmp2-pat ) { | |||
1004 | return(DmStrDup(tpat)); | |||
1005 | } | |||
1006 | first = 0; | |||
1007 | } | |||
1008 | ||||
1009 | /* find next dir. separator (or ""). */ | |||
1010 | cmp1 = DmStrPbrk(pfx, DirBrkStr); | |||
1011 | 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 | if ( (cmp1-pfx) != (cmp2-pat) || strncmp(pfx,pat,cmp1-pfx) != 0 ) { | |||
1018 | if( samerootdir ) { | |||
1019 | return(DmStrDup(tpat)); | |||
1020 | } | |||
1021 | break; | |||
1022 | } | |||
1023 | ||||
1024 | 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 | samerootdir = 0; | |||
1034 | } | |||
1035 | } | |||
1036 | ||||
1037 | result = DmStrDup(""); | |||
1038 | up = DmStrJoin("..",DirSepStr,-1,FALSE0); | |||
1039 | cmp1 = pfx; | |||
1040 | /* Add "../" for each directory in pfx */ | |||
1041 | while ( *(pfx=DmStrSpn(cmp1,DirBrkStr)) != '\0' ) { | |||
1042 | cmp1 = DmStrPbrk(pfx,DirBrkStr); | |||
1043 | result = DmStrJoin(result,up,-1,TRUE1); | |||
1044 | } | |||
1045 | FREE(up)free((char*)(up)); | |||
1046 | ||||
1047 | pat = DmStrSpn(pat,DirBrkStr); | |||
1048 | /* Append pat to result. */ | |||
1049 | if( *pat != '\0' ) { | |||
1050 | cmp2 = DmStrDup(Build_path(result, pat)); | |||
1051 | FREE(result)free((char*)(result)); | |||
1052 | result = cmp2; | |||
1053 | } else { | |||
1054 | /* if pat is empty and result exists remove the trailing slash | |||
1055 | * from the last "../". */ | |||
1056 | if( *result ) { | |||
1057 | result[strlen(result)-1] = '\0'; | |||
1058 | } | |||
1059 | } | |||
1060 | ||||
1061 | return(result); | |||
1062 | } | |||
1063 | ||||
1064 | ||||
1065 | static LINKPTR | |||
1066 | _dup_prq( lp ) | |||
1067 | LINKPTR lp; | |||
1068 | { | |||
1069 | LINKPTR tlp; | |||
1070 | ||||
1071 | if( lp == NIL(LINK)((LINK*)((void*)0)) ) return(lp); | |||
1072 | ||||
1073 | TALLOC(tlp, 1, LINK)if ((tlp = (LINK*) calloc((unsigned int)(1), (size_t)sizeof(LINK ))) == (LINK*)0) {No_ram();}; | |||
1074 | tlp->cl_prq = lp->cl_prq; | |||
1075 | tlp->cl_flag = lp->cl_flag; | |||
1076 | tlp->cl_next = _dup_prq( lp->cl_next ); | |||
1077 | ||||
1078 | return(tlp); | |||
1079 | } | |||
1080 | ||||
1081 | ||||
1082 | static LINKPTR | |||
1083 | _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 | CELLPTR cur = lp->cl_prq; | |||
1095 | ||||
1096 | if( !(*name) ) { | |||
1097 | /* If name is empty this leaves lp->cl_prq unchanged -> No prerequisite added. */ | |||
1098 | ; | |||
1099 | } | |||
1100 | else if ( strchr(name, ' ') == NIL(char)((char*)((void*)0)) ) { | |||
1101 | /* If condition above is true, no space is found. */ | |||
1102 | CELLPTR prq = Def_cell(name); | |||
1103 | LINKPTR tmp; | |||
1104 | ||||
1105 | /* Check if prq already exists. */ | |||
1106 | for(tmp=head;tmp != NIL(LINK)((LINK*)((void*)0)) && 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 | if ( !tmp ) { | |||
1110 | /* replace the prerequisite with the expanded version. */ | |||
1111 | lp->cl_prq = prq; | |||
1112 | lp->cl_prq->ce_flag |= F_MARK0x0001; | |||
1113 | } | |||
1114 | } | |||
1115 | else { | |||
1116 | LINKPTR tlp = lp; | |||
1117 | LINKPTR next = lp->cl_next; | |||
1118 | TKSTR token; | |||
1119 | char *p; | |||
1120 | int first=TRUE1; | |||
1121 | ||||
1122 | /* Handle more than one prerequisite. */ | |||
1123 | SET_TOKEN(&token, name)(&token)->tk_str = (name); (&token)->tk_cchar = *(name); (&token)->tk_quote = 1;; | |||
1124 | while (*(p=Get_token(&token, "", FALSE0)) != '\0') { | |||
1125 | CELLPTR prq = Def_cell(p); | |||
1126 | LINKPTR tmp; | |||
1127 | ||||
1128 | for(tmp=head;tmp != NIL(LINK)((LINK*)((void*)0)) && tmp->cl_prq != prq;tmp=tmp->cl_next); | |||
1129 | ||||
1130 | /* If tmp is not NULL the prerequisite already exists. */ | |||
1131 | if ( tmp ) continue; | |||
1132 | ||||
1133 | /* Add list elements behind the first if more then one new | |||
1134 | * prerequisite is found. */ | |||
1135 | if ( first ) { | |||
1136 | first = FALSE0; | |||
1137 | } | |||
1138 | else { | |||
1139 | TALLOC(tlp->cl_next,1,LINK)if ((tlp->cl_next = (LINK*) calloc((unsigned int)(1), (size_t )sizeof(LINK))) == (LINK*)0) {No_ram();}; | |||
1140 | tlp = tlp->cl_next; | |||
1141 | tlp->cl_flag |= F_TARGET0x0008; | |||
1142 | tlp->cl_next = next; | |||
1143 | } | |||
1144 | ||||
1145 | tlp->cl_prq = prq; | |||
1146 | tlp->cl_prq->ce_flag |= F_MARK0x0001; | |||
1147 | } | |||
1148 | CLEAR_TOKEN( &token )*(&token)->tk_str = (&token)->tk_cchar; | |||
1149 | } | |||
1150 | ||||
1151 | /* If the condition is true no new prerequisits were found. */ | |||
1152 | if ( lp->cl_prq == cur ) { | |||
1153 | lp->cl_prq = NIL(CELL)((CELL*)((void*)0)); | |||
1154 | lp->cl_flag = 0; | |||
1155 | } | |||
1156 | ||||
1157 | /* Is returned unchanged. */ | |||
1158 | return(lp); | |||
1159 | } | |||
1160 | ||||
1161 | ||||
1162 | static void | |||
1163 | _drop_mac( hp )/* | |||
1164 | ================ set a macro value to zero. */ | |||
1165 | HASHPTR hp; | |||
1166 | { | |||
1167 | if( hp && hp->ht_value != NIL(char)((char*)((void*)0)) ) { | |||
1168 | FREE( hp->ht_value )free((char*)(hp->ht_value)); | |||
1169 | hp->ht_value = NIL(char)((char*)((void*)0)); | |||
1170 | } | |||
1171 | } | |||
1172 | ||||
1173 | ||||
1174 | ||||
1175 | static int | |||
1176 | _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)((CELL*)((void*)0)); | |||
1188 | ||||
1189 | if ( removecell == NIL(CELL)((CELL*)((void*)0)) ) | |||
1190 | 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 | if ( setdirroot == removecell ) | |||
1199 | return( 0 ); | |||
1200 | ||||
1201 | if( cp->ce_setdir == setdirroot && | |||
1202 | !((cp->ce_attr & A_LIBRARYM0x80000) && (cp->ce_lib != NIL(char)((char*)((void*)0)))) ) | |||
1203 | 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 | if( cp->ce_setdir != NIL(CELL)((CELL*)((void*)0)) && | |||
1211 | setdirroot != NIL(CELL)((CELL*)((void*)0)) && | |||
1212 | cp->ce_dir && | |||
1213 | setdirroot->ce_dir && | |||
1214 | !strcmp(cp->ce_dir, setdirroot->ce_dir) ) | |||
1215 | return( 0 ); | |||
1216 | ||||
1217 | if( Max_proc > 1 ) { | |||
1218 | LINKPTR dp; | |||
1219 | ||||
1220 | TALLOC(parent->cl_prq, 1, CELL)if ((parent->cl_prq = (CELL*) calloc((unsigned int)(1), (size_t )sizeof(CELL))) == (CELL*)0) {No_ram();}; | |||
1221 | *parent->cl_prq = *cp; | |||
1222 | cp = parent->cl_prq; | |||
1223 | cp->ce_prq = _dup_prq(cp->ce_prqorg); | |||
1224 | cp->ce_all.cl_prq = cp; | |||
1225 | CeNotMe(cp)(cp)->ce_all.cl_next = _dup_prq(CeNotMe(cp)(cp)->ce_all.cl_next); | |||
1226 | ||||
1227 | for(dp=CeNotMe(cp)(cp)->ce_all.cl_next;dp;dp=dp->cl_next) { | |||
1228 | CELLPTR tcp = dp->cl_prq; | |||
1229 | TALLOC(dp->cl_prq,1,CELL)if ((dp->cl_prq = (CELL*) calloc((unsigned int)(1), (size_t )sizeof(CELL))) == (CELL*)0) {No_ram();}; | |||
1230 | *dp->cl_prq = *tcp; | |||
1231 | dp->cl_prq->ce_flag &= ~(F_STAT0x0040|F_VISITED0x0080|F_MADE0x8000); | |||
1232 | dp->cl_prq->ce_set = cp; | |||
1233 | } | |||
1234 | } | |||
1235 | cp->ce_flag &= ~(F_STAT0x0040|F_VISITED0x0080|F_MADE0x8000); | |||
1236 | ||||
1237 | /* Indicate that we exploded the graph and that the current node should | |||
1238 | * be made. */ | |||
1239 | return(1); | |||
1240 | } | |||
1241 | ||||
1242 | ||||
1243 | ||||
1244 | PUBLIC int | |||
1245 | 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)((HASH*)((void*)0)); | |||
1268 | static HASHPTR command = NIL(HASH)((HASH*)((void*)0)); | |||
1269 | static int read_cmnd = 0; | |||
1270 | register STRINGPTR rp; | |||
1271 | STRINGPTR orp; | |||
1272 | char *cmnd; | |||
1273 | char *groupfile; | |||
1274 | FILE *tmpfile = 0; | |||
1275 | int do_it; | |||
1276 | t_attr attr; | |||
1277 | int group; | |||
1278 | int trace; | |||
1279 | int rval = 0; | |||
1280 | ||||
1281 | DB_ENTER( "Exec_commands" ); | |||
1282 | ||||
1283 | if( cp->ce_recipe == NIL(STRING)((STRING*)((void*)0)) ) | |||
1284 | Fatal("Internal Error: No recipe found!"); | |||
1285 | ||||
1286 | attr = Glob_attr | cp->ce_attr; | |||
1287 | trace = Trace || !(attr & A_SILENT0x00002); | |||
1288 | group = cp->ce_flag & F_GROUP0x0020; | |||
1289 | ||||
1290 | /* Do it again here for those that call us from places other than Make() | |||
1291 | * above. */ | |||
1292 | orp = _recipes[ RP_RECIPE1 ]; | |||
1293 | _recipes[ RP_RECIPE1 ] = cp->ce_recipe; | |||
1294 | ||||
1295 | 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 | Current_target = cp; | |||
1300 | trace = Trace || !(attr & A_SILENT0x00002); | |||
1301 | ||||
1302 | if( !Trace ) tmpfile = Start_temp( Grp_suff, cp, &groupfile ); | |||
1303 | if( trace ) fputs( "[\n", stdoutstdout ); | |||
1304 | ||||
1305 | /* Emit group prolog */ | |||
1306 | if( attr & A_PROLOG0x00010 ) | |||
1307 | _append_file( _recipes[RP_GPPROLOG0], tmpfile, cp->CE_NAMEce_name->ht_name, trace ); | |||
1308 | } | |||
1309 | ||||
1310 | if( !useshell ) | |||
1311 | useshell=Def_macro("USESHELL",NIL(char)((char*)((void*)0)),M_MULTI0x0004|M_EXPANDED0x0008); | |||
1312 | ||||
1313 | if( !read_cmnd ) { | |||
1314 | command = GET_MACRO("COMMAND")Get_name("COMMAND", Macs, 0); | |||
1315 | read_cmnd = 1; | |||
1316 | } | |||
1317 | ||||
1318 | /* Process commands in recipe. If in group, merely append to file. | |||
1319 | * Otherwise, run them. */ | |||
1320 | for( rp=_recipes[RP_RECIPE1]; rp != NIL(STRING)((STRING*)((void*)0)); rp=rp->st_next) { | |||
1321 | t_attr a_attr = A_DEFAULT0x00000; | |||
1322 | t_attr l_attr; | |||
1323 | char *p; | |||
1324 | int new_attr = FALSE0; | |||
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 | 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 | if( *rp->st_string == '$' && !group ) { | |||
1336 | t_attr s_attr = Glob_attr; | |||
1337 | Glob_attr |= A_SILENT0x00002; | |||
1338 | Suppress_temp_file = TRUE1; | |||
1339 | cmnd = Expand(rp->st_string); | |||
1340 | Suppress_temp_file = FALSE0; | |||
1341 | a_attr |= Rcp_attribute(cmnd); | |||
1342 | FREE(cmnd)free((char*)(cmnd)); | |||
1343 | ++new_attr; | |||
1344 | Glob_attr = s_attr; | |||
1345 | } | |||
1346 | ||||
1347 | l_attr = attr|a_attr|rp->st_attr; | |||
1348 | shell = ((l_attr & A_SHELL0x00800) != 0); | |||
1349 | 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 | cmnd = Expand( rp->st_string ); | |||
1354 | ||||
1355 | if( new_attr && (p = DmStrSpn(cmnd," \t\n+-@%")) != cmnd ) { | |||
1356 | size_t len = strlen(p)+1; | |||
1357 | 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 | if( command != NIL(HASH)((HASH*)((void*)0)) && !group ) { | |||
1365 | char *cname = cmnd; | |||
1366 | char cmndbuf[30]; | |||
1367 | ||||
1368 | if ( *(p=DmStrPbrk(cmnd," \t\n")) != '\0' ) { | |||
1369 | *p = '\0'; | |||
1370 | (void)Def_macro("CMNDARGS",DmStrSpn(p+1," \t\n"),M_MULTI0x0004|M_EXPANDED0x0008); | |||
1371 | } | |||
1372 | else | |||
1373 | (void) Def_macro("CMNDARGS","",M_MULTI0x0004|M_EXPANDED0x0008); | |||
1374 | ||||
1375 | (void) Def_macro("CMNDNAME",cname,M_MULTI0x0004|M_EXPANDED0x0008); | |||
1376 | ||||
1377 | strcpy(cmndbuf, "$(COMMAND)"); | |||
1378 | cmnd = Expand(cmndbuf); | |||
1379 | FREE(cname)free((char*)(cname)); /* cname == cmnd at this point. */ | |||
1380 | ||||
1381 | /* Collect up any new attributes */ | |||
1382 | l_attr |= Rcp_attribute(cmnd); | |||
1383 | shell = ((l_attr & A_SHELL0x00800) != 0); | |||
1384 | ||||
1385 | /* clean up the attributes that we may have just added. */ | |||
1386 | if( (p = DmStrSpn(cmnd," \t\n+-@%")) != cmnd ) { | |||
1387 | size_t len = strlen(p)+1; | |||
1388 | memmove(cmnd,p,len); | |||
1389 | } | |||
1390 | } | |||
1391 | ||||
1392 | #if defined(MSDOS) | |||
1393 | Swap_on_exec = ((l_attr & A_SWAP0x01000) != 0); /* Swapping for DOS only */ | |||
1394 | #endif | |||
1395 | 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 | if( Trace | |||
1403 | && ((l_attr & A_EXECUTE0x20000)||(!group && DmStrStr(rp->st_string,"$(MAKE)"))) | |||
1404 | ) { | |||
1405 | Wait_for_completion |= Trace; | |||
1406 | do_it = TRUE1; | |||
1407 | } | |||
1408 | ||||
1409 | if( group ) | |||
1410 | /* Append_line() calls Print_cmnd(). */ | |||
1411 | Append_line( cmnd, TRUE1, tmpfile, cp->CE_NAMEce_name->ht_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 | if ( *cmnd ) { | |||
1417 | /* Print command and remove continuation sequence from cmnd. */ | |||
1418 | Print_cmnd(cmnd, !(do_it && (l_attr & A_SILENT0x00002)), 0); | |||
1419 | } | |||
1420 | rval=Do_cmnd(&cmnd,FALSE0,do_it,cp,l_attr, | |||
1421 | rp->st_next == NIL(STRING)((STRING*)((void*)0)) ); | |||
1422 | } | |||
1423 | ||||
1424 | FREE(cmnd)free((char*)(cmnd)); | |||
1425 | } | |||
1426 | ||||
1427 | /* If it is a group then output the EPILOG if required and possibly | |||
1428 | * execute the command */ | |||
1429 | if( group && !(cp->ce_attr & A_ERROR0x10000000) ) { | |||
1430 | if( attr & A_EPILOG0x00008 ) /* emit epilog */ | |||
1431 | _append_file( _recipes[RP_GPEPILOG2], tmpfile, cp->CE_NAMEce_name->ht_name, trace ); | |||
1432 | ||||
1433 | if( trace ) fputs("]\n", stdoutstdout); | |||
1434 | ||||
1435 | do_it = !Trace; | |||
1436 | if( do_it ) | |||
1437 | { | |||
1438 | Close_temp( cp, tmpfile ); | |||
1439 | #if defined(UNIX) | |||
1440 | ||||
1441 | chmod(groupfile,0700); | |||
1442 | #endif | |||
1443 | } | |||
1444 | rval = Do_cmnd(&groupfile, TRUE1, do_it, cp, attr | A_SHELL0x00800, TRUE1); | |||
1445 | } | |||
1446 | ||||
1447 | _recipes[ RP_RECIPE1 ] = orp; | |||
1448 | cp->ce_attr &= ~A_ERROR0x10000000; | |||
1449 | DB_RETURN( rval )return (rval); | |||
1450 | } | |||
1451 | ||||
1452 | ||||
1453 | PUBLIC void | |||
1454 | 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 | if( echo ) { | |||
1473 | printf( "%s\n", cmnd ); | |||
1474 | fflush(stdoutstdout); | |||
1475 | } | |||
1476 | ||||
1477 | tmp[0] = ESCAPE_CHAR*Escape_char; | |||
1478 | tmp[1] = CONTINUATION_CHAR'\\'; | |||
1479 | tmp[2] = '\0'; | |||
1480 | ||||
1481 | for( p=cmnd; *(n = DmStrPbrk(p,tmp)) != '\0'; ) | |||
1482 | /* Remove the \<nl> sequences. */ | |||
1483 | if(*n == CONTINUATION_CHAR'\\' && n[1] == '\n') { | |||
1484 | size_t len = strlen(n+2)+1; | |||
1485 | DB_PRINT( "make", ("fixing [%s]", p) ); | |||
1486 | memmove( n, n+2, len ); | |||
1487 | p = n; | |||
1488 | } | |||
1489 | /* Look for an escape sequence and replace it by it's corresponding | |||
1490 | * character value. */ | |||
1491 | else { | |||
1492 | if( *n == ESCAPE_CHAR*Escape_char && map ) Map_esc( n ); | |||
1493 | p = n+1; | |||
1494 | } | |||
1495 | ||||
1496 | DB_VOID_RETURNreturn; | |||
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)((STRING*)((void*)0)); | |||
1506 | ||||
1507 | PUBLIC int | |||
1508 | 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 | if( dir == NIL(char)((char*)((void*)0)) || *dir == '\0' ) dir = Pwd; | |||
1525 | if( *dir == '\'' && dir[strlen(dir)-1] == '\'' ) { | |||
1526 | dir = DmStrDup(dir+1); | |||
1527 | dir[strlen(dir)-1]='\0'; | |||
1528 | } | |||
1529 | else if (strchr(dir,'$') != NIL(char)((char*)((void*)0))) | |||
1530 | dir = Expand(dir); | |||
1531 | else | |||
1532 | dir = DmStrDup(dir); | |||
1533 | ||||
1534 | if( Set_dir(dir) ) { | |||
1535 | if( !ignore ) | |||
1536 | Fatal( "Unable to change to directory `%s', target is [%s]", | |||
1537 | dir, name ); | |||
1538 | FREE(dir)free((char*)(dir)); | |||
1539 | DB_RETURN( 0 )return (0); | |||
1540 | } | |||
1541 | ||||
1542 | DB_PRINT( "dir", ("Push: [%s]", dir) ); | |||
1543 | if( Verbose & V_DIR_SET0x02 ) | |||
1544 | printf( "%s: Changed to directory [%s]\n", Pname, dir ); | |||
1545 | ||||
1546 | FREE( dir )free((char*)(dir)); | |||
1547 | TALLOC( new_dir, 1, STRING )if ((new_dir = (STRING*) calloc((unsigned int)(1), (size_t)sizeof (STRING))) == (STRING*)0) {No_ram();}; | |||
1548 | new_dir->st_next = dir_stack; | |||
1549 | dir_stack = new_dir; | |||
1550 | new_dir->st_string = DmStrDup( Pwd ); | |||
1551 | ||||
1552 | Def_macro( "PWD", Get_current_dir(), M_FORCE0x0080 | M_EXPANDED0x0008 ); | |||
1553 | _set_tmd(); | |||
1554 | ||||
1555 | DB_RETURN( 1 )return (1); | |||
1556 | } | |||
1557 | ||||
1558 | ||||
1559 | ||||
1560 | PUBLIC void | |||
1561 | 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 | if( dir_stack == NIL(STRING)((STRING*)((void*)0)) ) { | |||
1572 | if( ignore ) { | |||
1573 | DB_VOID_RETURNreturn; | |||
1574 | } | |||
1575 | else | |||
1576 | Error( "Directory stack empty for return from .SETDIR" ); | |||
1577 | } | |||
1578 | ||||
1579 | if( Set_dir(dir = dir_stack->st_string) ) | |||
1580 | Fatal( "Could not change to directory `%s'", dir ); | |||
1581 | ||||
1582 | Def_macro( "PWD", dir, M_FORCE0x0080 | M_EXPANDED0x0008 ); | |||
1583 | DB_PRINT( "dir", ("Pop: [%s]", dir) ); | |||
1584 | if( Verbose & V_DIR_SET0x02 ) | |||
1585 | printf( "%s: Changed back to directory [%s]\n", Pname, dir); | |||
1586 | ||||
1587 | old_dir = dir_stack; | |||
1588 | dir_stack = dir_stack->st_next; | |||
1589 | ||||
1590 | FREE( old_dir->st_string )free((char*)(old_dir->st_string)); | |||
1591 | FREE( old_dir )free((char*)(old_dir)); | |||
1592 | _set_tmd(); | |||
1593 | ||||
1594 | DB_VOID_RETURNreturn; | |||
1595 | } | |||
1596 | ||||
1597 | ||||
1598 | ||||
1599 | static void | |||
1600 | _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 | if( Tmd ) | |||
1611 | FREE(Tmd)free((char*)(Tmd)); | |||
1612 | ||||
1613 | tmd = _prefix(Pwd, Makedir); | |||
1614 | if( *tmd ) { | |||
1615 | Def_macro( "TMD", DO_WINPATH(tmd)tmd, M_FORCE0x0080 | M_EXPANDED0x0008 ); | |||
1616 | Tmd = DmStrDup(tmd); | |||
1617 | } else { | |||
1618 | Def_macro( "TMD", ".", M_FORCE0x0080 | M_EXPANDED0x0008 ); | |||
1619 | Tmd = DmStrDup("."); | |||
1620 | } | |||
1621 | FREE( tmd )free((char*)(tmd)); | |||
1622 | } | |||
1623 | ||||
1624 | ||||
1625 | static void | |||
1626 | _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 | if( (hp = Get_name(target, Defs, FALSE0)) != NIL(HASH)((HASH*)((void*)0)) ) { | |||
1637 | cp = hp->CP_OWNRvar.val.ht.ht_owner; | |||
1638 | _recipes[ ind ] = cp->ce_recipe; | |||
1639 | } | |||
1640 | else | |||
1641 | _recipes[ ind ] = NIL(STRING)((STRING*)((void*)0)); | |||
1642 | } | |||
1643 | ||||
1644 | ||||
1645 | ||||
1646 | PUBLIC void | |||
1647 | 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 | Print_cmnd( cmnd, printit, map ); | |||
1656 | ||||
1657 | if( Trace ) return; | |||
1658 | ||||
1659 | fputs(cmnd, tmpfile); | |||
1660 | if( newline ) fputc('\n', tmpfile); | |||
1661 | fflush(tmpfile); | |||
1662 | ||||
1663 | if( ferror(tmpfile) ) | |||
1664 | Fatal("Write error on temporary file, while processing `%s'", name); | |||
1665 | } | |||
1666 | ||||
1667 | ||||
1668 | ||||
1669 | static void | |||
1670 | _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 | while( rp != NIL(STRING)((STRING*)((void*)0)) ) { | |||
1679 | Append_line(cmnd = Expand(rp->st_string), TRUE1, tmpfile, name, printit,0); | |||
1680 | FREE(cmnd)free((char*)(cmnd)); | |||
1681 | rp = rp->st_next; | |||
1682 | } | |||
1683 | } | |||
1684 | ||||
1685 | ||||
1686 | #define NUM_BUCKETS20 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_BUCKETS20 ]; | |||
1695 | ||||
1696 | static char * | |||
1697 | _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 | if( str == NIL(char)((char*)((void*)0)) ) DB_RETURN("")return (""); | |||
| ||||
1712 | ||||
1713 | hv = Hash(str, &keyval); | |||
1714 | key = strings[ keyindex = (hv % NUM_BUCKETS20) ]; | |||
1715 | ||||
1716 | while( key != NIL(POOL)((POOL*)((void*)0)) ) | |||
1717 | if( (key->keyval != keyval) || strcmp(str, key->string) ) | |||
1718 | key = key->next; | |||
1719 | else | |||
1720 | break; | |||
1721 | ||||
1722 | if( key == NIL(POOL)((POOL*)((void*)0)) ) { | |||
1723 | DB_PRINT( "pool", ("Adding string [%s]", str) ); | |||
1724 | TALLOC( key, 1, POOL )if ((key = (POOL*) calloc((unsigned int)(1), (size_t)sizeof(POOL ))) == (POOL*)0) {No_ram();}; /* not found so add string */ | |||
1725 | ||||
1726 | key->string = string = DmStrDup(str); | |||
| ||||
1727 | key->keyval = keyval; | |||
1728 | ||||
1729 | key->next = strings[ keyindex ]; | |||
1730 | strings[ keyindex ] = key; | |||
1731 | } | |||
1732 | else { | |||
1733 | DB_PRINT( "pool", ("Found string [%s], key->string") ); | |||
1734 | string = key->string; | |||
1735 | } | |||
1736 | ||||
1737 | DB_RETURN( string )return (string); | |||
1738 | } | |||
1739 | ||||
1740 | ||||
1741 | void | |||
1742 | 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 | for(dp=CeMeToo(cp)&((cp)->ce_all); dp; dp=dp->cl_next) { | |||
1754 | tcp = dp->cl_prq; | |||
1755 | ||||
1756 | /* Unmake the prerequisites. */ | |||
1757 | for( ep = tcp->ce_prq; ep != NIL(LINK)((LINK*)((void*)0)); ep = ep->cl_next ) { | |||
1758 | pcp = ep->cl_prq; | |||
1759 | ||||
1760 | Unmake(pcp); | |||
1761 | } | |||
1762 | DB_PRINT( "unmake", ("Unmake [%s]", tcp->CE_NAME) ); | |||
1763 | ||||
1764 | tcp->ce_flag &= ~(F_MADE0x8000|F_VISITED0x0080|F_STAT0x0040); | |||
1765 | tcp->ce_time = (time_t)0L; | |||
1766 | } | |||
1767 | ||||
1768 | DB_VOID_RETURNreturn; | |||
1769 | } |