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