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