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