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