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