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