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