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