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