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