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