Print this page
make: unifdef for PARALLEL (undefined, this relates to the old pmake)
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/make/bin/doname.cc
+++ new/usr/src/cmd/make/bin/doname.cc
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * doname.c
28 28 *
29 29 * Figure out which targets are out of date and rebuild them
30 30 */
31 31
32 32 /*
33 33 * Included files
34 34 */
35 35 #include <avo/avo_alloca.h> /* alloca() */
36 36 #if defined(TEAMWARE_MAKE_CMN)
37 37 #include <avo/util.h> /* avo_get_user(), avo_hostname() */
38 38 #endif
39 39
40 40 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
41 41 # include <avo/strings.h> /* AVO_STRDUP() */
42 42 # include <dm/Avo_MToolJobResultMsg.h>
43 43 # include <dm/Avo_MToolJobStartMsg.h>
44 44 # include <dm/Avo_MToolRsrcInfoMsg.h>
45 45 # include <dm/Avo_macro_defs.h> /* AVO_BLOCK_INTERUPTS & AVO_UNBLOCK_INTERUPTS */
46 46 # include <dmthread/Avo_ServerState.h>
47 47 # include <rw/pstream.h>
↓ open down ↓ |
47 lines elided |
↑ open up ↑ |
48 48 # include <rw/xdrstrea.h>
49 49 #endif
50 50
51 51 #include <fcntl.h>
52 52 #include <mk/defs.h>
53 53 #include <mksh/i18n.h> /* get_char_semantics_value() */
54 54 #include <mksh/macro.h> /* getvar(), expand_value() */
55 55 #include <mksh/misc.h> /* getmem() */
56 56 #include <poll.h>
57 57
58 -#ifdef PARALLEL
59 -# include <rx/api.h>
60 -#endif
61 58
62 59 #include <signal.h>
63 60
64 61 # include <stropts.h>
65 62
66 63 #include <sys/errno.h>
67 64 #include <sys/stat.h>
68 65 #include <sys/types.h>
69 66 #include <sys/utsname.h> /* uname() */
70 67 #include <sys/wait.h>
71 68 #include <unistd.h> /* close() */
72 69
73 70 /*
74 71 * Defined macros
75 72 */
76 -#ifndef PARALLEL
77 73 # define LOCALHOST "localhost"
78 -#endif
79 74
80 75 #define MAXRULES 100
81 76
82 77 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
83 78 #define SEND_MTOOL_MSG(cmds) \
84 79 if (send_mtool_msgs) { \
85 80 cmds \
86 81 }
87 82 #else
88 83 #define SEND_MTOOL_MSG(cmds)
89 84 #endif
90 85
91 86 // Sleep for .1 seconds between stat()'s
92 87 const int STAT_RETRY_SLEEP_TIME = 100000;
93 88
94 89 /*
95 90 * typedefs & structs
96 91 */
97 92
98 93 /*
99 94 * Static variables
100 95 */
101 96 static char hostName[MAXNAMELEN] = "";
102 97 static char userName[MAXNAMELEN] = "";
103 98
104 99 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
105 100 static FILE *mtool_msgs_fp;
106 101 static XDR xdrs;
107 102 static int sent_rsrc_info_msg = 0;
108 103 #endif
109 104
110 105 static int second_pass = 0;
111 106
112 107 /*
113 108 * File table of contents
114 109 */
115 110 extern Doname doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
116 111 extern Doname doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic);
117 112 static Boolean check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals);
118 113 void dynamic_dependencies(Name target);
119 114 static Doname run_command(register Property line, Boolean print_machine);
120 115 extern Doname execute_serial(Property line);
121 116 extern Name vpath_translation(register Name cmd);
122 117 extern void check_state(Name temp_file_name);
123 118 static void read_dependency_file(register Name filename);
124 119 static void check_read_state_file(void);
125 120 static void do_assign(register Name line, register Name target);
126 121 static void build_command_strings(Name target, register Property line);
127 122 static Doname touch_command(register Property line, register Name target, Doname result);
128 123 extern void update_target(Property line, Doname result);
129 124 static Doname sccs_get(register Name target, register Property *command);
130 125 extern void read_directory_of_file(register Name file);
131 126 static void add_pattern_conditionals(register Name target);
132 127 extern void set_locals(register Name target, register Property old_locals);
133 128 extern void reset_locals(register Name target, register Property old_locals, register Property conditional, register int index);
134 129 extern Boolean check_auto_dependencies(Name target, int auto_count, Name *automatics);
135 130 static void delete_query_chain(Chain ch);
136 131
137 132 // From read2.cc
138 133 extern Name normalize_name(register wchar_t *name_string, register int length);
139 134
140 135
141 136 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
142 137 static void append_job_result_msg(Avo_MToolJobResultMsg *job_result_msg);
143 138 static int pollResults(char *outFn, char *errFn, char *hostNm);
144 139 static void pollResultsAction(char *outFn, char *errFn);
145 140 static void rxmGetNextResultsBlock(int fd);
146 141 static int us_sleep(unsigned int nusecs);
147 142 extern "C" void Avo_PollResultsAction_Sigusr1Handler(int foo);
148 143 #endif
149 144
150 145 /*
151 146 * DONE.
152 147 *
153 148 * doname_check(target, do_get, implicit, automatic)
154 149 *
155 150 * Will call doname() and then inspect the return value
156 151 *
157 152 * Return value:
158 153 * Indication if the build failed or not
159 154 *
160 155 * Parameters:
161 156 * target The target to build
162 157 * do_get Passed thru to doname()
163 158 * implicit Passed thru to doname()
164 159 * automatic Are we building a hidden dependency?
165 160 *
166 161 * Global variables used:
167 162 * build_failed_seen Set if -k is on and error occurs
168 163 * continue_after_error Indicates that -k is on
169 164 * report_dependencies No error msg if -P is on
170 165 */
171 166 Doname
172 167 doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
173 168 {
174 169 int first_time = 1;
175 170 (void) fflush(stdout);
176 171 try_again:
177 172 switch (doname(target, do_get, implicit, automatic)) {
178 173 case build_ok:
179 174 second_pass = 0;
180 175 return build_ok;
181 176 case build_running:
182 177 second_pass = 0;
183 178 return build_running;
184 179 case build_failed:
185 180 if (!continue_after_error) {
186 181 fatal(catgets(catd, 1, 13, "Target `%s' not remade because of errors"),
187 182 target->string_mb);
188 183 }
189 184 build_failed_seen = true;
190 185 second_pass = 0;
191 186 return build_failed;
192 187 case build_dont_know:
193 188 /*
194 189 * If we can't figure out how to build an automatic
195 190 * (hidden) dependency, we just ignore it.
196 191 * We later declare the target to be out of date just in
197 192 * case something changed.
198 193 * Also, don't complain if just reporting the dependencies
199 194 * and not building anything.
200 195 */
201 196 if (automatic || (report_dependencies_level > 0)) {
202 197 second_pass = 0;
203 198 return build_dont_know;
204 199 }
205 200 if(first_time) {
206 201 first_time = 0;
207 202 second_pass = 1;
208 203 goto try_again;
209 204 }
210 205 second_pass = 0;
211 206 if (continue_after_error && !svr4) {
212 207 warning(catgets(catd, 1, 14, "Don't know how to make target `%s'"),
213 208 target->string_mb);
214 209 build_failed_seen = true;
215 210 return build_failed;
216 211 }
217 212 fatal(catgets(catd, 1, 15, "Don't know how to make target `%s'"), target->string_mb);
218 213 break;
219 214 }
220 215 #ifdef lint
221 216 return build_failed;
222 217 #endif
223 218 }
224 219
225 220
226 221 void
227 222 enter_explicit_rule_from_dynamic_rule(Name target, Name source)
228 223 {
229 224 Property line, source_line;
230 225 Dependency dependency;
231 226
232 227 source_line = get_prop(source->prop, line_prop);
233 228 line = maybe_append_prop(target, line_prop);
234 229 line->body.line.sccs_command = false;
235 230 line->body.line.target = target;
236 231 if (line->body.line.command_template == NULL) {
237 232 line->body.line.command_template = source_line->body.line.command_template;
238 233 for (dependency = source_line->body.line.dependencies;
239 234 dependency != NULL;
240 235 dependency = dependency->next) {
241 236 enter_dependency(line, dependency->name, false);
242 237 }
243 238 line->body.line.less = target;
244 239 }
245 240 line->body.line.percent = NULL;
246 241 }
247 242
248 243
249 244
250 245 Name
251 246 find_dyntarget(Name target)
252 247 {
253 248 Dyntarget p;
254 249 int i;
255 250 String_rec string;
256 251 wchar_t buffer[STRING_BUFFER_LENGTH];
257 252 wchar_t *pp, * bufend;
258 253 wchar_t tbuffer[MAXPATHLEN];
259 254 Wstring wcb(target);
260 255
261 256 for (p = dyntarget_list; p != NULL; p = p->next) {
262 257 INIT_STRING_FROM_STACK(string, buffer);
263 258 expand_value(p->name, &string, false);
264 259 i = 0;
265 260 pp = string.buffer.start;
266 261 bufend = pp + STRING_BUFFER_LENGTH;
267 262 while((*pp != nul_char) && (pp < bufend)) {
268 263 if(iswspace(*pp)) {
269 264 tbuffer[i] = nul_char;
270 265 if(i > 0) {
271 266 if (wcb.equal(tbuffer)) {
272 267 enter_explicit_rule_from_dynamic_rule(target, p->name);
273 268 return(target);
274 269 }
275 270 }
276 271 pp++;
277 272 i = 0;
278 273 continue;
279 274 }
280 275 tbuffer[i] = *pp;
281 276 i++;
282 277 pp++;
283 278 if(*pp == nul_char) {
284 279 tbuffer[i] = nul_char;
285 280 if(i > 0) {
286 281 if (wcb.equal(tbuffer)) {
287 282 enter_explicit_rule_from_dynamic_rule(target, p->name);
288 283 return(target);
289 284 }
290 285 }
291 286 break;
292 287 }
293 288 }
294 289 }
295 290 return(NULL);
296 291 }
297 292
298 293 /*
299 294 * DONE.
300 295 *
301 296 * doname(target, do_get, implicit)
302 297 *
303 298 * Chases all files the target depends on and builds any that
304 299 * are out of date. If the target is out of date it is then rebuilt.
305 300 *
306 301 * Return value:
307 302 * Indiates if build failed or nt
308 303 *
309 304 * Parameters:
310 305 * target Target to build
311 306 * do_get Run sccs get is nessecary
312 307 * implicit doname is trying to find an implicit rule
313 308 *
314 309 * Global variables used:
315 310 * assign_done True if command line assgnment has happened
316 311 * commands_done Preserved for the case that we need local value
317 312 * debug_level Should we trace make's actions?
318 313 * default_rule The rule for ".DEFAULT", used as last resort
319 314 * empty_name The Name "", used when looking for single sfx
320 315 * keep_state Indicates that .KEEP_STATE is on
321 316 * parallel True if building in parallel
322 317 * recursion_level Used for tracing
323 318 * report_dependencies make -P is on
324 319 */
325 320 Doname
326 321 doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic)
327 322 {
328 323 Doname result = build_dont_know;
329 324 Chain out_of_date_list = NULL;
330 325 #ifdef TEAMWARE_MAKE_CMN
331 326 Chain target_group;
332 327 #endif
333 328 Property old_locals = NULL;
334 329 register Property line;
335 330 Property command = NULL;
336 331 register Dependency dependency;
337 332 Name less = NULL;
338 333 Name true_target = target;
339 334 Name *automatics = NULL;
340 335 register int auto_count;
341 336 Boolean rechecking_target = false;
342 337 Boolean saved_commands_done;
343 338 Boolean restart = false;
344 339 Boolean save_parallel = parallel;
345 340 Boolean doing_subtree = false;
346 341
347 342 Boolean recheck_conditionals = false;
348 343
349 344 if (target->state == build_running) {
350 345 return build_running;
351 346 }
352 347 line = get_prop(target->prop, line_prop);
353 348 #ifdef TEAMWARE_MAKE_CMN
354 349 if (line != NULL) {
355 350 /*
356 351 * If this target is a member of target group and one of the
357 352 * other members of the group is running, mark this target
358 353 * as running.
359 354 */
360 355 for (target_group = line->body.line.target_group;
361 356 target_group != NULL;
362 357 target_group = target_group->next) {
363 358 if (is_running(target_group->name)) {
364 359 target->state = build_running;
365 360 add_pending(target,
366 361 recursion_level,
367 362 do_get,
368 363 implicit,
369 364 false);
370 365 return build_running;
371 366 }
372 367 }
373 368 }
374 369 #endif
375 370 /*
376 371 * If the target is a constructed one for a "::" target,
377 372 * we need to consider that.
378 373 */
379 374 if (target->has_target_prop) {
380 375 true_target = get_prop(target->prop,
381 376 target_prop)->body.target.target;
382 377 if (true_target->colon_splits > 0) {
383 378 /* Make sure we have a valid time for :: targets */
384 379 Property time;
385 380
386 381 time = get_prop(true_target->prop, time_prop);
387 382 if (time != NULL) {
388 383 true_target->stat.time = time->body.time.time;
389 384 }
390 385 }
391 386 }
392 387 (void) exists(true_target);
393 388 /*
394 389 * If the target has been processed, we don't need to do it again,
395 390 * unless it depends on conditional macros or a delayed assignment,
396 391 * or it has been done when KEEP_STATE is on.
397 392 */
398 393 if (target->state == build_ok) {
399 394 if((!keep_state || (!target->depends_on_conditional && !assign_done))) {
400 395 return build_ok;
401 396 } else {
402 397 recheck_conditionals = true;
403 398 }
404 399 }
405 400 if (target->state == build_subtree) {
406 401 /* A dynamic macro subtree is being built */
407 402 target->state = build_dont_know;
408 403 doing_subtree = true;
409 404 if (!target->checking_subtree) {
410 405 /*
411 406 * This target has been started before and therefore
412 407 * not all dependencies have to be built.
413 408 */
414 409 restart = true;
415 410 }
416 411 } else if (target->state == build_pending) {
417 412 target->state = build_dont_know;
418 413 restart = true;
419 414 /*
420 415 #ifdef TEAMWARE_MAKE_CMN
421 416 } else if (parallel &&
422 417 keep_state &&
423 418 (target->conditional_cnt > 0)) {
424 419 if (!parallel_ok(target, false)) {
425 420 add_subtree(target, recursion_level, do_get, implicit);
426 421 target->state = build_running;
427 422 return build_running;
428 423 }
429 424 #endif
430 425 */
431 426 }
432 427 /*
433 428 * If KEEP_STATE is on, we have to rebuild the target if the
434 429 * building of it caused new automatic dependencies to be reported.
435 430 * This is where we restart the build.
436 431 */
437 432 if (line != NULL) {
438 433 line->body.line.percent = NULL;
439 434 }
440 435 recheck_target:
441 436 /* Init all local variables */
442 437 result = build_dont_know;
443 438 out_of_date_list = NULL;
444 439 command = NULL;
445 440 less = NULL;
446 441 auto_count = 0;
447 442 if (!restart && line != NULL) {
448 443 /*
449 444 * If this target has never been built before, mark all
450 445 * of the dependencies as never built.
451 446 */
452 447 for (dependency = line->body.line.dependencies;
453 448 dependency != NULL;
454 449 dependency = dependency->next) {
455 450 dependency->built = false;
456 451 }
457 452 }
458 453 /* Save the set of automatic depes defined for this target */
459 454 if (keep_state &&
460 455 (line != NULL) &&
461 456 (line->body.line.dependencies != NULL)) {
462 457 Name *p;
463 458
464 459 /*
465 460 * First run thru the dependency list to see how many
466 461 * autos there are.
467 462 */
468 463 for (dependency = line->body.line.dependencies;
469 464 dependency != NULL;
470 465 dependency = dependency->next) {
471 466 if (dependency->automatic && !dependency->stale) {
472 467 auto_count++;
473 468 }
474 469 }
475 470 /* Create vector to hold the current autos */
476 471 automatics =
477 472 (Name *) alloca((int) (auto_count * sizeof (Name)));
478 473 /* Copy them */
479 474 for (p = automatics, dependency = line->body.line.dependencies;
480 475 dependency != NULL;
481 476 dependency = dependency->next) {
482 477 if (dependency->automatic && !dependency->stale) {
483 478 *p++ = dependency->name;
484 479 }
485 480 }
486 481 }
487 482 if (debug_level > 1) {
488 483 (void) printf(NOCATGETS("%*sdoname(%s)\n"),
489 484 recursion_level,
490 485 "",
491 486 target->string_mb);
492 487 }
493 488 recursion_level++;
494 489 /* Avoid infinite loops */
495 490 if (target->state == build_in_progress) {
496 491 warning(catgets(catd, 1, 16, "Infinite loop: Target `%s' depends on itself"),
497 492 target->string_mb);
498 493 return build_ok;
499 494 }
500 495 target->state = build_in_progress;
501 496
502 497 /* Activate conditional macros for the target */
503 498 if (!target->added_pattern_conditionals) {
504 499 add_pattern_conditionals(target);
505 500 target->added_pattern_conditionals = true;
506 501 }
507 502 if (target->conditional_cnt > 0) {
508 503 old_locals = (Property) alloca(target->conditional_cnt *
509 504 sizeof (Property_rec));
510 505 set_locals(target, old_locals);
511 506 }
512 507
513 508 /*
514 509 * after making the call to dynamic_dependecies unconditional we can handle
515 510 * target names that are same as file name. In this case $$@ in the
516 511 * dependencies did not mean anything. WIth this change it expands it
517 512 * as expected.
518 513 */
519 514 if (!target->has_depe_list_expanded)
520 515 {
521 516 dynamic_dependencies(target);
522 517 }
523 518
524 519 /*
525 520 * FIRST SECTION -- GO THROUGH DEPENDENCIES AND COLLECT EXPLICIT
526 521 * COMMANDS TO RUN
527 522 */
528 523 if ((line = get_prop(target->prop, line_prop)) != NULL) {
529 524 if (check_dependencies(&result,
530 525 line,
531 526 do_get,
532 527 target,
533 528 true_target,
534 529 doing_subtree,
535 530 &out_of_date_list,
536 531 old_locals,
537 532 implicit,
538 533 &command,
539 534 less,
↓ open down ↓ |
451 lines elided |
↑ open up ↑ |
540 535 rechecking_target,
541 536 recheck_conditionals)) {
542 537 return build_running;
543 538 }
544 539 if (line->body.line.query != NULL) {
545 540 delete_query_chain(line->body.line.query);
546 541 }
547 542 line->body.line.query = out_of_date_list;
548 543 }
549 544
550 -#ifdef PARALLEL
551 - if (doing_subtree) {
552 - parallel = false;
553 - }
554 -#endif
555 545
556 546 /*
557 547 * If the target is a :: type, do not try to find the rule for the target,
558 548 * all actions will be taken by separate branches.
559 549 * Else, we try to find an implicit rule using various methods,
560 550 * we quit as soon as one is found.
561 551 *
562 552 * [tolik, 12 Sep 2002] Do not try to find implicit rule for the target
563 553 * being rechecked - the target is being rechecked means that it already
564 554 * has explicit dependencies derived from an implicit rule found
565 555 * in previous step.
566 556 */
567 557 if (target->colon_splits == 0 && !rechecking_target) {
568 558 /* Look for percent matched rule */
569 559 if ((result == build_dont_know) &&
570 560 (command == NULL)) {
571 561 switch (find_percent_rule(
572 562 target,
573 563 &command,
574 564 recheck_conditionals)) {
575 565 case build_failed:
576 566 result = build_failed;
577 567 break;
578 568 #ifdef TEAMWARE_MAKE_CMN
579 569 case build_running:
580 570 target->state = build_running;
581 571 add_pending(target,
582 572 --recursion_level,
583 573 do_get,
584 574 implicit,
585 575 false);
586 576 if (target->conditional_cnt > 0) {
587 577 reset_locals(target,
588 578 old_locals,
589 579 get_prop(target->prop,
590 580 conditional_prop),
591 581 0);
592 582 }
593 583 return build_running;
594 584 #endif
595 585 case build_ok:
596 586 result = build_ok;
597 587 break;
598 588 }
599 589 }
600 590 /* Look for double suffix rule */
601 591 if (result == build_dont_know) {
602 592 Property member;
603 593
604 594 if (target->is_member &&
605 595 ((member = get_prop(target->prop, member_prop)) !=
606 596 NULL)) {
607 597 switch (find_ar_suffix_rule(target,
608 598 member->body.
609 599 member.member,
610 600 &command,
611 601 recheck_conditionals)) {
612 602 case build_failed:
613 603 result = build_failed;
614 604 break;
615 605 #ifdef TEAMWARE_MAKE_CMN
616 606 case build_running:
617 607 target->state = build_running;
618 608 add_pending(target,
619 609 --recursion_level,
620 610 do_get,
621 611 implicit,
622 612 false);
623 613 if (target->conditional_cnt > 0) {
624 614 reset_locals(target,
625 615 old_locals,
626 616 get_prop(target->prop,
627 617 conditional_prop),
628 618 0);
629 619 }
630 620 return build_running;
631 621 #endif
632 622 default:
633 623 /* ALWAYS bind $% for old style */
634 624 /* ar rules */
635 625 if (line == NULL) {
636 626 line =
637 627 maybe_append_prop(target,
638 628 line_prop);
639 629 }
640 630 line->body.line.percent =
641 631 member->body.member.member;
642 632 break;
643 633 }
644 634 } else {
645 635 switch (find_double_suffix_rule(target,
646 636 &command,
647 637 recheck_conditionals)) {
648 638 case build_failed:
649 639 result = build_failed;
650 640 break;
651 641 #ifdef TEAMWARE_MAKE_CMN
652 642 case build_running:
653 643 target->state = build_running;
654 644 add_pending(target,
655 645 --recursion_level,
656 646 do_get,
657 647 implicit,
658 648 false);
659 649 if (target->conditional_cnt > 0) {
660 650 reset_locals(target,
661 651 old_locals,
662 652 get_prop(target->
663 653 prop,
664 654 conditional_prop),
665 655 0);
666 656 }
667 657 return build_running;
668 658 #endif
669 659 }
670 660 }
671 661 }
672 662 /* Look for single suffix rule */
673 663
674 664 /* /tolik/
675 665 * I commented !implicit to fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
676 666 * This caused problem with SVR4 tilde rules (infinite recursion). So I made some changes in "implicit.cc"
677 667 */
678 668 /* /tolik, 06.21.96/
679 669 * Regression! See BugId 1255360
680 670 * If more than one percent rules are defined for the same target then
681 671 * the behaviour of 'make' with my previous fix may be different from one
682 672 * of the 'old make'.
683 673 * The global variable second_pass (maybe it should be an argument to doname())
684 674 * is intended to avoid this regression. It is set in doname_check().
685 675 * First, 'make' will work as it worked before. Only when it is
686 676 * going to say "don't know how to make target" it sets second_pass to true and
687 677 * run 'doname' again but now trying to use Single Suffix Rules.
688 678 */
689 679 if ((result == build_dont_know) && !automatic && (!implicit || second_pass) &&
690 680 ((line == NULL) ||
691 681 ((line->body.line.target != NULL) &&
692 682 !line->body.line.target->has_regular_dependency))) {
693 683 switch (find_suffix_rule(target,
694 684 target,
695 685 empty_name,
696 686 &command,
697 687 recheck_conditionals)) {
698 688 case build_failed:
699 689 result = build_failed;
700 690 break;
701 691 #ifdef TEAMWARE_MAKE_CMN
702 692 case build_running:
703 693 target->state = build_running;
704 694 add_pending(target,
705 695 --recursion_level,
706 696 do_get,
707 697 implicit,
708 698 false);
709 699 if (target->conditional_cnt > 0) {
710 700 reset_locals(target,
711 701 old_locals,
712 702 get_prop(target->prop,
713 703 conditional_prop),
714 704 0);
715 705 }
716 706 return build_running;
717 707 #endif
718 708 }
719 709 }
720 710 /* Try to sccs get */
721 711 if ((command == NULL) &&
722 712 (result == build_dont_know) &&
723 713 do_get) {
724 714 result = sccs_get(target, &command);
725 715 }
726 716
727 717 /* Use .DEFAULT rule if it is defined. */
728 718 if ((command == NULL) &&
729 719 (result == build_dont_know) &&
730 720 (true_target->colons == no_colon) &&
731 721 default_rule &&
732 722 !implicit) {
733 723 /* Make sure we have a line prop */
734 724 line = maybe_append_prop(target, line_prop);
735 725 command = line;
736 726 Boolean out_of_date;
737 727 if (true_target->is_member) {
738 728 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
739 729 line->body.line.dependency_time);
740 730 } else {
741 731 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
742 732 line->body.line.dependency_time);
743 733 }
744 734 if (build_unconditional || out_of_date) {
745 735 line->body.line.is_out_of_date = true;
746 736 if (debug_level > 0) {
747 737 (void) printf(catgets(catd, 1, 17, "%*sBuilding %s using .DEFAULT because it is out of date\n"),
748 738 recursion_level,
749 739 "",
750 740 true_target->string_mb);
751 741 }
752 742 }
753 743 line->body.line.sccs_command = false;
754 744 line->body.line.command_template = default_rule;
755 745 line->body.line.target = true_target;
756 746 line->body.line.star = NULL;
757 747 line->body.line.less = true_target;
758 748 line->body.line.percent = NULL;
759 749 }
760 750 }
761 751
762 752 /* We say "target up to date" if no cmd were executed for the target */
763 753 if (!target->is_double_colon_parent) {
764 754 commands_done = false;
765 755 }
766 756
767 757 silent = silent_all;
768 758 ignore_errors = ignore_errors_all;
769 759 if (posix)
770 760 {
771 761 if (!silent)
772 762 {
773 763 silent = (Boolean) target->silent_mode;
774 764 }
775 765 if (!ignore_errors)
776 766 {
777 767 ignore_errors = (Boolean) target->ignore_error_mode;
778 768 }
779 769 }
780 770
781 771 int doname_dyntarget = 0;
782 772 r_command:
783 773 /* Run commands if any. */
784 774 if ((command != NULL) &&
785 775 (command->body.line.command_template != NULL)) {
786 776 if (result != build_failed) {
787 777 result = run_command(command,
788 778 (Boolean) ((parallel || save_parallel) && !silent));
789 779 }
790 780 switch (result) {
791 781 #ifdef TEAMWARE_MAKE_CMN
792 782 case build_running:
793 783 add_running(target,
794 784 true_target,
795 785 command,
796 786 --recursion_level,
797 787 auto_count,
798 788 automatics,
799 789 do_get,
800 790 implicit);
801 791 target->state = build_running;
802 792 if ((line = get_prop(target->prop,
803 793 line_prop)) != NULL) {
804 794 if (line->body.line.query != NULL) {
805 795 delete_query_chain(line->body.line.query);
806 796 }
807 797 line->body.line.query = NULL;
808 798 }
809 799 if (target->conditional_cnt > 0) {
810 800 reset_locals(target,
811 801 old_locals,
812 802 get_prop(target->prop,
813 803 conditional_prop),
814 804 0);
815 805 }
816 806 return build_running;
817 807 case build_serial:
818 808 add_serial(target,
819 809 --recursion_level,
820 810 do_get,
821 811 implicit);
822 812 target->state = build_running;
823 813 line = get_prop(target->prop, line_prop);
824 814 if (line != NULL) {
825 815 if (line->body.line.query != NULL) {
826 816 delete_query_chain(line->body.line.query);
827 817 }
828 818 line->body.line.query = NULL;
829 819 }
830 820 if (target->conditional_cnt > 0) {
831 821 reset_locals(target,
832 822 old_locals,
833 823 get_prop(target->prop,
834 824 conditional_prop),
835 825 0);
836 826 }
837 827 return build_running;
838 828 #endif
839 829 case build_ok:
840 830 /* If all went OK set a nice timestamp */
841 831 if (true_target->stat.time == file_doesnt_exist) {
842 832 true_target->stat.time = file_max_time;
843 833 }
844 834 break;
845 835 }
846 836 } else {
847 837 /*
848 838 * If no command was found for the target, and it doesn't
849 839 * exist, and it is mentioned as a target in the makefile,
850 840 * we say it is extremely new and that it is OK.
851 841 */
852 842 if (target->colons != no_colon) {
853 843 if (true_target->stat.time == file_doesnt_exist){
854 844 true_target->stat.time = file_max_time;
855 845 }
856 846 result = build_ok;
857 847 }
858 848 /*
859 849 * Trying dynamic targets.
860 850 */
861 851 if(!doname_dyntarget) {
862 852 doname_dyntarget = 1;
863 853 Name dtarg = find_dyntarget(target);
864 854 if(dtarg!=NULL) {
865 855 if (!target->has_depe_list_expanded) {
866 856 dynamic_dependencies(target);
867 857 }
868 858 if ((line = get_prop(target->prop, line_prop)) != NULL) {
869 859 if (check_dependencies(&result,
870 860 line,
871 861 do_get,
872 862 target,
873 863 true_target,
874 864 doing_subtree,
875 865 &out_of_date_list,
876 866 old_locals,
877 867 implicit,
878 868 &command,
879 869 less,
880 870 rechecking_target,
881 871 recheck_conditionals))
882 872 {
883 873 return build_running;
884 874 }
885 875 if (line->body.line.query != NULL) {
886 876 delete_query_chain(line->body.line.query);
887 877 }
888 878 line->body.line.query = out_of_date_list;
889 879 }
890 880 goto r_command;
891 881 }
892 882 }
893 883 /*
894 884 * If the file exists, it is OK that we couldnt figure
895 885 * out how to build it.
896 886 */
897 887 (void) exists(target);
898 888 if ((target->stat.time != file_doesnt_exist) &&
899 889 (result == build_dont_know)) {
900 890 result = build_ok;
901 891 }
902 892 }
903 893
904 894 /*
905 895 * Some of the following is duplicated in the function finish_doname.
906 896 * If anything is changed here, check to see if it needs to be
907 897 * changed there.
908 898 */
909 899 if ((line = get_prop(target->prop, line_prop)) != NULL) {
910 900 if (line->body.line.query != NULL) {
911 901 delete_query_chain(line->body.line.query);
912 902 }
913 903 line->body.line.query = NULL;
914 904 }
915 905 target->state = result;
916 906 parallel = save_parallel;
917 907 if (target->conditional_cnt > 0) {
918 908 reset_locals(target,
919 909 old_locals,
920 910 get_prop(target->prop, conditional_prop),
921 911 0);
922 912 }
923 913 recursion_level--;
924 914 if (target->is_member) {
925 915 Property member;
926 916
927 917 /* Propagate the timestamp from the member file to the member*/
928 918 if ((target->stat.time != file_max_time) &&
929 919 ((member = get_prop(target->prop, member_prop)) != NULL) &&
930 920 (exists(member->body.member.member) > file_doesnt_exist)) {
931 921 target->stat.time =
932 922 member->body.member.member->stat.time;
933 923 }
934 924 }
935 925 /*
936 926 * Check if we found any new auto dependencies when we
937 927 * built the target.
938 928 */
939 929 if ((result == build_ok) && check_auto_dependencies(target,
940 930 auto_count,
941 931 automatics)) {
942 932 if (debug_level > 0) {
943 933 (void) printf(catgets(catd, 1, 18, "%*sTarget `%s' acquired new dependencies from build, rechecking all dependencies\n"),
944 934 recursion_level,
945 935 "",
946 936 true_target->string_mb);
947 937 }
948 938 rechecking_target = true;
949 939 saved_commands_done = commands_done;
950 940 goto recheck_target;
951 941 }
952 942
953 943 if (rechecking_target && !commands_done) {
954 944 commands_done = saved_commands_done;
955 945 }
956 946
957 947 return result;
958 948 }
959 949
960 950 /*
961 951 * DONE.
962 952 *
963 953 * check_dependencies(result, line, do_get,
964 954 * target, true_target, doing_subtree, out_of_date_tail,
965 955 * old_locals, implicit, command, less, rechecking_target)
966 956 *
967 957 * Return value:
968 958 * True returned if some dependencies left running
969 959 *
970 960 * Parameters:
971 961 * result Pointer to cell we update if build failed
972 962 * line We get the dependencies from here
973 963 * do_get Allow use of sccs get in recursive doname()
974 964 * target The target to chase dependencies for
975 965 * true_target The real one for :: and lib(member)
976 966 * doing_subtree True if building a conditional macro subtree
977 967 * out_of_date_tail Used to set the $? list
978 968 * old_locals Used for resetting the local macros
979 969 * implicit Called when scanning for implicit rules?
980 970 * command Place to stuff command
981 971 * less Set to $< value
982 972 *
983 973 * Global variables used:
984 974 * command_changed Set if we suspect .make.state needs rewrite
985 975 * debug_level Should we trace actions?
986 976 * force The Name " FORCE", compared against
987 977 * recursion_level Used for tracing
988 978 * rewrite_statefile Set if .make.state needs rewriting
989 979 * wait_name The Name ".WAIT", compared against
990 980 */
991 981 static Boolean
992 982 #ifdef TEAMWARE_MAKE_CMN
993 983 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
994 984 #else
995 985 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean, Chain *out_of_date_tail, Property, Boolean, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals)
996 986 #endif
997 987 {
998 988 Boolean dependencies_running;
999 989 register Dependency dependency;
1000 990 Doname dep_result;
1001 991 Boolean dependency_changed = false;
1002 992
1003 993 line->body.line.dependency_time = file_doesnt_exist;
1004 994 if (line->body.line.query != NULL) {
1005 995 delete_query_chain(line->body.line.query);
1006 996 }
1007 997 line->body.line.query = NULL;
1008 998 line->body.line.is_out_of_date = false;
1009 999 dependencies_running = false;
1010 1000 /*
1011 1001 * Run thru all the dependencies and call doname() recursively
1012 1002 * on each of them.
1013 1003 */
1014 1004 for (dependency = line->body.line.dependencies;
1015 1005 dependency != NULL;
1016 1006 dependency = dependency->next) {
1017 1007 Boolean this_dependency_changed = false;
1018 1008
1019 1009 if (!dependency->automatic &&
1020 1010 (rechecking_target || target->rechecking_target)) {
1021 1011 /*
1022 1012 * We only bother with the autos when rechecking
1023 1013 */
1024 1014 continue;
1025 1015 }
1026 1016
1027 1017 if (dependency->name == wait_name) {
1028 1018 /*
1029 1019 * The special target .WAIT means finish all of
1030 1020 * the prior dependencies before continuing.
1031 1021 */
1032 1022 if (dependencies_running) {
1033 1023 break;
1034 1024 }
1035 1025 #ifdef DISTRIBUTED
1036 1026 } else if ((!parallel_ok(dependency->name, false)) &&
1037 1027 (dependencies_running)) {
1038 1028 /*
1039 1029 * If we can't execute the current dependency in
1040 1030 * parallel, hold off the dependency processing
1041 1031 * to preserve the order of the dependencies.
1042 1032 */
1043 1033 break;
1044 1034 #endif
1045 1035 } else {
1046 1036 timestruc_t depe_time = file_doesnt_exist;
1047 1037
1048 1038
1049 1039 if (true_target->is_member) {
1050 1040 depe_time = exists(dependency->name);
1051 1041 }
1052 1042 if (dependency->built ||
1053 1043 (dependency->name->state == build_failed)) {
1054 1044 dep_result = (Doname) dependency->name->state;
1055 1045 } else {
1056 1046 dep_result = doname_check(dependency->name,
1057 1047 do_get,
1058 1048 false,
1059 1049 (Boolean) dependency->automatic);
1060 1050 }
1061 1051 if (true_target->is_member || dependency->name->is_member) {
1062 1052 /* should compare only secs, cause lib members does not have nsec time resolution */
1063 1053 if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) {
1064 1054 this_dependency_changed =
1065 1055 dependency_changed =
1066 1056 true;
1067 1057 }
1068 1058 } else {
1069 1059 if (depe_time != dependency->name->stat.time) {
1070 1060 this_dependency_changed =
1071 1061 dependency_changed =
1072 1062 true;
1073 1063 }
1074 1064 }
1075 1065 dependency->built = true;
1076 1066 switch (dep_result) {
1077 1067 case build_running:
1078 1068 dependencies_running = true;
1079 1069 continue;
1080 1070 case build_failed:
1081 1071 *result = build_failed;
1082 1072 break;
1083 1073 case build_dont_know:
1084 1074 /*
1085 1075 * If make can't figure out how to make a dependency, maybe the dependency
1086 1076 * is out of date. In this case, we just declare the target out of date
1087 1077 * and go on. If we really need the dependency, the make'ing of the target
1088 1078 * will fail. This will only happen for automatic (hidden) dependencies.
1089 1079 */
1090 1080 if(!recheck_conditionals) {
1091 1081 line->body.line.is_out_of_date = true;
1092 1082 }
1093 1083 /*
1094 1084 * Make sure the dependency is not saved
1095 1085 * in the state file.
1096 1086 */
1097 1087 dependency->stale = true;
1098 1088 rewrite_statefile =
1099 1089 command_changed =
1100 1090 true;
1101 1091 if (debug_level > 0) {
1102 1092 (void) printf(catgets(catd, 1, 19, "Target %s rebuilt because dependency %s does not exist\n"),
1103 1093 true_target->string_mb,
1104 1094 dependency->name->string_mb);
1105 1095 }
1106 1096 break;
1107 1097 }
1108 1098 if (dependency->name->depends_on_conditional) {
1109 1099 target->depends_on_conditional = true;
1110 1100 }
1111 1101 if (dependency->name == force) {
1112 1102 target->stat.time =
1113 1103 dependency->name->stat.time;
1114 1104 }
1115 1105 /*
1116 1106 * Propagate new timestamp from "member" to
1117 1107 * "lib.a(member)".
1118 1108 */
1119 1109 (void) exists(dependency->name);
1120 1110
1121 1111 /* Collect the timestamp of the youngest dependency */
1122 1112 line->body.line.dependency_time =
1123 1113 MAX(dependency->name->stat.time,
1124 1114 line->body.line.dependency_time);
1125 1115
1126 1116 /* Correction: do not consider nanosecs for members */
1127 1117 if(true_target->is_member || dependency->name->is_member) {
1128 1118 line->body.line.dependency_time.tv_nsec = 0;
1129 1119 }
1130 1120
1131 1121 if (debug_level > 1) {
1132 1122 (void) printf(catgets(catd, 1, 20, "%*sDate(%s)=%s \n"),
1133 1123 recursion_level,
1134 1124 "",
1135 1125 dependency->name->string_mb,
1136 1126 time_to_string(dependency->name->
1137 1127 stat.time));
1138 1128 if (dependency->name->stat.time > line->body.line.dependency_time) {
1139 1129 (void) printf(catgets(catd, 1, 21, "%*sDate-dependencies(%s) set to %s\n"),
1140 1130 recursion_level,
1141 1131 "",
1142 1132 true_target->string_mb,
1143 1133 time_to_string(line->body.line.
1144 1134 dependency_time));
1145 1135 }
1146 1136 }
1147 1137
1148 1138 /* Build the $? list */
1149 1139 if (true_target->is_member) {
1150 1140 if (this_dependency_changed == true) {
1151 1141 true_target->stat.time = dependency->name->stat.time;
1152 1142 true_target->stat.time.tv_sec--;
1153 1143 } else {
1154 1144 /* Dina:
1155 1145 * The next statement is commented
1156 1146 * out as a fix for bug #1051032.
1157 1147 * if dependency hasn't changed
1158 1148 * then there's no need to invalidate
1159 1149 * true_target. This statemnt causes
1160 1150 * make to take much longer to process
1161 1151 * an already-built archive. Soren
1162 1152 * said it was a quick fix for some
1163 1153 * problem he doesn't remember.
1164 1154 true_target->stat.time = file_no_time;
1165 1155 */
1166 1156 (void) exists(true_target);
1167 1157 }
1168 1158 } else {
1169 1159 (void) exists(true_target);
1170 1160 }
1171 1161 Boolean out_of_date;
1172 1162 if (true_target->is_member || dependency->name->is_member) {
1173 1163 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1174 1164 dependency->name->stat.time);
1175 1165 } else {
1176 1166 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1177 1167 dependency->name->stat.time);
1178 1168 }
1179 1169 if ((build_unconditional || out_of_date) &&
1180 1170 (dependency->name != force) &&
1181 1171 (dependency->stale == false)) {
1182 1172 *out_of_date_tail = ALLOC(Chain);
1183 1173 if (dependency->name->is_member &&
1184 1174 (get_prop(dependency->name->prop,
1185 1175 member_prop) != NULL)) {
1186 1176 (*out_of_date_tail)->name =
1187 1177 get_prop(dependency->name->prop,
1188 1178 member_prop)->
1189 1179 body.member.member;
1190 1180 } else {
1191 1181 (*out_of_date_tail)->name =
1192 1182 dependency->name;
1193 1183 }
1194 1184 (*out_of_date_tail)->next = NULL;
1195 1185 out_of_date_tail = &(*out_of_date_tail)->next;
1196 1186 if (debug_level > 0) {
1197 1187 if (dependency->name->stat.time == file_max_time) {
1198 1188 (void) printf(catgets(catd, 1, 22, "%*sBuilding %s because %s does not exist\n"),
1199 1189 recursion_level,
1200 1190 "",
1201 1191 true_target->string_mb,
1202 1192 dependency->name->string_mb);
1203 1193 } else {
1204 1194 (void) printf(catgets(catd, 1, 23, "%*sBuilding %s because it is out of date relative to %s\n"),
1205 1195 recursion_level,
1206 1196 "",
1207 1197 true_target->string_mb,
1208 1198 dependency->name->string_mb);
1209 1199 }
1210 1200 }
1211 1201 }
1212 1202 if (dependency->name == force) {
1213 1203 force->stat.time =
1214 1204 file_max_time;
1215 1205 force->state = build_dont_know;
1216 1206 }
1217 1207 }
1218 1208 }
1219 1209 #ifdef TEAMWARE_MAKE_CMN
1220 1210 if (dependencies_running) {
1221 1211 if (doing_subtree) {
1222 1212 if (target->conditional_cnt > 0) {
1223 1213 reset_locals(target,
1224 1214 old_locals,
1225 1215 get_prop(target->prop,
1226 1216 conditional_prop),
1227 1217 0);
1228 1218 }
1229 1219 return true;
1230 1220 } else {
1231 1221 target->state = build_running;
1232 1222 add_pending(target,
1233 1223 --recursion_level,
1234 1224 do_get,
1235 1225 implicit,
1236 1226 false);
1237 1227 if (target->conditional_cnt > 0) {
1238 1228 reset_locals(target,
1239 1229 old_locals,
1240 1230 get_prop(target->prop,
1241 1231 conditional_prop),
1242 1232 0);
1243 1233 }
1244 1234 return true;
1245 1235 }
1246 1236 }
1247 1237 #endif
1248 1238 /*
1249 1239 * Collect the timestamp of the youngest double colon target
1250 1240 * dependency.
1251 1241 */
1252 1242 if (target->is_double_colon_parent) {
1253 1243 for (dependency = line->body.line.dependencies;
1254 1244 dependency != NULL;
1255 1245 dependency = dependency->next) {
1256 1246 Property tmp_line;
1257 1247
1258 1248 if ((tmp_line = get_prop(dependency->name->prop, line_prop)) != NULL) {
1259 1249 if(tmp_line->body.line.dependency_time != file_max_time) {
1260 1250 target->stat.time =
1261 1251 MAX(tmp_line->body.line.dependency_time,
1262 1252 target->stat.time);
1263 1253 }
1264 1254 }
1265 1255 }
1266 1256 }
1267 1257 if ((true_target->is_member) && (dependency_changed == true)) {
1268 1258 true_target->stat.time = file_no_time;
1269 1259 }
1270 1260 /*
1271 1261 * After scanning all the dependencies, we check the rule
1272 1262 * if we found one.
1273 1263 */
1274 1264 if (line->body.line.command_template != NULL) {
1275 1265 if (line->body.line.command_template_redefined) {
1276 1266 warning(catgets(catd, 1, 24, "Too many rules defined for target %s"),
1277 1267 target->string_mb);
1278 1268 }
1279 1269 *command = line;
1280 1270 /* Check if the target is out of date */
1281 1271 Boolean out_of_date;
1282 1272 if (true_target->is_member) {
1283 1273 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time,
1284 1274 line->body.line.dependency_time);
1285 1275 } else {
1286 1276 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time,
1287 1277 line->body.line.dependency_time);
1288 1278 }
1289 1279 if (build_unconditional || out_of_date){
1290 1280 if(!recheck_conditionals) {
1291 1281 line->body.line.is_out_of_date = true;
1292 1282 }
1293 1283 }
1294 1284 line->body.line.sccs_command = false;
1295 1285 line->body.line.target = true_target;
1296 1286 if(gnu_style) {
1297 1287
1298 1288 // set $< for explicit rule
1299 1289 if(line->body.line.dependencies != NULL) {
1300 1290 less = line->body.line.dependencies->name;
1301 1291 }
1302 1292
1303 1293 // set $* for explicit rule
1304 1294 Name target_body;
1305 1295 Name tt = true_target;
1306 1296 Property member;
1307 1297 register wchar_t *target_end;
1308 1298 register Dependency suffix;
1309 1299 register int suffix_length;
1310 1300 Wstring targ_string;
1311 1301 Wstring suf_string;
1312 1302
1313 1303 if (true_target->is_member &&
1314 1304 ((member = get_prop(target->prop, member_prop)) !=
1315 1305 NULL)) {
1316 1306 tt = member->body.member.member;
1317 1307 }
1318 1308 targ_string.init(tt);
1319 1309 target_end = targ_string.get_string() + tt->hash.length;
1320 1310 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
1321 1311 suffix_length = suffix->name->hash.length;
1322 1312 suf_string.init(suffix->name);
1323 1313 if (tt->hash.length < suffix_length) {
1324 1314 continue;
1325 1315 } else if (!IS_WEQUALN(suf_string.get_string(),
1326 1316 (target_end - suffix_length),
1327 1317 suffix_length)) {
1328 1318 continue;
1329 1319 }
1330 1320 target_body = GETNAME(
1331 1321 targ_string.get_string(),
1332 1322 (int)(tt->hash.length - suffix_length)
1333 1323 );
1334 1324 line->body.line.star = target_body;
1335 1325 }
1336 1326
1337 1327 // set result = build_ok so that implicit rules are not used.
1338 1328 if(*result == build_dont_know) {
1339 1329 *result = build_ok;
1340 1330 }
1341 1331 }
1342 1332 if (less != NULL) {
1343 1333 line->body.line.less = less;
1344 1334 }
1345 1335 }
1346 1336
1347 1337 return false;
1348 1338 }
1349 1339
1350 1340 /*
1351 1341 * dynamic_dependencies(target)
1352 1342 *
1353 1343 * Checks if any dependency contains a macro ref
1354 1344 * If so, it replaces the dependency with the expanded version.
1355 1345 * Here, "$@" gets translated to target->string. That is
1356 1346 * the current name on the left of the colon in the
1357 1347 * makefile. Thus,
1358 1348 * xyz: s.$@.c
1359 1349 * translates into
1360 1350 * xyz: s.xyz.c
1361 1351 *
1362 1352 * Also, "$(@F)" translates to the same thing without a preceeding
1363 1353 * directory path (if one exists).
1364 1354 * Note, to enter "$@" on a dependency line in a makefile
1365 1355 * "$$@" must be typed. This is because make expands
1366 1356 * macros in dependency lists upon reading them.
1367 1357 * dynamic_dependencies() also expands file wildcards.
1368 1358 * If there are any Shell meta characters in the name,
1369 1359 * search the directory, and replace the dependency
1370 1360 * with the set of files the pattern matches
1371 1361 *
1372 1362 * Parameters:
1373 1363 * target Target to sanitize dependencies for
1374 1364 *
1375 1365 * Global variables used:
1376 1366 * c_at The Name "@", used to set macro value
1377 1367 * debug_level Should we trace actions?
1378 1368 * dot The Name ".", used to read directory
1379 1369 * recursion_level Used for tracing
1380 1370 */
1381 1371 void
1382 1372 dynamic_dependencies(Name target)
1383 1373 {
1384 1374 wchar_t pattern[MAXPATHLEN];
1385 1375 register wchar_t *p;
1386 1376 Property line;
1387 1377 register Dependency dependency;
1388 1378 register Dependency *remove;
1389 1379 String_rec string;
1390 1380 wchar_t buffer[MAXPATHLEN];
1391 1381 register Boolean set_at = false;
1392 1382 register wchar_t *start;
1393 1383 Dependency new_depe;
1394 1384 register Boolean reuse_cell;
1395 1385 Dependency first_member;
1396 1386 Name directory;
1397 1387 Name lib;
1398 1388 Name member;
1399 1389 Property prop;
1400 1390 Name true_target = target;
1401 1391 wchar_t *library;
1402 1392
1403 1393 if ((line = get_prop(target->prop, line_prop)) == NULL) {
1404 1394 return;
1405 1395 }
1406 1396 /* If the target is constructed from a "::" target we consider that */
1407 1397 if (target->has_target_prop) {
1408 1398 true_target = get_prop(target->prop,
1409 1399 target_prop)->body.target.target;
1410 1400 }
1411 1401 /* Scan all dependencies and process the ones that contain "$" chars */
1412 1402 for (dependency = line->body.line.dependencies;
1413 1403 dependency != NULL;
1414 1404 dependency = dependency->next) {
1415 1405 if (!dependency->name->dollar) {
1416 1406 continue;
1417 1407 }
1418 1408 target->has_depe_list_expanded = true;
1419 1409
1420 1410 /* The make macro $@ is bound to the target name once per */
1421 1411 /* invocation of dynamic_dependencies() */
1422 1412 if (!set_at) {
1423 1413 (void) SETVAR(c_at, true_target, false);
1424 1414 set_at = true;
1425 1415 }
1426 1416 /* Expand this dependency string */
1427 1417 INIT_STRING_FROM_STACK(string, buffer);
1428 1418 expand_value(dependency->name, &string, false);
1429 1419 /* Scan the expanded string. It could contain whitespace */
1430 1420 /* which mean it expands to several dependencies */
1431 1421 start = string.buffer.start;
1432 1422 while (iswspace(*start)) {
1433 1423 start++;
1434 1424 }
1435 1425 /* Remove the cell (later) if the macro was empty */
1436 1426 if (start[0] == (int) nul_char) {
1437 1427 dependency->name = NULL;
1438 1428 }
1439 1429
1440 1430 /* azv 10/26/95 to fix bug BID_1170218 */
1441 1431 if ((start[0] == (int) period_char) &&
1442 1432 (start[1] == (int) slash_char)) {
1443 1433 start += 2;
1444 1434 }
1445 1435 /* azv */
1446 1436
1447 1437 first_member = NULL;
1448 1438 /* We use the original dependency cell for the first */
1449 1439 /* dependency from the expansion */
1450 1440 reuse_cell = true;
1451 1441 /* We also have to deal with dependencies that expand to */
1452 1442 /* lib.a(members) notation */
1453 1443 for (p = start; *p != (int) nul_char; p++) {
1454 1444 if ((*p == (int) parenleft_char)) {
1455 1445 lib = GETNAME(start, p - start);
1456 1446 lib->is_member = true;
1457 1447 first_member = dependency;
1458 1448 start = p + 1;
1459 1449 while (iswspace(*start)) {
1460 1450 start++;
1461 1451 }
1462 1452 break;
1463 1453 }
1464 1454 }
1465 1455 do {
1466 1456 /* First skip whitespace */
1467 1457 for (p = start; *p != (int) nul_char; p++) {
1468 1458 if ((*p == (int) nul_char) ||
1469 1459 iswspace(*p) ||
1470 1460 (*p == (int) parenright_char)) {
1471 1461 break;
1472 1462 }
1473 1463 }
1474 1464 /* Enter dependency from expansion */
1475 1465 if (p != start) {
1476 1466 /* Create new dependency cell if */
1477 1467 /* this is not the first dependency */
1478 1468 /* picked from the expansion */
1479 1469 if (!reuse_cell) {
1480 1470 new_depe = ALLOC(Dependency);
1481 1471 new_depe->next = dependency->next;
1482 1472 new_depe->automatic = false;
1483 1473 new_depe->stale = false;
1484 1474 new_depe->built = false;
1485 1475 dependency->next = new_depe;
1486 1476 dependency = new_depe;
1487 1477 }
1488 1478 reuse_cell = false;
1489 1479 /* Internalize the dependency name */
1490 1480 // tolik. Fix for bug 4110429: inconsistent expansion for macros that
1491 1481 // include "//" and "/./"
1492 1482 //dependency->name = GETNAME(start, p - start);
1493 1483 dependency->name = normalize_name(start, p - start);
1494 1484 if ((debug_level > 0) &&
1495 1485 (first_member == NULL)) {
1496 1486 (void) printf(catgets(catd, 1, 25, "%*sDynamic dependency `%s' for target `%s'\n"),
1497 1487 recursion_level,
1498 1488 "",
1499 1489 dependency->name->string_mb,
1500 1490 true_target->string_mb);
1501 1491 }
1502 1492 for (start = p; iswspace(*start); start++);
1503 1493 p = start;
1504 1494 }
1505 1495 } while ((*p != (int) nul_char) &&
1506 1496 (*p != (int) parenright_char));
1507 1497 /* If the expansion was of lib.a(members) format we now */
1508 1498 /* enter the proper member cells */
1509 1499 if (first_member != NULL) {
1510 1500 /* Scan the new dependencies and transform them from */
1511 1501 /* "foo" to "lib.a(foo)" */
1512 1502 for (; 1; first_member = first_member->next) {
1513 1503 /* Build "lib.a(foo)" name */
1514 1504 INIT_STRING_FROM_STACK(string, buffer);
1515 1505 APPEND_NAME(lib,
1516 1506 &string,
1517 1507 (int) lib->hash.length);
1518 1508 append_char((int) parenleft_char, &string);
1519 1509 APPEND_NAME(first_member->name,
1520 1510 &string,
1521 1511 FIND_LENGTH);
1522 1512 append_char((int) parenright_char, &string);
1523 1513 member = first_member->name;
1524 1514 /* Replace "foo" with "lib.a(foo)" */
1525 1515 first_member->name =
1526 1516 GETNAME(string.buffer.start, FIND_LENGTH);
1527 1517 if (string.free_after_use) {
1528 1518 retmem(string.buffer.start);
1529 1519 }
1530 1520 if (debug_level > 0) {
1531 1521 (void) printf(catgets(catd, 1, 26, "%*sDynamic dependency `%s' for target `%s'\n"),
1532 1522 recursion_level,
1533 1523 "",
1534 1524 first_member->name->
1535 1525 string_mb,
1536 1526 true_target->string_mb);
1537 1527 }
1538 1528 first_member->name->is_member = lib->is_member;
1539 1529 /* Add member property to member */
1540 1530 prop = maybe_append_prop(first_member->name,
1541 1531 member_prop);
1542 1532 prop->body.member.library = lib;
1543 1533 prop->body.member.entry = NULL;
1544 1534 prop->body.member.member = member;
1545 1535 if (first_member == dependency) {
1546 1536 break;
1547 1537 }
1548 1538 }
1549 1539 }
1550 1540 }
1551 1541 Wstring wcb;
1552 1542 /* Then scan all the dependencies again. This time we want to expand */
1553 1543 /* shell file wildcards */
1554 1544 for (remove = &line->body.line.dependencies, dependency = *remove;
1555 1545 dependency != NULL;
1556 1546 dependency = *remove) {
1557 1547 if (dependency->name == NULL) {
1558 1548 dependency = *remove = (*remove)->next;
1559 1549 continue;
1560 1550 }
1561 1551 /* If dependency name string contains shell wildcards */
1562 1552 /* replace the name with the expansion */
1563 1553 if (dependency->name->wildcard) {
1564 1554 wcb.init(dependency->name);
1565 1555 if ((start = (wchar_t *) wschr(wcb.get_string(),
1566 1556 (int) parenleft_char)) != NULL) {
1567 1557 /* lib(*) type pattern */
1568 1558 library = buffer;
1569 1559 (void) wsncpy(buffer,
1570 1560 wcb.get_string(),
1571 1561 start - wcb.get_string());
1572 1562 buffer[start-wcb.get_string()] =
1573 1563 (int) nul_char;
1574 1564 (void) wsncpy(pattern,
1575 1565 start + 1,
1576 1566 (int) (dependency->name->hash.length-(start-wcb.get_string())-2));
1577 1567 pattern[dependency->name->hash.length -
1578 1568 (start-wcb.get_string()) - 2] =
1579 1569 (int) nul_char;
1580 1570 } else {
1581 1571 library = NULL;
1582 1572 (void) wsncpy(pattern,
1583 1573 wcb.get_string(),
1584 1574 (int) dependency->name->hash.length);
1585 1575 pattern[dependency->name->hash.length] =
1586 1576 (int) nul_char;
1587 1577 }
1588 1578 start = (wchar_t *) wsrchr(pattern, (int) slash_char);
1589 1579 if (start == NULL) {
1590 1580 directory = dot;
1591 1581 p = pattern;
1592 1582 } else {
1593 1583 directory = GETNAME(pattern, start-pattern);
1594 1584 p = start+1;
1595 1585 }
1596 1586 /* The expansion is handled by the read_dir() routine*/
1597 1587 if (read_dir(directory, p, line, library)) {
1598 1588 *remove = (*remove)->next;
1599 1589 } else {
1600 1590 remove = &dependency->next;
1601 1591 }
1602 1592 } else {
1603 1593 remove = &dependency->next;
1604 1594 }
1605 1595 }
1606 1596
1607 1597 /* Then unbind $@ */
1608 1598 (void) SETVAR(c_at, (Name) NULL, false);
1609 1599 }
1610 1600
1611 1601 /*
1612 1602 * DONE.
1613 1603 *
1614 1604 * run_command(line)
1615 1605 *
1616 1606 * Takes one Cmd_line and runs the commands from it.
1617 1607 *
1618 1608 * Return value:
1619 1609 * Indicates if the command failed or not
1620 1610 *
1621 1611 * Parameters:
1622 1612 * line The command line to run
1623 1613 *
1624 1614 * Global variables used:
1625 1615 * commands_done Set if we do run command
1626 1616 * current_line Set to the line we run a command from
1627 1617 * current_target Set to the target we run a command for
1628 1618 * file_number Used to form temp file name
1629 1619 * keep_state Indicates that .KEEP_STATE is on
1630 1620 * make_state The Name ".make.state", used to check timestamp
1631 1621 * parallel True if currently building in parallel
1632 1622 * parallel_process_cnt Count of parallel processes running
1633 1623 * quest Indicates that make -q is on
1634 1624 * rewrite_statefile Set if we do run a command
1635 1625 * sunpro_dependencies The Name "SUNPRO_DEPENDENCIES", set value
1636 1626 * temp_file_directory Used to form temp fie name
1637 1627 * temp_file_name Set to the name of the temp file
1638 1628 * touch Indicates that make -t is on
1639 1629 */
1640 1630 static Doname
1641 1631 run_command(register Property line, Boolean)
1642 1632 {
1643 1633 register Doname result = build_ok;
1644 1634 register Boolean remember_only = false;
1645 1635 register Name target = line->body.line.target;
1646 1636 wchar_t *string;
1647 1637 char tmp_file_path[MAXPATHLEN];
1648 1638
1649 1639 if (!line->body.line.is_out_of_date && target->rechecking_target) {
1650 1640 target->rechecking_target = false;
1651 1641 return build_ok;
1652 1642 }
1653 1643
1654 1644 /*
1655 1645 * Build the command if we know the target is out of date,
1656 1646 * or if we want to check cmd consistency.
1657 1647 */
1658 1648 if (line->body.line.is_out_of_date || keep_state) {
1659 1649 /* Hack for handling conditional macros in DMake. */
1660 1650 if (!line->body.line.dont_rebuild_command_used) {
1661 1651 build_command_strings(target, line);
1662 1652 }
1663 1653 }
1664 1654 /* Never mind */
1665 1655 if (!line->body.line.is_out_of_date) {
1666 1656 return build_ok;
1667 1657 }
1668 1658 /* If quest, then exit(1) because the target is out of date */
1669 1659 if (quest) {
1670 1660 if (posix) {
1671 1661 #ifdef TEAMWARE_MAKE_CMN
1672 1662 result = execute_parallel(line, true);
1673 1663 #else
1674 1664 result = execute_serial(line);
1675 1665 #endif
1676 1666 }
1677 1667 exit_status = 1;
1678 1668 exit(1);
1679 1669 }
1680 1670 /* We actually had to do something this time */
1681 1671 rewrite_statefile = commands_done = true;
1682 1672 /*
1683 1673 * If this is an sccs command, we have to do some extra checking
1684 1674 * and possibly complain. If the file can't be gotten because it's
1685 1675 * checked out, we complain and behave as if the command was
1686 1676 * executed eventhough we ignored the command.
1687 1677 */
1688 1678 if (!touch &&
1689 1679 line->body.line.sccs_command &&
1690 1680 (target->stat.time != file_doesnt_exist) &&
1691 1681 ((target->stat.mode & 0222) != 0)) {
1692 1682 fatal(catgets(catd, 1, 27, "%s is writable so it cannot be sccs gotten"),
1693 1683 target->string_mb);
1694 1684 target->has_complained = remember_only = true;
1695 1685 }
1696 1686 /*
1697 1687 * If KEEP_STATE is on, we make sure we have the timestamp for
1698 1688 * .make.state. If .make.state changes during the command run,
1699 1689 * we reread .make.state after the command. We also setup the
1700 1690 * environment variable that asks utilities to report dependencies.
1701 1691 */
1702 1692 if (!touch &&
1703 1693 keep_state &&
1704 1694 !remember_only) {
1705 1695 (void) exists(make_state);
1706 1696 if((strlen(temp_file_directory) == 1) &&
1707 1697 (temp_file_directory[0] == '/')) {
1708 1698 tmp_file_path[0] = '\0';
1709 1699 } else {
1710 1700 strcpy(tmp_file_path, temp_file_directory);
1711 1701 }
1712 1702 sprintf(mbs_buffer,
1713 1703 NOCATGETS("%s/.make.dependency.%08x.%d.%d"),
1714 1704 tmp_file_path,
1715 1705 hostid,
1716 1706 getpid(),
1717 1707 file_number++);
1718 1708 MBSTOWCS(wcs_buffer, mbs_buffer);
1719 1709 Boolean fnd;
1720 1710 temp_file_name = getname_fn(wcs_buffer, FIND_LENGTH, false, &fnd);
1721 1711 temp_file_name->stat.is_file = true;
1722 1712 int len = 2*MAXPATHLEN + strlen(target->string_mb) + 2;
1723 1713 wchar_t *to = string = ALLOC_WC(len);
1724 1714 for (wchar_t *from = wcs_buffer; *from != (int) nul_char; ) {
1725 1715 if (*from == (int) space_char) {
1726 1716 *to++ = (int) backslash_char;
1727 1717 }
1728 1718 *to++ = *from++;
1729 1719 }
1730 1720 *to++ = (int) space_char;
1731 1721 MBSTOWCS(to, target->string_mb);
1732 1722 Name sprodep_name = getname_fn(string, FIND_LENGTH, false, &fnd);
1733 1723 (void) SETVAR(sunpro_dependencies,
1734 1724 sprodep_name,
1735 1725 false);
1736 1726 retmem(string);
1737 1727 } else {
1738 1728 temp_file_name = NULL;
1739 1729 }
1740 1730
1741 1731 /*
1742 1732 * In case we are interrupted, we need to know what was going on.
1743 1733 */
1744 1734 current_target = target;
1745 1735 /*
1746 1736 * We also need to be able to save an empty command instead of the
1747 1737 * interrupted one in .make.state.
1748 1738 */
1749 1739 current_line = line;
1750 1740 if (remember_only) {
1751 1741 /* Empty block!!! */
1752 1742 } else if (touch) {
1753 1743 result = touch_command(line, target, result);
1754 1744 if (posix) {
1755 1745 #ifdef TEAMWARE_MAKE_CMN
1756 1746 result = execute_parallel(line, true);
1757 1747 #else
1758 1748 result = execute_serial(line);
1759 1749 #endif
1760 1750 }
1761 1751 } else {
1762 1752 /*
1763 1753 * If this is not a touch run, we need to execute the
1764 1754 * proper command(s) for the target.
1765 1755 */
1766 1756 #ifdef TEAMWARE_MAKE_CMN
1767 1757 if (parallel) {
1768 1758 if (!parallel_ok(target, true)) {
1769 1759 /*
1770 1760 * We are building in parallel, but
1771 1761 * this target must be built in serial.
1772 1762 */
1773 1763 /*
1774 1764 * If nothing else is building,
1775 1765 * do this one, else wait.
1776 1766 */
1777 1767 if (parallel_process_cnt == 0) {
1778 1768 #ifdef TEAMWARE_MAKE_CMN
1779 1769 result = execute_parallel(line, true, target->localhost);
1780 1770 #else
1781 1771 result = execute_serial(line);
1782 1772 #endif
1783 1773 } else {
1784 1774 current_target = NULL;
1785 1775 current_line = NULL;
1786 1776 /*
1787 1777 line->body.line.command_used = NULL;
1788 1778 */
1789 1779 line->body.line.dont_rebuild_command_used = true;
1790 1780 return build_serial;
1791 1781 }
1792 1782 } else {
1793 1783 result = execute_parallel(line, false);
1794 1784 switch (result) {
1795 1785 case build_running:
1796 1786 return build_running;
1797 1787 case build_serial:
1798 1788 if (parallel_process_cnt == 0) {
1799 1789 #ifdef TEAMWARE_MAKE_CMN
1800 1790 result = execute_parallel(line, true, target->localhost);
1801 1791 #else
1802 1792 result = execute_serial(line);
1803 1793 #endif
1804 1794 } else {
1805 1795 current_target = NULL;
1806 1796 current_line = NULL;
1807 1797 target->parallel = false;
1808 1798 line->body.line.command_used =
1809 1799 NULL;
1810 1800 return build_serial;
1811 1801 }
1812 1802 }
1813 1803 }
1814 1804 } else {
1815 1805 #endif
1816 1806 #ifdef TEAMWARE_MAKE_CMN
1817 1807 result = execute_parallel(line, true, target->localhost);
1818 1808 #else
1819 1809 result = execute_serial(line);
1820 1810 #endif
1821 1811 #ifdef TEAMWARE_MAKE_CMN
1822 1812 }
1823 1813 #endif
1824 1814 }
1825 1815 temp_file_name = NULL;
1826 1816 if (report_dependencies_level == 0){
1827 1817 update_target(line, result);
1828 1818 }
1829 1819 current_target = NULL;
1830 1820 current_line = NULL;
1831 1821 return result;
1832 1822 }
1833 1823
1834 1824 /*
1835 1825 * execute_serial(line)
1836 1826 *
1837 1827 * Runs thru the command line for the target and
1838 1828 * executes the rules one by one.
1839 1829 *
1840 1830 * Return value:
1841 1831 * The result of the command build
1842 1832 *
1843 1833 * Parameters:
1844 1834 * line The command to execute
1845 1835 *
1846 1836 * Static variables used:
1847 1837 *
1848 1838 * Global variables used:
1849 1839 * continue_after_error -k flag
1850 1840 * do_not_exec_rule -n flag
1851 1841 * report_dependencies -P flag
1852 1842 * silent Don't echo commands before executing
1853 1843 * temp_file_name Temp file for auto dependencies
1854 1844 * vpath_defined If true, translate path for command
1855 1845 */
1856 1846 Doname
1857 1847 execute_serial(Property line)
1858 1848 {
1859 1849 int child_pid = 0;
1860 1850 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
1861 1851 Avo_MToolJobResultMsg *job_result_msg;
1862 1852 RWCollectable *xdr_msg;
1863 1853 #endif
1864 1854 Boolean printed_serial;
1865 1855 Doname result = build_ok;
1866 1856 Cmd_line rule, cmd_tail, command = NULL;
1867 1857 char mbstring[MAXPATHLEN];
1868 1858 int filed;
1869 1859 Name target = line->body.line.target;
1870 1860
1871 1861 SEND_MTOOL_MSG(
1872 1862 if (!sent_rsrc_info_msg) {
1873 1863 if (userName[0] == '\0') {
1874 1864 avo_get_user(userName, NULL);
1875 1865 }
1876 1866 if (hostName[0] == '\0') {
1877 1867 strcpy(hostName, avo_hostname());
1878 1868 }
1879 1869 send_rsrc_info_msg(1, hostName, userName);
1880 1870 sent_rsrc_info_msg = 1;
1881 1871 }
1882 1872 send_job_start_msg(line);
1883 1873 job_result_msg = new Avo_MToolJobResultMsg();
1884 1874 );
1885 1875
1886 1876 target->has_recursive_dependency = false;
1887 1877 // We have to create a copy of the rules chain for processing because
1888 1878 // the original one can be destroyed during .make.state file rereading.
1889 1879 for (rule = line->body.line.command_used;
1890 1880 rule != NULL;
1891 1881 rule = rule->next) {
1892 1882 if (command == NULL) {
1893 1883 command = cmd_tail = ALLOC(Cmd_line);
1894 1884 } else {
1895 1885 cmd_tail->next = ALLOC(Cmd_line);
1896 1886 cmd_tail = cmd_tail->next;
1897 1887 }
1898 1888 *cmd_tail = *rule;
1899 1889 }
1900 1890 if (command) {
1901 1891 cmd_tail->next = NULL;
1902 1892 }
1903 1893 for (rule = command; rule != NULL; rule = rule->next) {
1904 1894 if (posix && (touch || quest) && !rule->always_exec) {
1905 1895 continue;
1906 1896 }
1907 1897 if (vpath_defined) {
1908 1898 rule->command_line =
1909 1899 vpath_translation(rule->command_line);
1910 1900 }
1911 1901 /* Echo command line, maybe. */
1912 1902 if ((rule->command_line->hash.length > 0) &&
1913 1903 !silent &&
1914 1904 (!rule->silent || do_not_exec_rule) &&
1915 1905 (report_dependencies_level == 0)) {
1916 1906 (void) printf("%s\n", rule->command_line->string_mb);
1917 1907 SEND_MTOOL_MSG(
1918 1908 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb));
1919 1909 );
1920 1910 }
1921 1911 if (rule->command_line->hash.length > 0) {
1922 1912 SEND_MTOOL_MSG(
1923 1913 (void) sprintf(mbstring,
1924 1914 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"),
1925 1915 tmpdir,
1926 1916 getpid(),
1927 1917 file_number++);
1928 1918
1929 1919 int tmp_fd = mkstemp(mbstring);
1930 1920 if(tmp_fd) {
1931 1921 (void) close(tmp_fd);
1932 1922 }
1933 1923
1934 1924 stdout_file = strdup(mbstring);
1935 1925 stderr_file = NULL;
1936 1926 child_pid = pollResults(stdout_file,
1937 1927 (char *)NULL,
1938 1928 (char *)NULL);
1939 1929 );
1940 1930 /* Do assignment if command line prefixed with "=" */
1941 1931 if (rule->assign) {
1942 1932 result = build_ok;
1943 1933 do_assign(rule->command_line, target);
1944 1934 } else if (report_dependencies_level == 0) {
1945 1935 /* Execute command line. */
1946 1936 #ifdef DISTRIBUTED
1947 1937 setvar_envvar((Avo_DoJobMsg *)NULL);
1948 1938 #else
1949 1939 setvar_envvar();
1950 1940 #endif
1951 1941 result = dosys(rule->command_line,
1952 1942 (Boolean) rule->ignore_error,
1953 1943 (Boolean) rule->make_refd,
1954 1944 /* ds 98.04.23 bug #4085164. make should always show error messages */
1955 1945 false,
1956 1946 /* BOOLEAN(rule->silent &&
1957 1947 rule->ignore_error), */
1958 1948 (Boolean) rule->always_exec,
1959 1949 target,
1960 1950 send_mtool_msgs);
1961 1951 check_state(temp_file_name);
1962 1952 }
1963 1953 SEND_MTOOL_MSG(
1964 1954 append_job_result_msg(job_result_msg);
1965 1955 if (child_pid > 0) {
1966 1956 kill(child_pid, SIGUSR1);
1967 1957 while (!((waitpid(child_pid, 0, 0) == -1)
1968 1958 && (errno == ECHILD)));
1969 1959 }
1970 1960 child_pid = 0;
1971 1961 (void) unlink(stdout_file);
1972 1962 retmem_mb(stdout_file);
1973 1963 stdout_file = NULL;
1974 1964 );
1975 1965 } else {
1976 1966 result = build_ok;
1977 1967 }
1978 1968 if (result == build_failed) {
1979 1969 if (silent || rule->silent) {
1980 1970 (void) printf(catgets(catd, 1, 242, "The following command caused the error:\n%s\n"),
1981 1971 rule->command_line->string_mb);
1982 1972 SEND_MTOOL_MSG(
1983 1973 job_result_msg->appendOutput(AVO_STRDUP(catgets(catd, 1, 243, "The following command caused the error:")));
1984 1974 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb));
1985 1975 );
1986 1976 }
1987 1977 if (!rule->ignore_error && !ignore_errors) {
1988 1978 if (!continue_after_error) {
1989 1979 SEND_MTOOL_MSG(
1990 1980 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
1991 1981 xdr_msg = (RWCollectable*)
1992 1982 job_result_msg;
1993 1983 xdr(&xdrs, xdr_msg);
1994 1984 (void) fflush(mtool_msgs_fp);
1995 1985 delete job_result_msg;
1996 1986 );
1997 1987 fatal(catgets(catd, 1, 244, "Command failed for target `%s'"),
1998 1988 target->string_mb);
1999 1989 }
2000 1990 /*
2001 1991 * Make sure a failing command is not
2002 1992 * saved in .make.state.
2003 1993 */
2004 1994 line->body.line.command_used = NULL;
2005 1995 break;
2006 1996 } else {
2007 1997 result = build_ok;
2008 1998 }
2009 1999 }
2010 2000 }
2011 2001 for (rule = command; rule != NULL; rule = cmd_tail) {
2012 2002 cmd_tail = rule->next;
2013 2003 free(rule);
2014 2004 }
2015 2005 command = NULL;
2016 2006 SEND_MTOOL_MSG(
2017 2007 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2018 2008 xdr_msg = (RWCollectable*) job_result_msg;
2019 2009 xdr(&xdrs, xdr_msg);
2020 2010 (void) fflush(mtool_msgs_fp);
2021 2011
2022 2012 delete job_result_msg;
2023 2013 );
2024 2014 if (temp_file_name != NULL) {
2025 2015 free_name(temp_file_name);
2026 2016 }
2027 2017 temp_file_name = NULL;
2028 2018
2029 2019 Property spro = get_prop(sunpro_dependencies->prop, macro_prop);
2030 2020 if(spro != NULL) {
2031 2021 Name val = spro->body.macro.value;
2032 2022 if(val != NULL) {
2033 2023 free_name(val);
2034 2024 spro->body.macro.value = NULL;
2035 2025 }
2036 2026 }
2037 2027 spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
2038 2028 if(spro) {
2039 2029 char *val = spro->body.env_mem.value;
2040 2030 if(val != NULL) {
2041 2031 /*
2042 2032 * Do not return memory allocated for SUNPRO_DEPENDENCIES
2043 2033 * It will be returned in setvar_daemon() in macro.cc
2044 2034 */
2045 2035 // retmem_mb(val);
2046 2036 spro->body.env_mem.value = NULL;
2047 2037 }
2048 2038 }
2049 2039
2050 2040 return result;
2051 2041 }
2052 2042
2053 2043
2054 2044 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
2055 2045
2056 2046 /*
2057 2047 * Create and send an Avo_MToolRsrcInfoMsg.
2058 2048 */
2059 2049 void
2060 2050 send_rsrc_info_msg(int max_jobs, char *hostname, char *username)
2061 2051 {
2062 2052 static int first = 1;
2063 2053 Avo_MToolRsrcInfoMsg *msg;
2064 2054 RWSlistCollectables server_list;
2065 2055 Avo_ServerState *server_state;
2066 2056 RWCollectable *xdr_msg;
2067 2057
2068 2058 if (!first) {
2069 2059 return;
2070 2060 }
2071 2061 first = 0;
2072 2062
2073 2063 create_xdrs_ptr();
2074 2064
2075 2065 server_state = new Avo_ServerState(max_jobs, hostname, username);
2076 2066 server_list.append(server_state);
2077 2067 msg = new Avo_MToolRsrcInfoMsg(&server_list);
2078 2068
2079 2069 xdr_msg = (RWCollectable *)msg;
2080 2070 xdr(get_xdrs_ptr(), xdr_msg);
2081 2071 (void) fflush(get_mtool_msgs_fp());
2082 2072
2083 2073 delete server_state;
2084 2074 delete msg;
2085 2075 }
2086 2076
2087 2077 /*
2088 2078 * Create and send an Avo_MToolJobStartMsg.
2089 2079 */
2090 2080 void
2091 2081 send_job_start_msg(Property line)
2092 2082 {
2093 2083 int cmd_options = 0;
2094 2084 Avo_MToolJobStartMsg *msg;
2095 2085 Cmd_line rule;
2096 2086 Name target = line->body.line.target;
2097 2087 RWCollectable *xdr_msg;
2098 2088
2099 2089 if (userName[0] == '\0') {
2100 2090 avo_get_user(userName, NULL);
2101 2091 }
2102 2092 if (hostName[0] == '\0') {
2103 2093 strcpy(hostName, avo_hostname());
2104 2094 }
2105 2095
2106 2096 msg = new Avo_MToolJobStartMsg();
2107 2097 msg->setJobId(++job_msg_id);
2108 2098 msg->setTarget(AVO_STRDUP(target->string_mb));
2109 2099 msg->setHost(AVO_STRDUP(hostName));
2110 2100 msg->setUser(AVO_STRDUP(userName));
2111 2101
2112 2102 for (rule = line->body.line.command_used;
2113 2103 rule != NULL;
2114 2104 rule = rule->next) {
2115 2105 if (posix && (touch || quest) && !rule->always_exec) {
2116 2106 continue;
2117 2107 }
2118 2108 if (vpath_defined) {
2119 2109 rule->command_line =
2120 2110 vpath_translation(rule->command_line);
2121 2111 }
2122 2112 cmd_options = 0;
2123 2113 if (rule->ignore_error || ignore_errors) {
2124 2114 cmd_options |= ignore_mask;
2125 2115 }
2126 2116 if (rule->silent || silent) {
2127 2117 cmd_options |= silent_mask;
2128 2118 }
2129 2119 if (rule->command_line->meta) {
2130 2120 cmd_options |= meta_mask;
2131 2121 }
2132 2122 if (!touch && (rule->command_line->hash.length > 0)) {
2133 2123 msg->appendCmd(new Avo_DmakeCommand(rule->command_line->string_mb, cmd_options));
2134 2124 }
2135 2125 }
2136 2126
2137 2127 xdr_msg = (RWCollectable*) msg;
2138 2128 xdr(&xdrs, xdr_msg);
2139 2129 (void) fflush(mtool_msgs_fp);
2140 2130
2141 2131 /* tolik, 08/39/2002.
2142 2132 I commented out this code because it causes using unallocated memory.
2143 2133 delete msg;
2144 2134 */
2145 2135 }
2146 2136
2147 2137 /*
2148 2138 * Append the stdout/err to Avo_MToolJobResultMsg.
2149 2139 */
2150 2140 static void
2151 2141 append_job_result_msg(Avo_MToolJobResultMsg *job_result_msg)
2152 2142 {
2153 2143 FILE *fp;
2154 2144 char line[MAXPATHLEN];
2155 2145 char stdout_file2[MAXPATHLEN];
2156 2146
2157 2147 if (stdout_file != NULL) {
2158 2148 fp = fopen(stdout_file, "r");
2159 2149 if (fp == NULL) {
2160 2150 /* Hmmm... what should we do here? */
2161 2151 warning(catgets(catd, 1, 326, "fopen() of stdout_file failed. Output may be lost"));
2162 2152 return;
2163 2153 }
2164 2154 while (fgets(line, MAXPATHLEN, fp) != NULL) {
2165 2155 if (line[strlen(line) - 1] == '\n') {
2166 2156 line[strlen(line) - 1] = '\0';
2167 2157 }
2168 2158 job_result_msg->appendOutput(AVO_STRDUP(line));
2169 2159 }
2170 2160 (void) fclose(fp);
2171 2161 us_sleep(STAT_RETRY_SLEEP_TIME);
2172 2162 } else {
2173 2163 /* Hmmm... stdout_file shouldn't be NULL */
2174 2164 warning(catgets(catd, 1, 327, "Internal stdout_file variable shouldn't be NULL. Output may be lost"));
2175 2165 }
2176 2166 }
2177 2167 #endif /* TEAMWARE_MAKE_CMN */
2178 2168
2179 2169 /*
2180 2170 * vpath_translation(cmd)
2181 2171 *
2182 2172 * Translates one command line by
2183 2173 * checking each word. If the word has an alias it is translated.
2184 2174 *
2185 2175 * Return value:
2186 2176 * The translated command
2187 2177 *
2188 2178 * Parameters:
2189 2179 * cmd Command to translate
2190 2180 *
2191 2181 * Global variables used:
2192 2182 */
2193 2183 Name
2194 2184 vpath_translation(register Name cmd)
2195 2185 {
2196 2186 wchar_t buffer[STRING_BUFFER_LENGTH];
2197 2187 String_rec new_cmd;
2198 2188 wchar_t *p;
2199 2189 wchar_t *start;
2200 2190
2201 2191 if (!vpath_defined || (cmd == NULL) || (cmd->hash.length == 0)) {
2202 2192 return cmd;
2203 2193 }
2204 2194 INIT_STRING_FROM_STACK(new_cmd, buffer);
2205 2195
2206 2196 Wstring wcb(cmd);
2207 2197 p = wcb.get_string();
2208 2198
2209 2199 while (*p != (int) nul_char) {
2210 2200 while (iswspace(*p) && (*p != (int) nul_char)) {
2211 2201 append_char(*p++, &new_cmd);
2212 2202 }
2213 2203 start = p;
2214 2204 while (!iswspace(*p) && (*p != (int) nul_char)) {
2215 2205 p++;
2216 2206 }
2217 2207 cmd = GETNAME(start, p - start);
2218 2208 if (cmd->has_vpath_alias_prop) {
2219 2209 cmd = get_prop(cmd->prop, vpath_alias_prop)->
2220 2210 body.vpath_alias.alias;
2221 2211 APPEND_NAME(cmd,
2222 2212 &new_cmd,
2223 2213 (int) cmd->hash.length);
2224 2214 } else {
2225 2215 append_string(start, &new_cmd, p - start);
2226 2216 }
2227 2217 }
2228 2218 cmd = GETNAME(new_cmd.buffer.start, FIND_LENGTH);
2229 2219 if (new_cmd.free_after_use) {
2230 2220 retmem(new_cmd.buffer.start);
2231 2221 }
2232 2222 return cmd;
2233 2223 }
2234 2224
2235 2225 /*
2236 2226 * check_state(temp_file_name)
2237 2227 *
2238 2228 * Reads and checks the state changed by the previously executed command.
2239 2229 *
2240 2230 * Parameters:
2241 2231 * temp_file_name The auto dependency temp file
2242 2232 *
2243 2233 * Global variables used:
2244 2234 */
2245 2235 void
2246 2236 check_state(Name temp_file_name)
2247 2237 {
2248 2238 if (!keep_state) {
2249 2239 return;
2250 2240 }
2251 2241
2252 2242 /*
2253 2243 * Then read the temp file that now might
2254 2244 * contain dependency reports from utilities
2255 2245 */
2256 2246 read_dependency_file(temp_file_name);
2257 2247
2258 2248 /*
2259 2249 * And reread .make.state if it
2260 2250 * changed (the command ran recursive makes)
2261 2251 */
2262 2252 check_read_state_file();
2263 2253 if (temp_file_name != NULL) {
2264 2254 (void) unlink(temp_file_name->string_mb);
2265 2255 }
2266 2256 }
2267 2257
2268 2258 /*
2269 2259 * read_dependency_file(filename)
2270 2260 *
2271 2261 * Read the temp file used for reporting dependencies to make
2272 2262 *
2273 2263 * Parameters:
2274 2264 * filename The name of the file with the state info
2275 2265 *
2276 2266 * Global variables used:
2277 2267 * makefile_type The type of makefile being read
2278 2268 * read_trace_level Debug flag
2279 2269 * temp_file_number The always increasing number for unique files
2280 2270 * trace_reader Debug flag
2281 2271 */
2282 2272 static void
2283 2273 read_dependency_file(register Name filename)
2284 2274 {
2285 2275 register Makefile_type save_makefile_type;
2286 2276
2287 2277 if (filename == NULL) {
2288 2278 return;
2289 2279 }
2290 2280 filename->stat.time = file_no_time;
2291 2281 if (exists(filename) > file_doesnt_exist) {
2292 2282 save_makefile_type = makefile_type;
2293 2283 makefile_type = reading_cpp_file;
2294 2284 if (read_trace_level > 1) {
2295 2285 trace_reader = true;
2296 2286 }
2297 2287 temp_file_number++;
2298 2288 (void) read_simple_file(filename,
2299 2289 false,
2300 2290 false,
2301 2291 false,
2302 2292 false,
2303 2293 false,
2304 2294 false);
2305 2295 trace_reader = false;
2306 2296 makefile_type = save_makefile_type;
2307 2297 }
2308 2298 }
2309 2299
2310 2300 /*
2311 2301 * check_read_state_file()
2312 2302 *
2313 2303 * Check if .make.state has changed
2314 2304 * If it has we reread it
2315 2305 *
2316 2306 * Parameters:
2317 2307 *
2318 2308 * Global variables used:
2319 2309 * make_state Make state file name
2320 2310 * makefile_type Type of makefile being read
2321 2311 * read_trace_level Debug flag
2322 2312 * trace_reader Debug flag
2323 2313 */
2324 2314 static void
2325 2315 check_read_state_file(void)
2326 2316 {
2327 2317 timestruc_t previous = make_state->stat.time;
2328 2318 register Makefile_type save_makefile_type;
2329 2319 register Property makefile;
2330 2320
2331 2321 make_state->stat.time = file_no_time;
2332 2322 if ((exists(make_state) == file_doesnt_exist) ||
2333 2323 (make_state->stat.time == previous)) {
2334 2324 return;
2335 2325 }
2336 2326 save_makefile_type = makefile_type;
2337 2327 makefile_type = rereading_statefile;
2338 2328 /* Make sure we clear the old cached contents of .make.state */
2339 2329 makefile = maybe_append_prop(make_state, makefile_prop);
2340 2330 if (makefile->body.makefile.contents != NULL) {
2341 2331 retmem(makefile->body.makefile.contents);
2342 2332 makefile->body.makefile.contents = NULL;
2343 2333 }
2344 2334 if (read_trace_level > 1) {
2345 2335 trace_reader = true;
2346 2336 }
2347 2337 temp_file_number++;
2348 2338 (void) read_simple_file(make_state,
2349 2339 false,
2350 2340 false,
2351 2341 false,
2352 2342 false,
2353 2343 false,
2354 2344 true);
2355 2345 trace_reader = false;
2356 2346 makefile_type = save_makefile_type;
2357 2347 }
2358 2348
2359 2349 /*
2360 2350 * do_assign(line, target)
2361 2351 *
2362 2352 * Handles runtime assignments for command lines prefixed with "=".
2363 2353 *
2364 2354 * Parameters:
2365 2355 * line The command that contains an assignment
2366 2356 * target The Name of the target, used for error reports
2367 2357 *
2368 2358 * Global variables used:
2369 2359 * assign_done Set to indicate doname needs to reprocess
2370 2360 */
2371 2361 static void
2372 2362 do_assign(register Name line, register Name target)
2373 2363 {
2374 2364 Wstring wcb(line);
2375 2365 register wchar_t *string = wcb.get_string();
2376 2366 register wchar_t *equal;
2377 2367 register Name name;
2378 2368 register Boolean append = false;
2379 2369
2380 2370 /*
2381 2371 * If any runtime assignments are done, doname() must reprocess all
2382 2372 * targets in the future since the macro values used to build the
2383 2373 * command lines for the targets might have changed.
2384 2374 */
2385 2375 assign_done = true;
2386 2376 /* Skip white space. */
2387 2377 while (iswspace(*string)) {
2388 2378 string++;
2389 2379 }
2390 2380 equal = string;
2391 2381 /* Find "+=" or "=". */
2392 2382 while (!iswspace(*equal) &&
2393 2383 (*equal != (int) plus_char) &&
2394 2384 (*equal != (int) equal_char)) {
2395 2385 equal++;
2396 2386 }
2397 2387 /* Internalize macro name. */
2398 2388 name = GETNAME(string, equal - string);
2399 2389 /* Skip over "+=" "=". */
2400 2390 while (!((*equal == (int) nul_char) ||
2401 2391 (*equal == (int) equal_char) ||
2402 2392 (*equal == (int) plus_char))) {
2403 2393 equal++;
2404 2394 }
2405 2395 switch (*equal) {
2406 2396 case nul_char:
2407 2397 fatal(catgets(catd, 1, 31, "= expected in rule `%s' for target `%s'"),
2408 2398 line->string_mb,
2409 2399 target->string_mb);
2410 2400 case plus_char:
2411 2401 append = true;
2412 2402 equal++;
2413 2403 break;
2414 2404 }
2415 2405 equal++;
2416 2406 /* Skip over whitespace in front of value. */
2417 2407 while (iswspace(*equal)) {
2418 2408 equal++;
2419 2409 }
2420 2410 /* Enter new macro value. */
2421 2411 enter_equal(name,
2422 2412 GETNAME(equal, wcb.get_string() + line->hash.length - equal),
2423 2413 append);
2424 2414 }
2425 2415
2426 2416 /*
2427 2417 * build_command_strings(target, line)
2428 2418 *
2429 2419 * Builds the command string to used when
2430 2420 * building a target. If the string is different from the previous one
2431 2421 * is_out_of_date is set.
2432 2422 *
2433 2423 * Parameters:
2434 2424 * target Target to build commands for
2435 2425 * line Where to stuff result
2436 2426 *
2437 2427 * Global variables used:
2438 2428 * c_at The Name "@", used to set macro value
2439 2429 * command_changed Set if command is different from old
2440 2430 * debug_level Should we trace activities?
2441 2431 * do_not_exec_rule Always echo when running -n
2442 2432 * empty_name The Name "", used for empty rule
2443 2433 * funny Semantics of characters
2444 2434 * ignore_errors Used to init field for line
2445 2435 * is_conditional Set to false befor evaling macro, checked
2446 2436 * after expanding macros
2447 2437 * keep_state Indicates that .KEEP_STATE is on
2448 2438 * make_word_mentioned Set by macro eval, inits field for cmd
2449 2439 * query The Name "?", used to set macro value
2450 2440 * query_mentioned Set by macro eval, inits field for cmd
2451 2441 * recursion_level Used for tracing
2452 2442 * silent Used to init field for line
2453 2443 */
2454 2444 static void
2455 2445 build_command_strings(Name target, register Property line)
2456 2446 {
2457 2447 String_rec command_line;
2458 2448 register Cmd_line command_template = line->body.line.command_template;
2459 2449 register Cmd_line *insert = &line->body.line.command_used;
2460 2450 register Cmd_line used = *insert;
2461 2451 wchar_t buffer[STRING_BUFFER_LENGTH];
2462 2452 wchar_t *start;
2463 2453 Name new_command_line;
2464 2454 register Boolean new_command_longer = false;
2465 2455 register Boolean ignore_all_command_dependency = true;
2466 2456 Property member;
2467 2457 static Name less_name;
2468 2458 static Name percent_name;
2469 2459 static Name star;
2470 2460 Name tmp_name;
2471 2461
2472 2462 if (less_name == NULL) {
2473 2463 MBSTOWCS(wcs_buffer, "<");
2474 2464 less_name = GETNAME(wcs_buffer, FIND_LENGTH);
2475 2465 MBSTOWCS(wcs_buffer, "%");
2476 2466 percent_name = GETNAME(wcs_buffer, FIND_LENGTH);
2477 2467 MBSTOWCS(wcs_buffer, "*");
2478 2468 star = GETNAME(wcs_buffer, FIND_LENGTH);
2479 2469 }
2480 2470
2481 2471 /* We have to check if a target depends on conditional macros */
2482 2472 /* Targets that do must be reprocessed by doname() each time around */
2483 2473 /* since the macro values used when building the target might have */
2484 2474 /* changed */
2485 2475 conditional_macro_used = false;
2486 2476 /* If we are building a lib.a(member) target $@ should be bound */
2487 2477 /* to lib.a */
2488 2478 if (target->is_member &&
2489 2479 ((member = get_prop(target->prop, member_prop)) != NULL)) {
2490 2480 target = member->body.member.library;
2491 2481 }
2492 2482 /* If we are building a "::" help target $@ should be bound to */
2493 2483 /* the real target name */
2494 2484 /* A lib.a(member) target is never :: */
2495 2485 if (target->has_target_prop) {
2496 2486 target = get_prop(target->prop, target_prop)->
2497 2487 body.target.target;
2498 2488 }
2499 2489 /* Bind the magic macros that make supplies */
2500 2490 tmp_name = target;
2501 2491 if(tmp_name != NULL) {
2502 2492 if (tmp_name->has_vpath_alias_prop) {
2503 2493 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2504 2494 body.vpath_alias.alias;
2505 2495 }
2506 2496 }
2507 2497 (void) SETVAR(c_at, tmp_name, false);
2508 2498
2509 2499 tmp_name = line->body.line.star;
2510 2500 if(tmp_name != NULL) {
2511 2501 if (tmp_name->has_vpath_alias_prop) {
2512 2502 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2513 2503 body.vpath_alias.alias;
2514 2504 }
2515 2505 }
2516 2506 (void) SETVAR(star, tmp_name, false);
2517 2507
2518 2508 tmp_name = line->body.line.less;
2519 2509 if(tmp_name != NULL) {
2520 2510 if (tmp_name->has_vpath_alias_prop) {
2521 2511 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2522 2512 body.vpath_alias.alias;
2523 2513 }
2524 2514 }
2525 2515 (void) SETVAR(less_name, tmp_name, false);
2526 2516
2527 2517 tmp_name = line->body.line.percent;
2528 2518 if(tmp_name != NULL) {
2529 2519 if (tmp_name->has_vpath_alias_prop) {
2530 2520 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)->
2531 2521 body.vpath_alias.alias;
2532 2522 }
2533 2523 }
2534 2524 (void) SETVAR(percent_name, tmp_name, false);
2535 2525
2536 2526 /* $? is seldom used and it is expensive to build */
2537 2527 /* so we store the list form and build the string on demand */
2538 2528 Chain query_list = NULL;
2539 2529 Chain *query_list_tail = &query_list;
2540 2530
2541 2531 for (Chain ch = line->body.line.query; ch != NULL; ch = ch->next) {
2542 2532 *query_list_tail = ALLOC(Chain);
2543 2533 (*query_list_tail)->name = ch->name;
2544 2534 if ((*query_list_tail)->name->has_vpath_alias_prop) {
2545 2535 (*query_list_tail)->name =
2546 2536 get_prop((*query_list_tail)->name->prop,
2547 2537 vpath_alias_prop)->body.vpath_alias.alias;
2548 2538 }
2549 2539 (*query_list_tail)->next = NULL;
2550 2540 query_list_tail = &(*query_list_tail)->next;
2551 2541 }
2552 2542 (void) setvar_daemon(query,
2553 2543 (Name) query_list,
2554 2544 false,
2555 2545 chain_daemon,
2556 2546 false,
2557 2547 debug_level);
2558 2548
2559 2549 /* build $^ */
2560 2550 Chain hat_list = NULL;
2561 2551 Chain *hat_list_tail = &hat_list;
2562 2552
2563 2553 for (Dependency dependency = line->body.line.dependencies;
2564 2554 dependency != NULL;
2565 2555 dependency = dependency->next) {
2566 2556 /* skip automatic dependencies */
2567 2557 if (!dependency->automatic) {
2568 2558 if ((dependency->name != force) &&
2569 2559 (dependency->stale == false)) {
2570 2560 *hat_list_tail = ALLOC(Chain);
2571 2561
2572 2562 if (dependency->name->is_member &&
2573 2563 (get_prop(dependency->name->prop, member_prop) != NULL)) {
2574 2564 (*hat_list_tail)->name =
2575 2565 get_prop(dependency->name->prop,
2576 2566 member_prop)->body.member.member;
2577 2567 } else {
2578 2568 (*hat_list_tail)->name = dependency->name;
2579 2569 }
2580 2570
2581 2571 if((*hat_list_tail)->name != NULL) {
2582 2572 if ((*hat_list_tail)->name->has_vpath_alias_prop) {
2583 2573 (*hat_list_tail)->name =
2584 2574 get_prop((*hat_list_tail)->name->prop,
2585 2575 vpath_alias_prop)->body.vpath_alias.alias;
2586 2576 }
2587 2577 }
2588 2578
2589 2579 (*hat_list_tail)->next = NULL;
2590 2580 hat_list_tail = &(*hat_list_tail)->next;
2591 2581 }
2592 2582 }
2593 2583 }
2594 2584 (void) setvar_daemon(hat,
2595 2585 (Name) hat_list,
2596 2586 false,
2597 2587 chain_daemon,
2598 2588 false,
2599 2589 debug_level);
2600 2590
2601 2591 /* We have two command sequences we need to handle */
2602 2592 /* The old one that we probably read from .make.state */
2603 2593 /* and the new one we are building that will replace the old one */
2604 2594 /* Even when KEEP_STATE is not on we build a new command sequence and store */
2605 2595 /* it in the line prop. This command sequence is then executed by */
2606 2596 /* run_command(). If KEEP_STATE is on it is also later written to */
2607 2597 /* .make.state. The routine replaces the old command line by line with the */
2608 2598 /* new one trying to reuse Cmd_lines */
2609 2599
2610 2600 /* If there is no old command_used we have to start creating */
2611 2601 /* Cmd_lines to keep the new cmd in */
2612 2602 if (used == NULL) {
2613 2603 new_command_longer = true;
2614 2604 *insert = used = ALLOC(Cmd_line);
2615 2605 used->next = NULL;
2616 2606 used->command_line = NULL;
2617 2607 insert = &used->next;
2618 2608 }
2619 2609 /* Run thru the template for the new command and build the expanded */
2620 2610 /* new command lines */
2621 2611 for (;
2622 2612 command_template != NULL;
2623 2613 command_template = command_template->next, insert = &used->next, used = *insert) {
2624 2614 /* If there is no old command_used Cmd_line we need to */
2625 2615 /* create one and say that cmd consistency failed */
2626 2616 if (used == NULL) {
2627 2617 new_command_longer = true;
2628 2618 *insert = used = ALLOC(Cmd_line);
2629 2619 used->next = NULL;
2630 2620 used->command_line = empty_name;
2631 2621 }
2632 2622 /* Prepare the Cmd_line for the processing */
2633 2623 /* The command line prefixes "@-=?" are stripped and that */
2634 2624 /* information is saved in the Cmd_line */
2635 2625 used->assign = false;
2636 2626 used->ignore_error = ignore_errors;
2637 2627 used->silent = silent;
2638 2628 used->always_exec = false;
2639 2629 /* Expand the macros in the command line */
2640 2630 INIT_STRING_FROM_STACK(command_line, buffer);
2641 2631 make_word_mentioned =
2642 2632 query_mentioned =
2643 2633 false;
2644 2634 expand_value(command_template->command_line, &command_line, true);
2645 2635 /* If the macro $(MAKE) is mentioned in the command */
2646 2636 /* "make -n" runs actually execute the command */
2647 2637 used->make_refd = make_word_mentioned;
2648 2638 used->ignore_command_dependency = query_mentioned;
2649 2639 /* Strip the prefixes */
2650 2640 start = command_line.buffer.start;
2651 2641 for (;
2652 2642 iswspace(*start) ||
2653 2643 (get_char_semantics_value(*start) & (int) command_prefix_sem);
2654 2644 start++) {
2655 2645 switch (*start) {
2656 2646 case question_char:
2657 2647 used->ignore_command_dependency = true;
2658 2648 break;
2659 2649 case exclam_char:
2660 2650 used->ignore_command_dependency = false;
2661 2651 break;
2662 2652 case equal_char:
2663 2653 used->assign = true;
2664 2654 break;
2665 2655 case hyphen_char:
2666 2656 used->ignore_error = true;
2667 2657 break;
2668 2658 case at_char:
2669 2659 if (!do_not_exec_rule) {
2670 2660 used->silent = true;
2671 2661 }
2672 2662 break;
2673 2663 case plus_char:
2674 2664 if(posix) {
2675 2665 used->always_exec = true;
2676 2666 }
2677 2667 break;
2678 2668 }
2679 2669 }
2680 2670 /* If all command lines of the template are prefixed with "?"*/
2681 2671 /* the VIRTUAL_ROOT is not used for cmd consistency checks */
2682 2672 if (!used->ignore_command_dependency) {
2683 2673 ignore_all_command_dependency = false;
2684 2674 }
2685 2675 /* Internalize the expanded and stripped command line */
2686 2676 new_command_line = GETNAME(start, FIND_LENGTH);
2687 2677 if ((used->command_line == NULL) &&
2688 2678 (line->body.line.sccs_command)) {
2689 2679 used->command_line = new_command_line;
2690 2680 new_command_longer = false;
2691 2681 }
2692 2682 /* Compare it with the old one for command consistency */
2693 2683 if (used->command_line != new_command_line) {
2694 2684 Name vpath_translated = vpath_translation(new_command_line);
2695 2685 if (keep_state &&
2696 2686 !used->ignore_command_dependency && (vpath_translated != used->command_line)) {
2697 2687 if (debug_level > 0) {
2698 2688 if (used->command_line != NULL
2699 2689 && *used->command_line->string_mb !=
2700 2690 '\0') {
2701 2691 (void) printf(catgets(catd, 1, 32, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from old\n\t%s\n"),
2702 2692 recursion_level,
2703 2693 "",
2704 2694 target->string_mb,
2705 2695 vpath_translated->string_mb,
2706 2696 recursion_level,
2707 2697 "",
2708 2698 used->
2709 2699 command_line->
2710 2700 string_mb);
2711 2701 } else {
2712 2702 (void) printf(catgets(catd, 1, 33, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from empty old command\n"),
2713 2703 recursion_level,
2714 2704 "",
2715 2705 target->string_mb,
2716 2706 vpath_translated->string_mb,
2717 2707 recursion_level,
2718 2708 "");
2719 2709 }
2720 2710 }
2721 2711 command_changed = true;
2722 2712 line->body.line.is_out_of_date = true;
2723 2713 }
2724 2714 used->command_line = new_command_line;
2725 2715 }
2726 2716 if (command_line.free_after_use) {
2727 2717 retmem(command_line.buffer.start);
2728 2718 }
2729 2719 }
2730 2720 /* Check if the old command is longer than the new for */
2731 2721 /* command consistency */
2732 2722 if (used != NULL) {
2733 2723 *insert = NULL;
2734 2724 if (keep_state &&
2735 2725 !ignore_all_command_dependency) {
2736 2726 if (debug_level > 0) {
2737 2727 (void) printf(catgets(catd, 1, 34, "%*sBuilding %s because new command shorter than old\n"),
2738 2728 recursion_level,
2739 2729 "",
2740 2730 target->string_mb);
2741 2731 }
2742 2732 command_changed = true;
2743 2733 line->body.line.is_out_of_date = true;
2744 2734 }
2745 2735 }
2746 2736 /* Check if the new command is longer than the old command for */
2747 2737 /* command consistency */
2748 2738 if (new_command_longer &&
2749 2739 !ignore_all_command_dependency &&
2750 2740 keep_state) {
2751 2741 if (debug_level > 0) {
2752 2742 (void) printf(catgets(catd, 1, 35, "%*sBuilding %s because new command longer than old\n"),
2753 2743 recursion_level,
2754 2744 "",
2755 2745 target->string_mb);
2756 2746 }
2757 2747 command_changed = true;
2758 2748 line->body.line.is_out_of_date = true;
2759 2749 }
2760 2750 /* Unbind the magic macros */
2761 2751 (void) SETVAR(c_at, (Name) NULL, false);
2762 2752 (void) SETVAR(star, (Name) NULL, false);
2763 2753 (void) SETVAR(less_name, (Name) NULL, false);
2764 2754 (void) SETVAR(percent_name, (Name) NULL, false);
2765 2755 (void) SETVAR(query, (Name) NULL, false);
2766 2756 if (query_list != NULL) {
2767 2757 delete_query_chain(query_list);
2768 2758 }
2769 2759 (void) SETVAR(hat, (Name) NULL, false);
2770 2760 if (hat_list != NULL) {
2771 2761 delete_query_chain(hat_list);
2772 2762 }
2773 2763
2774 2764 if (conditional_macro_used) {
2775 2765 target->conditional_macro_list = cond_macro_list;
2776 2766 cond_macro_list = NULL;
2777 2767 target->depends_on_conditional = true;
2778 2768 }
2779 2769 }
2780 2770
2781 2771 /*
2782 2772 * touch_command(line, target, result)
2783 2773 *
2784 2774 * If this is an "make -t" run we do this.
2785 2775 * We touch all targets in the target group ("foo + fie:") if any.
2786 2776 *
2787 2777 * Return value:
2788 2778 * Indicates if the command failed or not
2789 2779 *
2790 2780 * Parameters:
2791 2781 * line The command line to update
2792 2782 * target The target we are touching
2793 2783 * result Initial value for the result we return
2794 2784 *
2795 2785 * Global variables used:
2796 2786 * do_not_exec_rule Indicates that -n is on
2797 2787 * silent Do not echo commands
2798 2788 */
2799 2789 static Doname
2800 2790 touch_command(register Property line, register Name target, Doname result)
2801 2791 {
2802 2792 Name name;
2803 2793 register Chain target_group;
2804 2794 String_rec touch_string;
2805 2795 wchar_t buffer[MAXPATHLEN];
2806 2796 Name touch_cmd;
2807 2797 Cmd_line rule;
2808 2798
2809 2799 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
2810 2800 Avo_MToolJobResultMsg *job_result_msg;
2811 2801 RWCollectable *xdr_msg;
2812 2802 int child_pid = 0;
2813 2803 wchar_t string[MAXPATHLEN];
2814 2804 char mbstring[MAXPATHLEN];
2815 2805 int filed;
2816 2806 #endif
2817 2807
2818 2808 SEND_MTOOL_MSG(
2819 2809 if (!sent_rsrc_info_msg) {
2820 2810 if (userName[0] == '\0') {
2821 2811 avo_get_user(userName, NULL);
2822 2812 }
2823 2813 if (hostName[0] == '\0') {
2824 2814 strcpy(hostName, avo_hostname());
2825 2815 }
2826 2816 send_rsrc_info_msg(1, hostName, userName);
2827 2817 sent_rsrc_info_msg = 1;
2828 2818 }
2829 2819 send_job_start_msg(line);
2830 2820 job_result_msg = new Avo_MToolJobResultMsg();
2831 2821 );
2832 2822 for (name = target, target_group = NULL; name != NULL;) {
2833 2823 if (!name->is_member) {
2834 2824 /*
2835 2825 * Build a touch command that can be passed
2836 2826 * to dosys(). If KEEP_STATE is on, "make -t"
2837 2827 * will save the proper command, not the
2838 2828 * "touch" in .make.state.
2839 2829 */
2840 2830 INIT_STRING_FROM_STACK(touch_string, buffer);
2841 2831 MBSTOWCS(wcs_buffer, NOCATGETS("touch "));
2842 2832 append_string(wcs_buffer, &touch_string, FIND_LENGTH);
2843 2833 touch_cmd = name;
2844 2834 if (name->has_vpath_alias_prop) {
2845 2835 touch_cmd = get_prop(name->prop,
2846 2836 vpath_alias_prop)->
2847 2837 body.vpath_alias.alias;
2848 2838 }
2849 2839 APPEND_NAME(touch_cmd,
2850 2840 &touch_string,
2851 2841 FIND_LENGTH);
2852 2842 touch_cmd = GETNAME(touch_string.buffer.start,
2853 2843 FIND_LENGTH);
2854 2844 if (touch_string.free_after_use) {
2855 2845 retmem(touch_string.buffer.start);
2856 2846 }
2857 2847 if (!silent ||
2858 2848 do_not_exec_rule &&
2859 2849 (target_group == NULL)) {
2860 2850 (void) printf("%s\n", touch_cmd->string_mb);
2861 2851 SEND_MTOOL_MSG(
2862 2852 job_result_msg->appendOutput(AVO_STRDUP(touch_cmd->string_mb));
2863 2853 );
2864 2854 }
2865 2855 /* Run the touch command, or simulate it */
2866 2856 if (!do_not_exec_rule) {
2867 2857
2868 2858 SEND_MTOOL_MSG(
2869 2859 (void) sprintf(mbstring,
2870 2860 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"),
2871 2861 tmpdir,
2872 2862 getpid(),
2873 2863 file_number++);
2874 2864
2875 2865 int tmp_fd = mkstemp(mbstring);
2876 2866 if(tmp_fd) {
2877 2867 (void) close(tmp_fd);
2878 2868 }
2879 2869
2880 2870 stdout_file = strdup(mbstring);
2881 2871 stderr_file = NULL;
2882 2872 child_pid = pollResults(stdout_file,
2883 2873 (char *)NULL,
2884 2874 (char *)NULL);
2885 2875 );
2886 2876
2887 2877 result = dosys(touch_cmd,
2888 2878 false,
2889 2879 false,
2890 2880 false,
2891 2881 false,
2892 2882 name,
2893 2883 send_mtool_msgs);
2894 2884
2895 2885 SEND_MTOOL_MSG(
2896 2886 append_job_result_msg(job_result_msg);
2897 2887 if (child_pid > 0) {
2898 2888 kill(child_pid, SIGUSR1);
2899 2889 while (!((waitpid(child_pid, 0, 0) == -1)
2900 2890 && (errno == ECHILD)));
2901 2891 }
2902 2892 child_pid = 0;
2903 2893 (void) unlink(stdout_file);
2904 2894 retmem_mb(stdout_file);
2905 2895 stdout_file = NULL;
2906 2896 );
2907 2897
2908 2898 } else {
2909 2899 result = build_ok;
2910 2900 }
2911 2901 } else {
2912 2902 result = build_ok;
2913 2903 }
2914 2904 if (target_group == NULL) {
2915 2905 target_group = line->body.line.target_group;
2916 2906 } else {
2917 2907 target_group = target_group->next;
2918 2908 }
2919 2909 if (target_group != NULL) {
2920 2910 name = target_group->name;
2921 2911 } else {
2922 2912 name = NULL;
2923 2913 }
2924 2914 }
2925 2915 SEND_MTOOL_MSG(
2926 2916 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE);
2927 2917 xdr_msg = (RWCollectable*) job_result_msg;
2928 2918 xdr(&xdrs, xdr_msg);
2929 2919 (void) fflush(mtool_msgs_fp);
2930 2920 delete job_result_msg;
2931 2921 );
2932 2922 return result;
2933 2923 }
2934 2924
2935 2925 /*
2936 2926 * update_target(line, result)
2937 2927 *
2938 2928 * updates the status of a target after executing its commands.
2939 2929 *
2940 2930 * Parameters:
2941 2931 * line The command line block to update
2942 2932 * result Indicates that build is OK so can update
2943 2933 *
2944 2934 * Global variables used:
2945 2935 * do_not_exec_rule Indicates that -n is on
2946 2936 * touch Fake the new timestamp if we are just touching
2947 2937 */
2948 2938 void
2949 2939 update_target(Property line, Doname result)
2950 2940 {
2951 2941 Name target;
2952 2942 Chain target_group;
2953 2943 Property line2;
2954 2944 timestruc_t old_stat_time;
2955 2945 Property member;
2956 2946
2957 2947 /*
2958 2948 * [tolik] Additional fix for bug 1063790. It was fixed
2959 2949 * for serial make long ago, but DMake dumps core when
2960 2950 * target is a symlink and sccs file is newer then target.
2961 2951 * In this case, finish_children() calls update_target()
2962 2952 * with line==NULL.
2963 2953 */
2964 2954 if(line == NULL) {
2965 2955 /* XXX. Should we do anything here? */
2966 2956 return;
2967 2957 }
2968 2958
2969 2959 target = line->body.line.target;
2970 2960
2971 2961 if ((result == build_ok) && (line->body.line.command_used != NULL)) {
2972 2962 if (do_not_exec_rule ||
2973 2963 touch ||
2974 2964 (target->is_member &&
2975 2965 (line->body.line.command_template != NULL) &&
2976 2966 (line->body.line.command_template->command_line->string_mb[0] == 0) &&
2977 2967 (line->body.line.command_template->next == NULL))) {
2978 2968 /* If we are simulating execution we need to fake a */
2979 2969 /* new timestamp for the target we didnt build */
2980 2970 target->stat.time = file_max_time;
2981 2971 } else {
2982 2972 /*
2983 2973 * If we really built the target we read the new
2984 2974 * timestamp.
2985 2975 * Fix for bug #1110906: if .c file is newer than
2986 2976 * the corresponding .o file which is in an archive
2987 2977 * file, make will compile the .c file but it won't
2988 2978 * update the object in the .a file.
2989 2979 */
2990 2980 old_stat_time = target->stat.time;
2991 2981 target->stat.time = file_no_time;
2992 2982 (void) exists(target);
2993 2983 if ((target->is_member) &&
2994 2984 (target->stat.time == old_stat_time)) {
2995 2985 member = get_prop(target->prop, member_prop);
2996 2986 if (member != NULL) {
2997 2987 target->stat.time = member->body.member.library->stat.time;
2998 2988 target->stat.time.tv_sec++;
2999 2989 }
3000 2990 }
3001 2991 }
3002 2992 /* If the target is part of a group we need to propagate the */
3003 2993 /* result of the run to all members */
3004 2994 for (target_group = line->body.line.target_group;
3005 2995 target_group != NULL;
3006 2996 target_group = target_group->next) {
3007 2997 target_group->name->stat.time = target->stat.time;
3008 2998 line2 = maybe_append_prop(target_group->name,
3009 2999 line_prop);
3010 3000 line2->body.line.command_used =
3011 3001 line->body.line.command_used;
3012 3002 line2->body.line.target = target_group->name;
3013 3003 }
3014 3004 }
3015 3005 target->has_built = true;
3016 3006 }
3017 3007
3018 3008 /*
3019 3009 * sccs_get(target, command)
3020 3010 *
3021 3011 * Figures out if it possible to sccs get a file
3022 3012 * and builds the command to do it if it is.
3023 3013 *
3024 3014 * Return value:
3025 3015 * Indicates if sccs get failed or not
3026 3016 *
3027 3017 * Parameters:
3028 3018 * target Target to get
3029 3019 * command Where to deposit command to use
3030 3020 *
3031 3021 * Global variables used:
3032 3022 * debug_level Should we trace activities?
3033 3023 * recursion_level Used for tracing
3034 3024 * sccs_get_rule The rule to used for sccs getting
3035 3025 */
3036 3026 static Doname
3037 3027 sccs_get(register Name target, register Property *command)
3038 3028 {
3039 3029 register int result;
3040 3030 char link[MAXPATHLEN];
3041 3031 String_rec string;
3042 3032 wchar_t name[MAXPATHLEN];
3043 3033 register wchar_t *p;
3044 3034 timestruc_t sccs_time;
3045 3035 register Property line;
3046 3036 int sym_link_depth = 0;
3047 3037
3048 3038 /* For sccs, we need to chase symlinks. */
3049 3039 while (target->stat.is_sym_link) {
3050 3040 if (sym_link_depth++ > 90) {
3051 3041 fatal(catgets(catd, 1, 95, "Can't read symbolic link `%s': Number of symbolic links encountered during path name traversal exceeds 90."),
3052 3042 target->string_mb);
3053 3043 }
3054 3044 /* Read the value of the link. */
3055 3045 result = readlink_vroot(target->string_mb,
3056 3046 link,
3057 3047 sizeof(link),
3058 3048 NULL,
3059 3049 VROOT_DEFAULT);
3060 3050 if (result == -1) {
3061 3051 fatal(catgets(catd, 1, 36, "Can't read symbolic link `%s': %s"),
3062 3052 target->string_mb, errmsg(errno));
3063 3053 }
3064 3054 link[result] = 0;
3065 3055 /* Use the value to build the proper filename. */
3066 3056 INIT_STRING_FROM_STACK(string, name);
3067 3057
3068 3058 Wstring wcb(target);
3069 3059 if ((link[0] != slash_char) &&
3070 3060 ((p = (wchar_t *) wsrchr(wcb.get_string(), slash_char)) != NULL)) {
3071 3061 append_string(wcb.get_string(), &string, p - wcb.get_string() + 1);
3072 3062 }
3073 3063 append_string(link, &string, result);
3074 3064 /* Replace the old name with the translated name. */
3075 3065 target = normalize_name(string.buffer.start, string.text.p - string.buffer.start);
3076 3066 (void) exists(target);
3077 3067 if (string.free_after_use) {
3078 3068 retmem(string.buffer.start);
3079 3069 }
3080 3070 }
3081 3071
3082 3072 /*
3083 3073 * read_dir() also reads the ?/SCCS dir and saves information
3084 3074 * about which files have SCSC/s. files.
3085 3075 */
3086 3076 if (target->stat.has_sccs == DONT_KNOW_SCCS) {
3087 3077 read_directory_of_file(target);
3088 3078 }
3089 3079 switch (target->stat.has_sccs) {
3090 3080 case DONT_KNOW_SCCS:
3091 3081 /* We dont know by now there is no SCCS/s.* */
3092 3082 target->stat.has_sccs = NO_SCCS;
3093 3083 case NO_SCCS:
3094 3084 /*
3095 3085 * If there is no SCCS/s.* but the plain file exists,
3096 3086 * we say things are OK.
3097 3087 */
3098 3088 if (target->stat.time > file_doesnt_exist) {
3099 3089 return build_ok;
3100 3090 }
3101 3091 /* If we cant find the plain file, we give up. */
3102 3092 return build_dont_know;
3103 3093 case HAS_SCCS:
3104 3094 /*
3105 3095 * Pay dirt. We now need to figure out if the plain file
3106 3096 * is out of date relative to the SCCS/s.* file.
3107 3097 */
3108 3098 sccs_time = exists(get_prop(target->prop,
3109 3099 sccs_prop)->body.sccs.file);
3110 3100 break;
3111 3101 }
3112 3102
3113 3103 if ((!target->has_complained &&
3114 3104 (sccs_time != file_doesnt_exist) &&
3115 3105 (sccs_get_rule != NULL))) {
3116 3106 /* only checking */
3117 3107 if (command == NULL) {
3118 3108 return build_ok;
3119 3109 }
3120 3110 /*
3121 3111 * We provide a command line for the target. The line is a
3122 3112 * "sccs get" command from default.mk.
3123 3113 */
3124 3114 line = maybe_append_prop(target, line_prop);
3125 3115 *command = line;
3126 3116 if (sccs_time > target->stat.time) {
3127 3117 /*
3128 3118 * And only if the plain file is out of date do we
3129 3119 * request execution of the command.
3130 3120 */
3131 3121 line->body.line.is_out_of_date = true;
3132 3122 if (debug_level > 0) {
3133 3123 (void) printf(catgets(catd, 1, 37, "%*sSccs getting %s because s. file is younger than source file\n"),
3134 3124 recursion_level,
3135 3125 "",
3136 3126 target->string_mb);
3137 3127 }
3138 3128 }
3139 3129 line->body.line.sccs_command = true;
3140 3130 line->body.line.command_template = sccs_get_rule;
3141 3131 if(!svr4 && (!allrules_read || posix)) {
3142 3132 if((target->prop) &&
3143 3133 (target->prop->body.sccs.file) &&
3144 3134 (target->prop->body.sccs.file->string_mb)) {
3145 3135 if((strlen(target->prop->body.sccs.file->string_mb) ==
3146 3136 strlen(target->string_mb) + 2) &&
3147 3137 (target->prop->body.sccs.file->string_mb[0] == 's') &&
3148 3138 (target->prop->body.sccs.file->string_mb[1] == '.')) {
3149 3139
3150 3140 line->body.line.command_template = get_posix_rule;
3151 3141 }
3152 3142 }
3153 3143 }
3154 3144 line->body.line.target = target;
3155 3145 /*
3156 3146 * Also make sure the rule is build with $* and $<
3157 3147 * bound properly.
3158 3148 */
3159 3149 line->body.line.star = NULL;
3160 3150 line->body.line.less = NULL;
3161 3151 line->body.line.percent = NULL;
3162 3152 return build_ok;
3163 3153 }
3164 3154 return build_dont_know;
3165 3155 }
3166 3156
3167 3157 /*
3168 3158 * read_directory_of_file(file)
3169 3159 *
3170 3160 * Reads the directory the specified file lives in.
3171 3161 *
3172 3162 * Parameters:
3173 3163 * file The file we need to read dir for
3174 3164 *
3175 3165 * Global variables used:
3176 3166 * dot The Name ".", used as the default dir
3177 3167 */
3178 3168 void
3179 3169 read_directory_of_file(register Name file)
3180 3170 {
3181 3171
3182 3172 Wstring file_string(file);
3183 3173 wchar_t * wcb = file_string.get_string();
3184 3174 wchar_t usr_include_buf[MAXPATHLEN];
3185 3175 wchar_t usr_include_sys_buf[MAXPATHLEN];
3186 3176
3187 3177 register Name directory = dot;
3188 3178 register wchar_t *p = (wchar_t *) wsrchr(wcb,
3189 3179 (int) slash_char);
3190 3180 register int length = p - wcb;
3191 3181 static Name usr_include;
3192 3182 static Name usr_include_sys;
3193 3183
3194 3184 if (usr_include == NULL) {
3195 3185 MBSTOWCS(usr_include_buf, NOCATGETS("/usr/include"));
3196 3186 usr_include = GETNAME(usr_include_buf, FIND_LENGTH);
3197 3187 MBSTOWCS(usr_include_sys_buf, NOCATGETS("/usr/include/sys"));
3198 3188 usr_include_sys = GETNAME(usr_include_sys_buf, FIND_LENGTH);
3199 3189 }
3200 3190
3201 3191 /*
3202 3192 * If the filename contains a "/" we have to extract the path
3203 3193 * Else the path defaults to ".".
3204 3194 */
3205 3195 if (p != NULL) {
3206 3196 /*
3207 3197 * Check some popular directories first to possibly
3208 3198 * save time. Compare string length first to gain speed.
3209 3199 */
3210 3200 if ((usr_include->hash.length == length) &&
3211 3201 IS_WEQUALN(usr_include_buf,
3212 3202 wcb,
3213 3203 length)) {
3214 3204 directory = usr_include;
3215 3205 } else if ((usr_include_sys->hash.length == length) &&
3216 3206 IS_WEQUALN(usr_include_sys_buf,
3217 3207 wcb,
3218 3208 length)) {
3219 3209 directory = usr_include_sys;
3220 3210 } else {
3221 3211 directory = GETNAME(wcb, length);
3222 3212 }
3223 3213 }
3224 3214 (void) read_dir(directory,
3225 3215 (wchar_t *) NULL,
3226 3216 (Property) NULL,
3227 3217 (wchar_t *) NULL);
3228 3218 }
3229 3219
3230 3220 /*
3231 3221 * add_pattern_conditionals(target)
3232 3222 *
3233 3223 * Scan the list of conditionals defined for pattern targets and add any
3234 3224 * that match this target to its list of conditionals.
3235 3225 *
3236 3226 * Parameters:
3237 3227 * target The target we should add conditionals for
3238 3228 *
3239 3229 * Global variables used:
3240 3230 * conditionals The list of pattern conditionals
3241 3231 */
3242 3232 static void
3243 3233 add_pattern_conditionals(register Name target)
3244 3234 {
3245 3235 register Property conditional;
3246 3236 Property new_prop;
3247 3237 Property *previous;
3248 3238 Name_rec dummy;
3249 3239 wchar_t *pattern;
3250 3240 wchar_t *percent;
3251 3241 int length;
3252 3242
3253 3243 Wstring wcb(target);
3254 3244 Wstring wcb1;
3255 3245
3256 3246 for (conditional = get_prop(conditionals->prop, conditional_prop);
3257 3247 conditional != NULL;
3258 3248 conditional = get_prop(conditional->next, conditional_prop)) {
3259 3249 wcb1.init(conditional->body.conditional.target);
3260 3250 pattern = wcb1.get_string();
3261 3251 if (pattern[1] != 0) {
3262 3252 percent = (wchar_t *) wschr(pattern, (int) percent_char);
3263 3253 if (!wcb.equaln(pattern, percent-pattern) ||
3264 3254 !IS_WEQUAL(wcb.get_string(wcb.length()-wslen(percent+1)), percent+1)) {
3265 3255 continue;
3266 3256 }
3267 3257 }
3268 3258 for (previous = &target->prop;
3269 3259 *previous != NULL;
3270 3260 previous = &(*previous)->next) {
3271 3261 if (((*previous)->type == conditional_prop) &&
3272 3262 ((*previous)->body.conditional.sequence >
3273 3263 conditional->body.conditional.sequence)) {
3274 3264 break;
3275 3265 }
3276 3266 }
3277 3267 if (*previous == NULL) {
3278 3268 new_prop = append_prop(target, conditional_prop);
3279 3269 } else {
3280 3270 dummy.prop = NULL;
3281 3271 new_prop = append_prop(&dummy, conditional_prop);
3282 3272 new_prop->next = *previous;
3283 3273 *previous = new_prop;
3284 3274 }
3285 3275 target->conditional_cnt++;
3286 3276 new_prop->body.conditional = conditional->body.conditional;
3287 3277 }
3288 3278 }
3289 3279
3290 3280 /*
3291 3281 * set_locals(target, old_locals)
3292 3282 *
3293 3283 * Sets any conditional macros for the target.
3294 3284 * Each target carries a possibly empty set of conditional properties.
3295 3285 *
3296 3286 * Parameters:
3297 3287 * target The target to set conditional macros for
3298 3288 * old_locals Space to store old values in
3299 3289 *
3300 3290 * Global variables used:
3301 3291 * debug_level Should we trace activity?
3302 3292 * is_conditional We need to preserve this value
3303 3293 * recursion_level Used for tracing
3304 3294 */
3305 3295 void
3306 3296 set_locals(register Name target, register Property old_locals)
3307 3297 {
3308 3298 register Property conditional;
3309 3299 register int i;
3310 3300 register Boolean saved_conditional_macro_used;
3311 3301 Chain cond_name;
3312 3302 Chain cond_chain;
3313 3303
3314 3304 #ifdef DISTRIBUTED
3315 3305 if (target->dont_activate_cond_values) {
3316 3306 return;
3317 3307 }
3318 3308 #endif
3319 3309
3320 3310 saved_conditional_macro_used = conditional_macro_used;
3321 3311
3322 3312 /* Scan the list of conditional properties and apply each one */
3323 3313 for (conditional = get_prop(target->prop, conditional_prop), i = 0;
3324 3314 conditional != NULL;
3325 3315 conditional = get_prop(conditional->next, conditional_prop),
3326 3316 i++) {
3327 3317 /* Save the old value */
3328 3318 old_locals[i].body.macro =
3329 3319 maybe_append_prop(conditional->body.conditional.name,
3330 3320 macro_prop)->body.macro;
3331 3321 if (debug_level > 1) {
3332 3322 (void) printf(catgets(catd, 1, 38, "%*sActivating conditional value: "),
3333 3323 recursion_level,
3334 3324 "");
3335 3325 }
3336 3326 /* Set the conditional value. Macros are expanded when the */
3337 3327 /* macro is refd as usual */
3338 3328 if ((conditional->body.conditional.name != virtual_root) ||
3339 3329 (conditional->body.conditional.value != virtual_root)) {
3340 3330 (void) SETVAR(conditional->body.conditional.name,
3341 3331 conditional->body.conditional.value,
3342 3332 (Boolean) conditional->body.conditional.append);
3343 3333 }
3344 3334 cond_name = ALLOC(Chain);
3345 3335 cond_name->name = conditional->body.conditional.name;
3346 3336 }
3347 3337 /* Put this target on the front of the chain of conditional targets */
3348 3338 cond_chain = ALLOC(Chain);
3349 3339 cond_chain->name = target;
3350 3340 cond_chain->next = conditional_targets;
3351 3341 conditional_targets = cond_chain;
3352 3342 conditional_macro_used = saved_conditional_macro_used;
3353 3343 }
3354 3344
3355 3345 /*
3356 3346 * reset_locals(target, old_locals, conditional, index)
3357 3347 *
3358 3348 * Removes any conditional macros for the target.
3359 3349 *
3360 3350 * Parameters:
3361 3351 * target The target we are retoring values for
3362 3352 * old_locals The values to restore
3363 3353 * conditional The first conditional block for the target
3364 3354 * index into the old_locals vector
3365 3355 * Global variables used:
3366 3356 * debug_level Should we trace activities?
3367 3357 * recursion_level Used for tracing
3368 3358 */
3369 3359 void
3370 3360 reset_locals(register Name target, register Property old_locals, register Property conditional, register int index)
3371 3361 {
3372 3362 register Property this_conditional;
3373 3363 Chain cond_chain;
3374 3364
3375 3365 #ifdef DISTRIBUTED
3376 3366 if (target->dont_activate_cond_values) {
3377 3367 return;
3378 3368 }
3379 3369 #endif
3380 3370
3381 3371 /* Scan the list of conditional properties and restore the old value */
3382 3372 /* to each one Reverse the order relative to when we assigned macros */
3383 3373 this_conditional = get_prop(conditional->next, conditional_prop);
3384 3374 if (this_conditional != NULL) {
3385 3375 reset_locals(target, old_locals, this_conditional, index+1);
3386 3376 } else {
3387 3377 /* Remove conditional target from chain */
3388 3378 if (conditional_targets == NULL ||
3389 3379 conditional_targets->name != target) {
3390 3380 warning(catgets(catd, 1, 39, "Internal error: reset target not at head of condtional_targets chain"));
3391 3381 } else {
3392 3382 cond_chain = conditional_targets->next;
3393 3383 retmem_mb((caddr_t) conditional_targets);
3394 3384 conditional_targets = cond_chain;
3395 3385 }
3396 3386 }
3397 3387 get_prop(conditional->body.conditional.name->prop,
3398 3388 macro_prop)->body.macro = old_locals[index].body.macro;
3399 3389 if (conditional->body.conditional.name == virtual_root) {
3400 3390 (void) SETVAR(virtual_root, getvar(virtual_root), false);
3401 3391 }
3402 3392 if (debug_level > 1) {
3403 3393 if (old_locals[index].body.macro.value != NULL) {
3404 3394 (void) printf(catgets(catd, 1, 40, "%*sdeactivating conditional value: %s= %s\n"),
3405 3395 recursion_level,
3406 3396 "",
3407 3397 conditional->body.conditional.name->
3408 3398 string_mb,
3409 3399 old_locals[index].body.macro.value->
3410 3400 string_mb);
3411 3401 } else {
3412 3402 (void) printf(catgets(catd, 1, 41, "%*sdeactivating conditional value: %s =\n"),
3413 3403 recursion_level,
3414 3404 "",
3415 3405 conditional->body.conditional.name->
3416 3406 string_mb);
3417 3407 }
3418 3408 }
3419 3409 }
3420 3410
3421 3411 /*
3422 3412 * check_auto_dependencies(target, auto_count, automatics)
3423 3413 *
3424 3414 * Returns true if the target now has a dependency
3425 3415 * it didn't previously have (saved on automatics).
3426 3416 *
3427 3417 * Return value:
3428 3418 * true if new dependency found
3429 3419 *
3430 3420 * Parameters:
3431 3421 * target Target we check
3432 3422 * auto_count Number of old automatic vars
3433 3423 * automatics Saved old automatics
3434 3424 *
3435 3425 * Global variables used:
3436 3426 * keep_state Indicates that .KEEP_STATE is on
3437 3427 */
3438 3428 Boolean
3439 3429 check_auto_dependencies(Name target, int auto_count, Name *automatics)
3440 3430 {
3441 3431 Name *p;
3442 3432 int n;
3443 3433 Property line;
3444 3434 Dependency dependency;
3445 3435
3446 3436 if (keep_state) {
3447 3437 if ((line = get_prop(target->prop, line_prop)) == NULL) {
3448 3438 return false;
3449 3439 }
3450 3440 /* Go thru new list of automatic depes */
3451 3441 for (dependency = line->body.line.dependencies;
3452 3442 dependency != NULL;
3453 3443 dependency = dependency->next) {
3454 3444 /* And make sure that each one existed before we */
3455 3445 /* built the target */
3456 3446 if (dependency->automatic && !dependency->stale) {
3457 3447 for (n = auto_count, p = automatics;
3458 3448 n > 0;
3459 3449 n--) {
3460 3450 if (*p++ == dependency->name) {
3461 3451 /* If we can find it on the */
3462 3452 /* saved list of autos we */
3463 3453 /* are OK */
3464 3454 goto not_new;
3465 3455 }
3466 3456 }
3467 3457 /* But if we scan over the old list */
3468 3458 /* of auto. without finding it it is */
3469 3459 /* new and we must check it */
3470 3460 return true;
3471 3461 }
3472 3462 not_new:;
3473 3463 }
3474 3464 return false;
3475 3465 } else {
3476 3466 return false;
3477 3467 }
3478 3468 }
3479 3469
3480 3470 #if defined(DISTRIBUTED) || defined(MAKETOOL) /* tolik */
3481 3471 void
3482 3472 create_xdrs_ptr(void)
3483 3473 {
3484 3474 static int xdrs_init = 0;
3485 3475
3486 3476 if (!xdrs_init) {
3487 3477 xdrs_init = 1;
3488 3478 mtool_msgs_fp = fdopen(mtool_msgs_fd, "a");
3489 3479 xdrstdio_create(&xdrs,
3490 3480 mtool_msgs_fp,
3491 3481 XDR_ENCODE);
3492 3482 }
3493 3483 }
3494 3484
3495 3485 XDR *
3496 3486 get_xdrs_ptr(void)
3497 3487 {
3498 3488 return &xdrs;
3499 3489 }
3500 3490
3501 3491 FILE *
3502 3492 get_mtool_msgs_fp(void)
3503 3493 {
3504 3494 return mtool_msgs_fp;
3505 3495 }
3506 3496
3507 3497 int
3508 3498 get_job_msg_id(void)
3509 3499 {
3510 3500 return job_msg_id;
3511 3501 }
3512 3502
3513 3503 // Continuously poll and show the results of remotely executing a job,
3514 3504 // i.e., output the stdout and stderr files.
3515 3505
3516 3506 static int
3517 3507 pollResults(char *outFn, char *errFn, char *hostNm)
3518 3508 {
3519 3509 int child;
3520 3510
3521 3511 child = fork();
3522 3512 switch (child) {
3523 3513 case -1:
3524 3514 break;
3525 3515 case 0:
3526 3516 enable_interrupt((void (*) (int))SIG_DFL);
3527 3517 (void) sigset(SIGUSR1, Avo_PollResultsAction_Sigusr1Handler);
3528 3518 pollResultsAction(outFn, errFn);
3529 3519
3530 3520 exit(0);
3531 3521 break;
3532 3522 default:
3533 3523 break;
3534 3524 }
3535 3525 return child;
3536 3526 }
3537 3527
3538 3528 // This is the PollResultsAction SIGUSR1 handler.
3539 3529
3540 3530 static bool_t pollResultsActionTimeToFinish = FALSE;
3541 3531
3542 3532 extern "C" void
3543 3533 Avo_PollResultsAction_Sigusr1Handler(int foo)
3544 3534 {
3545 3535 pollResultsActionTimeToFinish = TRUE;
3546 3536 }
3547 3537
3548 3538 static void
3549 3539 pollResultsAction(char *outFn, char *errFn)
3550 3540 {
3551 3541 int fd;
3552 3542 time_t file_time = 0;
3553 3543 long file_time_nsec = 0;
3554 3544 struct stat statbuf;
3555 3545 int stat_rc;
3556 3546
3557 3547 // Keep stat'ing until file exists.
3558 3548 while (((stat_rc = stat(outFn, &statbuf)) != 0) &&
3559 3549 (errno == ENOENT) &&
3560 3550 !pollResultsActionTimeToFinish) {
3561 3551 us_sleep(STAT_RETRY_SLEEP_TIME);
3562 3552 }
3563 3553 // The previous stat() could be failed due to EINTR
3564 3554 // So one more try is needed
3565 3555 if (stat_rc != 0 && stat(outFn, &statbuf) != 0) {
3566 3556 // stat() failed
3567 3557 warning(NOCATGETS("Internal error: stat(\"%s\", ...) failed: %s\n"),
3568 3558 outFn, strerror(errno));
3569 3559 exit(1);
3570 3560 }
3571 3561
3572 3562 if ((fd = open(outFn, O_RDONLY)) < 0
3573 3563 && (errno != EINTR || (fd = open(outFn, O_RDONLY)) < 0)) {
3574 3564 // open() failed
3575 3565 warning(NOCATGETS("Internal error: open(\"%s\", O_RDONLY) failed: %s\n"),
3576 3566 outFn, strerror(errno));
3577 3567 exit(1);
3578 3568 }
3579 3569
3580 3570 while (!pollResultsActionTimeToFinish && stat(outFn, &statbuf) == 0) {
3581 3571 if ((statbuf.st_mtim.tv_sec > file_time) ||
3582 3572 ((statbuf.st_mtim.tv_sec == file_time) &&
3583 3573 (statbuf.st_mtim.tv_nsec > file_time_nsec))
3584 3574 ) {
3585 3575 file_time = statbuf.st_mtim.tv_sec;
3586 3576 file_time_nsec = statbuf.st_mtim.tv_nsec;
3587 3577 rxmGetNextResultsBlock(fd);
3588 3578 }
3589 3579 us_sleep(STAT_RETRY_SLEEP_TIME);
3590 3580 }
3591 3581 // Check for the rest of output
3592 3582 rxmGetNextResultsBlock(fd);
3593 3583
3594 3584 (void) close(fd);
3595 3585 }
3596 3586
3597 3587 static void
3598 3588 rxmGetNextResultsBlock(int fd)
3599 3589 {
3600 3590 size_t to_read = 8 * 1024;
3601 3591 ssize_t bytes_read;
3602 3592 ssize_t bytes_written;
3603 3593 char results_buf[8 * 1024];
3604 3594 sigset_t newset;
3605 3595 sigset_t oldset;
3606 3596
3607 3597 // Read some more from the output/results file.
3608 3598 // Hopefully the kernel managed to prefetch the stuff.
3609 3599 bytes_read = read(fd, results_buf, to_read);
3610 3600 while (bytes_read > 0) {
3611 3601 AVO_BLOCK_INTERUPTS;
3612 3602 bytes_written = write(1, results_buf, bytes_read);
3613 3603 AVO_UNBLOCK_INTERUPTS;
3614 3604 if (bytes_written != bytes_read) {
3615 3605 // write() failed
3616 3606 warning(NOCATGETS("Internal error: write(1, ...) failed: %s\n"),
3617 3607 strerror(errno));
3618 3608 exit(1);
3619 3609 }
3620 3610 bytes_read = read(fd, results_buf, to_read);
3621 3611 }
3622 3612 }
3623 3613
3624 3614 // Generic, interruptable microsecond resolution sleep member function.
3625 3615
3626 3616 static int
3627 3617 us_sleep(unsigned int nusecs)
3628 3618 {
3629 3619 struct pollfd dummy;
3630 3620 int timeout;
3631 3621
3632 3622 if ((timeout = nusecs/1000) <= 0) {
3633 3623 timeout = 1;
3634 3624 }
3635 3625 return poll(&dummy, 0, timeout);
3636 3626 }
3637 3627 #endif /* TEAMWARE_MAKE_CMN */
3638 3628
3639 3629 // Recursively delete each of the Chain struct on the chain.
3640 3630
3641 3631 static void
3642 3632 delete_query_chain(Chain ch)
3643 3633 {
3644 3634 if (ch == NULL) {
3645 3635 return;
3646 3636 } else {
3647 3637 delete_query_chain(ch->next);
3648 3638 retmem_mb((char *) ch);
3649 3639 }
3650 3640 }
3651 3641
3652 3642 Doname
3653 3643 target_can_be_built(register Name target) {
3654 3644 Doname result = build_dont_know;
3655 3645 Name true_target = target;
3656 3646 Property line;
3657 3647
3658 3648 if (target == wait_name) {
3659 3649 return(build_ok);
3660 3650 }
3661 3651 /*
3662 3652 * If the target is a constructed one for a "::" target,
3663 3653 * we need to consider that.
3664 3654 */
3665 3655 if (target->has_target_prop) {
3666 3656 true_target = get_prop(target->prop,
3667 3657 target_prop)->body.target.target;
3668 3658 }
3669 3659
3670 3660 (void) exists(true_target);
3671 3661
3672 3662 if (true_target->state == build_running) {
3673 3663 return(build_running);
3674 3664 }
3675 3665 if (true_target->stat.time != file_doesnt_exist) {
3676 3666 result = build_ok;
3677 3667 }
3678 3668
3679 3669 /* get line property for the target */
3680 3670 line = get_prop(true_target->prop, line_prop);
3681 3671
3682 3672 /* first check for explicit rule */
3683 3673 if (line != NULL && line->body.line.command_template != NULL) {
3684 3674 result = build_ok;
3685 3675 }
3686 3676 /* try to find pattern rule */
3687 3677 if (result == build_dont_know) {
3688 3678 result = find_percent_rule(target, NULL, false);
3689 3679 }
3690 3680
3691 3681 /* try to find double suffix rule */
3692 3682 if (result == build_dont_know) {
3693 3683 if (target->is_member) {
3694 3684 Property member = get_prop(target->prop, member_prop);
3695 3685 if (member != NULL && member->body.member.member != NULL) {
3696 3686 result = find_ar_suffix_rule(target, member->body.member.member, NULL, false);
3697 3687 } else {
3698 3688 result = find_double_suffix_rule(target, NULL, false);
3699 3689 }
3700 3690 } else {
3701 3691 result = find_double_suffix_rule(target, NULL, false);
3702 3692 }
3703 3693 }
3704 3694
3705 3695 /* try to find suffix rule */
3706 3696 if ((result == build_dont_know) && second_pass) {
3707 3697 result = find_suffix_rule(target, target, empty_name, NULL, false);
3708 3698 }
3709 3699
3710 3700 /* check for sccs */
3711 3701 if (result == build_dont_know) {
3712 3702 result = sccs_get(target, NULL);
3713 3703 }
3714 3704
3715 3705 /* try to find dyn target */
3716 3706 if (result == build_dont_know) {
3717 3707 Name dtarg = find_dyntarget(target);
3718 3708 if (dtarg != NULL) {
3719 3709 result = target_can_be_built(dtarg);
3720 3710 }
3721 3711 }
3722 3712
3723 3713 /* check whether target was mentioned in makefile */
3724 3714 if (result == build_dont_know) {
3725 3715 if (target->colons != no_colon) {
3726 3716 result = build_ok;
3727 3717 }
3728 3718 }
3729 3719
3730 3720 /* result */
3731 3721 return result;
3732 3722 }
↓ open down ↓ |
3168 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX