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