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