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