18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * implicit.c
28 *
29 * Handle suffix and percent rules
30 */
31
32 /*
33 * Included files
34 */
35 #include <mk/defs.h>
36 #include <mksh/macro.h> /* expand_value() */
37 #include <mksh/misc.h> /* retmem() */
38
39 /*
40 * Defined macros
41 */
42
43 /*
44 * typedefs & structs
45 */
46
47 /*
48 * Static variables
49 */
50 static wchar_t WIDE_NULL[1] = {(wchar_t) nul_char};
51
52 /*
53 * File table of contents
54 */
55 extern Doname find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking);
56 extern Doname find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking);
57 extern Doname find_double_suffix_rule(register Name target, Property *command, Boolean rechecking);
122 Boolean posix_tilde_attempt = true;
123 int src_len = MAXPATHLEN + strlen(target_body->string_mb);
124
125 /*
126 * To avoid infinite recursion
127 */
128 if(we_are_in_tilde) {
129 we_are_in_tilde = false;
130 return(build_dont_know);
131 }
132
133 /*
134 * If the target is a constructed one for a "::" target,
135 * we need to consider that.
136 */
137 if (target->has_target_prop) {
138 true_target = get_prop(target->prop,
139 target_prop)->body.target.target;
140 }
141 if (debug_level > 1) {
142 (void) printf(NOCATGETS("%*sfind_suffix_rule(%s,%s,%s)\n"),
143 recursion_level,
144 "",
145 true_target->string_mb,
146 target_body->string_mb,
147 target_suffix->string_mb);
148 }
149 if (command != NULL) {
150 if ((true_target->suffix_scan_done == true) && (*command == NULL)) {
151 return build_ok;
152 }
153 }
154 true_target->suffix_scan_done = true;
155 /*
156 * Enter all names from the directory where the target lives as
157 * files that makes sense.
158 * This will make finding the synthesized source possible.
159 */
160 read_directory_of_file(target_body);
161 /* Cache the suffixes for this target suffix if not done. */
162 if (!target_suffix->has_read_suffixes) {
172 put_suffix = sourcename + target_body->hash.length;
173 /* Scan the suffix list for the target if one exists. */
174 if (target_suffix->has_suffixes) {
175 posix_attempts:
176 for (source_suffix = get_prop(target_suffix->prop,
177 suffix_prop);
178 source_suffix != NULL;
179 source_suffix = get_prop(source_suffix->next,
180 suffix_prop)) {
181 /* Build the synthesized source name. */
182 (void) mbstowcs(put_suffix,
183 source_suffix->body.
184 suffix.suffix->string_mb,
185 (int) source_suffix->body.
186 suffix.suffix->hash.length);
187 put_suffix[source_suffix->body.
188 suffix.suffix->hash.length] =
189 (int) nul_char;
190 if (debug_level > 1) {
191 WCSTOMBS(mbs_buffer, sourcename);
192 (void) printf(catgets(catd, 1, 218, "%*sTrying %s\n"),
193 recursion_level,
194 "",
195 mbs_buffer);
196 }
197 source = getname_fn(sourcename, FIND_LENGTH, false, &name_found);
198 /*
199 * If the source file is not registered as
200 * a file, this source suffix did not match.
201 */
202 if(vpath_defined && !posix && !svr4) {
203 (void) exists(source);
204 }
205 if (!source->stat.is_file) {
206 if(!(posix|svr4))
207 {
208 if(!name_found) {
209 free_name(source);
210 }
211 continue;
212 }
222
223 if(source->string_mb[source->hash.length - 1] == '~' &&
224 ( svr4 || posix_tilde_attempt ) )
225 {
226 char *p, *np;
227 char *tmpbuf;
228
229 tmpbuf = getmem(source->hash.length + 8);
230 /* + 8 to add "s." or "SCCS/s." */
231 memset(tmpbuf,0,source->hash.length + 8);
232 source->string_mb[source->hash.length - 1] = '\0';
233 if(p = (char *) memchr((char *)source->string_mb,'/',source->hash.length))
234 {
235 while(1) {
236 if(np = (char *) memchr((char *)p+1,'/',source->hash.length - (p - source->string_mb))) {
237 p = np;
238 } else {break;}
239 }
240 /* copy everything including '/' */
241 strncpy(tmpbuf, source->string_mb, p - source->string_mb + 1);
242 strcat(tmpbuf, NOCATGETS("s."));
243 strcat(tmpbuf, p+1);
244 retmem((wchar_t *) source->string_mb);
245 source->string_mb = tmpbuf;
246
247 } else {
248 strcpy(tmpbuf, NOCATGETS("s."));
249 strcat(tmpbuf, source->string_mb);
250 retmem((wchar_t *) source->string_mb);
251 source->string_mb = tmpbuf;
252
253 }
254 source->hash.length = strlen(source->string_mb);
255 if(exists(source) == file_doesnt_exist)
256 continue;
257 tilde_rule = true;
258 we_are_in_tilde = true;
259 } else {
260 if(!name_found) {
261 free_name(source);
262 }
263 continue;
264 }
265 } else {
266 if(posix && posix_tilde_attempt) {
267 if(exists(source) == file_doesnt_exist) {
268 if(!name_found) {
332 enter_dependency(line, source, false);
333 line->body.line.target = true_target;
334 return build_running;
335 case build_ok:
336 if(!name_found) {
337 store_name(source);
338 }
339 break;
340 case build_failed:
341 if(!name_found) {
342 store_name(source);
343 }
344 if (sourcename != static_string_buf_3M) {
345 retmem(sourcename);
346 }
347 return build_failed;
348 }
349
350 if (debug_level > 1) {
351 WCSTOMBS(mbs_buffer, sourcename);
352 (void) printf(catgets(catd, 1, 219, "%*sFound %s\n"),
353 recursion_level,
354 "",
355 mbs_buffer);
356 }
357
358 if (source->depends_on_conditional) {
359 target->depends_on_conditional = true;
360 }
361 /*
362 * Since it is possible that the same target is built several times during
363 * the make run, we have to patch the target with all information we found
364 * here. Thus, the target will have an explicit rule the next time around.
365 */
366 line = maybe_append_prop(target, line_prop);
367 if (*command == NULL) {
368 *command = line;
369 }
370 if ((source->stat.time > (*command)->body.line.dependency_time) &&
371 (debug_level > 1)) {
372 (void) printf(catgets(catd, 1, 220, "%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
373 recursion_level,
374 "",
375 source->string_mb,
376 time_to_string(source->
377 stat.time),
378 true_target->string_mb,
379 time_to_string((*command)->
380 body.line.
381 dependency_time));
382 }
383 /*
384 * Determine if this new dependency made the
385 * target out of date.
386 */
387 (*command)->body.line.dependency_time =
388 MAX((*command)->body.line.dependency_time,
389 source->stat.time);
390 Boolean out_of_date;
391 if (target->is_member) {
392 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time,
393 (*command)->body.line.dependency_time);
394 } else {
395 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time,
396 (*command)->body.line.dependency_time);
397 }
398 if (build_unconditional || out_of_date) {
399 if(!rechecking) {
400 line->body.line.is_out_of_date = true;
401 }
402 if (debug_level > 0) {
403 (void) printf(catgets(catd, 1, 221, "%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"),
404 recursion_level,
405 "",
406 true_target->string_mb,
407 source_suffix->body.suffix.suffix->string_mb,
408 target_suffix->string_mb,
409 source->string_mb);
410 }
411 }
412 /*
413 * Add the implicit rule as the target's explicit
414 * rule if none actually given, and register
415 * dependency.
416 * The time checking above really should be
417 * conditional on actual use of implicit rule
418 * as well.
419 */
420 line->body.line.sccs_command = false;
421 if (line->body.line.command_template == NULL) {
422 line->body.line.command_template =
423 source_suffix->body.suffix.command_template;
424 }
425 enter_dependency(line, source, false);
426 line->body.line.target = true_target;
427 /*
428 * Also make sure the rule is built with
429 * $* and $< bound properly.
430 */
431 line->body.line.star = target_body;
432 if(svr4|posix) {
433 char * p;
434 char tstr[256];
435 extern Boolean dollarless_flag;
436 extern Name dollarless_value;
437
438 if(tilde_rule) {
439 MBSTOWCS(wcs_buffer, NOCATGETS(source->string_mb));
440 dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH);
441 }
442 else {
443 dollarless_flag = false;
444 }
445 }
446 line->body.line.less = source;
447 line->body.line.percent = NULL;
448 add_target_to_chain(source, &(line->body.line.query));
449 if (sourcename != static_string_buf_3M) {
450 retmem(sourcename);
451 }
452 return build_ok;
453 }
454 if(posix && posix_tilde_attempt) {
455 posix_tilde_attempt = false;
456 goto posix_attempts;
457 }
458 if ((command != NULL) &&
459 ((*command) != NULL) &&
489 * Global variables used:
490 * debug_level Indicates how much tracing to do
491 * dot_a The Name ".a", compared against
492 * recursion_level Used for tracing
493 * suffixes List of suffixes used for scan (from .SUFFIXES)
494 */
495 Doname
496 find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking)
497 {
498 wchar_t *target_end;
499 register Dependency suffix;
500 register int suffix_length;
501 Property line;
502 Name body;
503 static Name dot_a;
504
505 Wstring targ_string(true_target);
506 Wstring suf_string;
507
508 if (dot_a == NULL) {
509 MBSTOWCS(wcs_buffer, NOCATGETS(".a"));
510 dot_a = GETNAME(wcs_buffer, FIND_LENGTH);
511 }
512 target_end = targ_string.get_string() + true_target->hash.length;
513
514 /*
515 * We compare the tail of the target name with the suffixes
516 * from .SUFFIXES.
517 */
518 if (debug_level > 1) {
519 (void) printf(NOCATGETS("%*sfind_ar_suffix_rule(%s)\n"),
520 recursion_level,
521 "",
522 true_target->string_mb);
523 }
524 /*
525 * Scan the .SUFFIXES list to see if the target matches any of
526 * those suffixes.
527 */
528 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
529 /* Compare one suffix. */
530 suffix_length = suffix->name->hash.length;
531 suf_string.init(suffix->name);
532 if (!IS_WEQUALN(suf_string.get_string(),
533 target_end - suffix_length,
534 suffix_length)) {
535 goto not_this_one;
536 }
537 /*
538 * The target tail matched a suffix from the .SUFFIXES list.
539 * Now check for a rule to match.
600
601 Wstring targ_string;
602 Wstring suf_string;
603
604 /*
605 * If the target is a constructed one for a "::" target,
606 * we need to consider that.
607 */
608 if (target->has_target_prop) {
609 true_target = get_prop(target->prop,
610 target_prop)->body.target.target;
611 }
612 targ_string.init(true_target);
613
614 /*
615 * We compare the tail of the target name with the
616 * suffixes from .SUFFIXES.
617 */
618 target_end = targ_string.get_string() + true_target->hash.length;
619 if (debug_level > 1) {
620 (void) printf(NOCATGETS("%*sfind_double_suffix_rule(%s)\n"),
621 recursion_level,
622 "",
623 true_target->string_mb);
624 }
625 /*
626 * Scan the .SUFFIXES list to see if the target matches
627 * any of those suffixes.
628 */
629 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
630 target->suffix_scan_done = false;
631 true_target->suffix_scan_done = false;
632 /* Compare one suffix. */
633 suffix_length = suffix->name->hash.length;
634 suf_string.init(suffix->name);
635 /* Check the lengths, or else RTC will report rua. */
636 if (true_target->hash.length < suffix_length) {
637 goto not_this_one;
638 } else if (!IS_WEQUALN(suf_string.get_string(),
639 (target_end - suffix_length),
640 suffix_length)) {
692 * debug_level Indicates how much tracing to do
693 * recursion_level Used for tracing
694 * suffixes List of suffixes used for scan (from .SUFFIXES)
695 * working_on_targets Indicates that this is a real target
696 */
697 void
698 build_suffix_list(register Name target_suffix)
699 {
700 register Dependency source_suffix;
701 wchar_t rule_name[MAXPATHLEN];
702 register Property line;
703 register Property suffix;
704 Name rule;
705
706 /* If this is before default.mk has been read we just return to try */
707 /* again later */
708 if ((suffixes == NULL) || !working_on_targets) {
709 return;
710 }
711 if (debug_level > 1) {
712 (void) printf(NOCATGETS("%*sbuild_suffix_list(%s) "),
713 recursion_level,
714 "",
715 target_suffix->string_mb);
716 }
717 /* Mark the target suffix saying we cashed its list */
718 target_suffix->has_read_suffixes = true;
719 /* Scan the .SUFFIXES list */
720 for (source_suffix = suffixes;
721 source_suffix != NULL;
722 source_suffix = source_suffix->next) {
723 /*
724 * Build the name "<suffix-on-list><target-suffix>".
725 * (a popular one would be ".c.o").
726 */
727 (void) mbstowcs(rule_name,
728 source_suffix->name->string_mb,
729 (int) source_suffix->name->hash.length);
730 (void) mbstowcs(rule_name + source_suffix->name->hash.length,
731 target_suffix->string_mb,
732 (int) target_suffix->hash.length);
805 wchar_t percent_buf[STRING_BUFFER_LENGTH];
806 Name true_target = target;
807 Name less;
808 Boolean nonpattern_less;
809 Boolean dep_name_found = false;
810 Doname result = build_dont_know;
811 Percent rule_candidate = NULL;
812 Boolean rule_maybe_ok;
813 Boolean is_pattern;
814
815 /* If the target is constructed for a "::" target we consider that */
816 if (target->has_target_prop) {
817 true_target = get_prop(target->prop,
818 target_prop)->body.target.target;
819 }
820 if (target->has_long_member_name) {
821 true_target = get_prop(target->prop,
822 long_member_name_prop)->body.long_member_name.member_name;
823 }
824 if (debug_level > 1) {
825 (void) printf(catgets(catd, 1, 222, "%*sLooking for %% rule for %s\n"),
826 recursion_level,
827 "",
828 true_target->string_mb);
829 }
830 for (pat_rule = percent_list;
831 pat_rule != NULL;
832 pat_rule = pat_rule->next) {
833 /* Avoid infinite recursion when expanding patterns */
834 if (pat_rule->being_expanded == true) {
835 continue;
836 }
837
838 /* Mark this pat_rule as "maybe ok". If no % rule is found
839 make will use this rule. The following algorithm is used:
840 1) make scans all pattern rules in order to find the rule
841 where ALL dependencies, including nonpattern ones, exist or
842 can be built (GNU behaviour). If such rule is found make
843 will apply it.
844 2) During this check make also remembers the first pattern rule
845 where all PATTERN dependencies can be build (no matter what
886 is_pattern = false;
887 depe_to_check = pat_depe->name;
888 if(depe_to_check->dollar) {
889 INIT_STRING_FROM_STACK(string, string_buf);
890 expand_value(depe_to_check, &string, false);
891 depe_to_check = getname_fn(string.buffer.start,
892 FIND_LENGTH,
893 false,
894 &dep_name_found
895 );
896 }
897 if (less == NULL) {
898 less = depe_to_check;
899 }
900 }
901
902 if (depe_to_check == empty_name) {
903 result = build_ok;
904 } else {
905 if (debug_level > 1) {
906 (void) printf(catgets(catd, 1, 223, "%*sTrying %s\n"),
907 recursion_level,
908 "",
909 depe_to_check->string_mb);
910 }
911
912 pat_rule->being_expanded = true;
913
914 /* suppress message output */
915 int save_debug_level = debug_level;
916 debug_level = 0;
917
918 /* check whether dependency can be built */
919 if (dependency_exists(depe_to_check,
920 get_prop(target->prop,
921 line_prop)))
922 {
923 result = (Doname) depe_to_check->state;
924 } else {
925 if(actual_doname) {
926 result = doname(depe_to_check, true, true);
976 or return build_dont_know if there is no candidate.
977 */
978 if (result != build_ok && result != build_running) {
979 if(rule_candidate) {
980 pat_rule = rule_candidate;
981 } else {
982 return build_dont_know;
983 }
984 }
985
986 /* if we are performing only check whether dependency could be built with existing rules,
987 return success */
988 if (command == NULL) {
989 if(pat_rule != NULL) {
990 pat_rule->being_expanded = false;
991 }
992 return result;
993 }
994
995 if (debug_level > 1) {
996 (void) printf(catgets(catd, 1, 224, "%*sMatched %s:"),
997 recursion_level,
998 "",
999 target->string_mb);
1000
1001 for (pat_depe = pat_rule->dependencies;
1002 pat_depe != NULL;
1003 pat_depe = pat_depe->next) {
1004 if (pat_depe->name->percent) {
1005 INIT_STRING_FROM_STACK(string, string_buf);
1006 construct_string_from_pattern(pat_depe, &percent, &string);
1007 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1008 } else {
1009 depe_to_check = pat_depe->name;
1010 if(depe_to_check->dollar) {
1011 INIT_STRING_FROM_STACK(string, string_buf);
1012 expand_value(depe_to_check, &string, false);
1013 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1014 }
1015 }
1016
1017 if (depe_to_check != empty_name) {
1018 (void) printf(" %s", depe_to_check->string_mb);
1019 }
1020 }
1021
1022 (void) printf(catgets(catd, 1, 225, " from: %s:"),
1023 pat_rule->name->string_mb);
1024
1025 for (pat_depe = pat_rule->dependencies;
1026 pat_depe != NULL;
1027 pat_depe = pat_depe->next) {
1028 (void) printf(" %s", pat_depe->name->string_mb);
1029 }
1030
1031 (void) printf("\n");
1032 }
1033
1034 if (true_target->colons == no_colon) {
1035 true_target->colons = one_colon;
1036 }
1037
1038 /* create deppendency list and target group from matched pattern rule */
1039 create_target_group_and_dependencies_list(target, pat_rule, &percent);
1040
1041 /* save command */
1042 line = get_prop(target->prop, line_prop);
1052 if (line->body.line.dependencies != NULL) {
1053 /* build all collected dependencies */
1054 for (depe = line->body.line.dependencies;
1055 depe != NULL;
1056 depe = depe->next) {
1057 actual_doname = true;
1058 result = doname_check(depe->name, true, true, depe->automatic);
1059
1060 actual_doname = false;
1061 if (result == build_failed) {
1062 pat_rule->being_expanded = false;
1063 return build_failed;
1064 }
1065 if (result == build_running) {
1066 pat_rule->being_expanded = false;
1067 return build_running;
1068 }
1069
1070 if ((depe->name->stat.time > line->body.line.dependency_time) &&
1071 (debug_level > 1)) {
1072 (void) printf(catgets(catd, 1, 226, "%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
1073 recursion_level,
1074 "",
1075 depe->name->string_mb,
1076 time_to_string(depe->name->stat.time),
1077 true_target->string_mb,
1078 time_to_string(line->body.line.dependency_time));
1079 }
1080
1081 line->body.line.dependency_time =
1082 MAX(line->body.line.dependency_time, depe->name->stat.time);
1083
1084 /* determine whether this dependency made target out of date */
1085 Boolean out_of_date;
1086 if (target->is_member || depe->name->is_member) {
1087 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time);
1088 } else {
1089 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time);
1090 }
1091 if (build_unconditional || out_of_date) {
1092 if(!rechecking) {
1093 line->body.line.is_out_of_date = true;
1094 }
1095 add_target_to_chain(depe->name, &(line->body.line.query));
1096
1097 if (debug_level > 0) {
1098 (void) printf(catgets(catd, 1, 227, "%*sBuilding %s using pattern rule %s:"),
1099 recursion_level,
1100 "",
1101 true_target->string_mb,
1102 pat_rule->name->string_mb);
1103
1104 for (pat_depe = pat_rule->dependencies;
1105 pat_depe != NULL;
1106 pat_depe = pat_depe->next) {
1107 (void) printf(" %s", pat_depe->name->string_mb);
1108 }
1109
1110 (void) printf(catgets(catd, 1, 228, " because it is out of date relative to %s\n"),
1111 depe->name->string_mb);
1112 }
1113 }
1114 }
1115 } else {
1116 if ((true_target->stat.time <= file_doesnt_exist) ||
1117 (true_target->stat.time < line->body.line.dependency_time)) {
1118 if(!rechecking) {
1119 line->body.line.is_out_of_date = true;
1120 }
1121 if (debug_level > 0) {
1122 (void) printf(catgets(catd, 1, 229, "%*sBuilding %s using pattern rule %s: "),
1123 recursion_level,
1124 "",
1125 true_target->string_mb,
1126 pat_rule->name->string_mb,
1127 (target->stat.time > file_doesnt_exist) ?
1128 catgets(catd, 1, 230, "because it is out of date") :
1129 catgets(catd, 1, 236, "because it does not exist"));
1130 }
1131 }
1132 }
1133
1134 /* enter explicit rule from percent rule */
1135 Name lmn_target = true_target;
1136 if (true_target->has_long_member_name) {
1137 lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name;
1138 }
1139 line->body.line.sccs_command = false;
1140 line->body.line.target = true_target;
1141 line->body.line.command_template = pat_rule->command_template;
1142 line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH);
1143 line->body.line.less = less;
1144
1145 if (lmn_target->parenleft) {
1146 Wstring lmn_string(lmn_target);
1147
1148 wchar_t *left = (wchar_t *) wschr(lmn_string.get_string(), (int) parenleft_char);
1149 wchar_t *right = (wchar_t *) wschr(lmn_string.get_string(), (int) parenright_char);
|
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * implicit.c
28 *
29 * Handle suffix and percent rules
30 */
31
32 /*
33 * Included files
34 */
35 #include <mk/defs.h>
36 #include <mksh/macro.h> /* expand_value() */
37 #include <mksh/misc.h> /* retmem() */
38 #include <libintl.h>
39
40 /*
41 * Defined macros
42 */
43
44 /*
45 * typedefs & structs
46 */
47
48 /*
49 * Static variables
50 */
51 static wchar_t WIDE_NULL[1] = {(wchar_t) nul_char};
52
53 /*
54 * File table of contents
55 */
56 extern Doname find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking);
57 extern Doname find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking);
58 extern Doname find_double_suffix_rule(register Name target, Property *command, Boolean rechecking);
123 Boolean posix_tilde_attempt = true;
124 int src_len = MAXPATHLEN + strlen(target_body->string_mb);
125
126 /*
127 * To avoid infinite recursion
128 */
129 if(we_are_in_tilde) {
130 we_are_in_tilde = false;
131 return(build_dont_know);
132 }
133
134 /*
135 * If the target is a constructed one for a "::" target,
136 * we need to consider that.
137 */
138 if (target->has_target_prop) {
139 true_target = get_prop(target->prop,
140 target_prop)->body.target.target;
141 }
142 if (debug_level > 1) {
143 (void) printf("%*sfind_suffix_rule(%s,%s,%s)\n",
144 recursion_level,
145 "",
146 true_target->string_mb,
147 target_body->string_mb,
148 target_suffix->string_mb);
149 }
150 if (command != NULL) {
151 if ((true_target->suffix_scan_done == true) && (*command == NULL)) {
152 return build_ok;
153 }
154 }
155 true_target->suffix_scan_done = true;
156 /*
157 * Enter all names from the directory where the target lives as
158 * files that makes sense.
159 * This will make finding the synthesized source possible.
160 */
161 read_directory_of_file(target_body);
162 /* Cache the suffixes for this target suffix if not done. */
163 if (!target_suffix->has_read_suffixes) {
173 put_suffix = sourcename + target_body->hash.length;
174 /* Scan the suffix list for the target if one exists. */
175 if (target_suffix->has_suffixes) {
176 posix_attempts:
177 for (source_suffix = get_prop(target_suffix->prop,
178 suffix_prop);
179 source_suffix != NULL;
180 source_suffix = get_prop(source_suffix->next,
181 suffix_prop)) {
182 /* Build the synthesized source name. */
183 (void) mbstowcs(put_suffix,
184 source_suffix->body.
185 suffix.suffix->string_mb,
186 (int) source_suffix->body.
187 suffix.suffix->hash.length);
188 put_suffix[source_suffix->body.
189 suffix.suffix->hash.length] =
190 (int) nul_char;
191 if (debug_level > 1) {
192 WCSTOMBS(mbs_buffer, sourcename);
193 (void) printf(gettext("%*sTrying %s\n"),
194 recursion_level,
195 "",
196 mbs_buffer);
197 }
198 source = getname_fn(sourcename, FIND_LENGTH, false, &name_found);
199 /*
200 * If the source file is not registered as
201 * a file, this source suffix did not match.
202 */
203 if(vpath_defined && !posix && !svr4) {
204 (void) exists(source);
205 }
206 if (!source->stat.is_file) {
207 if(!(posix|svr4))
208 {
209 if(!name_found) {
210 free_name(source);
211 }
212 continue;
213 }
223
224 if(source->string_mb[source->hash.length - 1] == '~' &&
225 ( svr4 || posix_tilde_attempt ) )
226 {
227 char *p, *np;
228 char *tmpbuf;
229
230 tmpbuf = getmem(source->hash.length + 8);
231 /* + 8 to add "s." or "SCCS/s." */
232 memset(tmpbuf,0,source->hash.length + 8);
233 source->string_mb[source->hash.length - 1] = '\0';
234 if(p = (char *) memchr((char *)source->string_mb,'/',source->hash.length))
235 {
236 while(1) {
237 if(np = (char *) memchr((char *)p+1,'/',source->hash.length - (p - source->string_mb))) {
238 p = np;
239 } else {break;}
240 }
241 /* copy everything including '/' */
242 strncpy(tmpbuf, source->string_mb, p - source->string_mb + 1);
243 strcat(tmpbuf, "s.");
244 strcat(tmpbuf, p+1);
245 retmem((wchar_t *) source->string_mb);
246 source->string_mb = tmpbuf;
247
248 } else {
249 strcpy(tmpbuf, "s.");
250 strcat(tmpbuf, source->string_mb);
251 retmem((wchar_t *) source->string_mb);
252 source->string_mb = tmpbuf;
253
254 }
255 source->hash.length = strlen(source->string_mb);
256 if(exists(source) == file_doesnt_exist)
257 continue;
258 tilde_rule = true;
259 we_are_in_tilde = true;
260 } else {
261 if(!name_found) {
262 free_name(source);
263 }
264 continue;
265 }
266 } else {
267 if(posix && posix_tilde_attempt) {
268 if(exists(source) == file_doesnt_exist) {
269 if(!name_found) {
333 enter_dependency(line, source, false);
334 line->body.line.target = true_target;
335 return build_running;
336 case build_ok:
337 if(!name_found) {
338 store_name(source);
339 }
340 break;
341 case build_failed:
342 if(!name_found) {
343 store_name(source);
344 }
345 if (sourcename != static_string_buf_3M) {
346 retmem(sourcename);
347 }
348 return build_failed;
349 }
350
351 if (debug_level > 1) {
352 WCSTOMBS(mbs_buffer, sourcename);
353 (void) printf(gettext("%*sFound %s\n"),
354 recursion_level,
355 "",
356 mbs_buffer);
357 }
358
359 if (source->depends_on_conditional) {
360 target->depends_on_conditional = true;
361 }
362 /*
363 * Since it is possible that the same target is built several times during
364 * the make run, we have to patch the target with all information we found
365 * here. Thus, the target will have an explicit rule the next time around.
366 */
367 line = maybe_append_prop(target, line_prop);
368 if (*command == NULL) {
369 *command = line;
370 }
371 if ((source->stat.time > (*command)->body.line.dependency_time) &&
372 (debug_level > 1)) {
373 (void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
374 recursion_level,
375 "",
376 source->string_mb,
377 time_to_string(source->
378 stat.time),
379 true_target->string_mb,
380 time_to_string((*command)->
381 body.line.
382 dependency_time));
383 }
384 /*
385 * Determine if this new dependency made the
386 * target out of date.
387 */
388 (*command)->body.line.dependency_time =
389 MAX((*command)->body.line.dependency_time,
390 source->stat.time);
391 Boolean out_of_date;
392 if (target->is_member) {
393 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time,
394 (*command)->body.line.dependency_time);
395 } else {
396 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time,
397 (*command)->body.line.dependency_time);
398 }
399 if (build_unconditional || out_of_date) {
400 if(!rechecking) {
401 line->body.line.is_out_of_date = true;
402 }
403 if (debug_level > 0) {
404 (void) printf(gettext("%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"),
405 recursion_level,
406 "",
407 true_target->string_mb,
408 source_suffix->body.suffix.suffix->string_mb,
409 target_suffix->string_mb,
410 source->string_mb);
411 }
412 }
413 /*
414 * Add the implicit rule as the target's explicit
415 * rule if none actually given, and register
416 * dependency.
417 * The time checking above really should be
418 * conditional on actual use of implicit rule
419 * as well.
420 */
421 line->body.line.sccs_command = false;
422 if (line->body.line.command_template == NULL) {
423 line->body.line.command_template =
424 source_suffix->body.suffix.command_template;
425 }
426 enter_dependency(line, source, false);
427 line->body.line.target = true_target;
428 /*
429 * Also make sure the rule is built with
430 * $* and $< bound properly.
431 */
432 line->body.line.star = target_body;
433 if(svr4|posix) {
434 char * p;
435 char tstr[256];
436 extern Boolean dollarless_flag;
437 extern Name dollarless_value;
438
439 if(tilde_rule) {
440 MBSTOWCS(wcs_buffer, source->string_mb);
441 dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH);
442 }
443 else {
444 dollarless_flag = false;
445 }
446 }
447 line->body.line.less = source;
448 line->body.line.percent = NULL;
449 add_target_to_chain(source, &(line->body.line.query));
450 if (sourcename != static_string_buf_3M) {
451 retmem(sourcename);
452 }
453 return build_ok;
454 }
455 if(posix && posix_tilde_attempt) {
456 posix_tilde_attempt = false;
457 goto posix_attempts;
458 }
459 if ((command != NULL) &&
460 ((*command) != NULL) &&
490 * Global variables used:
491 * debug_level Indicates how much tracing to do
492 * dot_a The Name ".a", compared against
493 * recursion_level Used for tracing
494 * suffixes List of suffixes used for scan (from .SUFFIXES)
495 */
496 Doname
497 find_ar_suffix_rule(register Name target, Name true_target, Property *command, Boolean rechecking)
498 {
499 wchar_t *target_end;
500 register Dependency suffix;
501 register int suffix_length;
502 Property line;
503 Name body;
504 static Name dot_a;
505
506 Wstring targ_string(true_target);
507 Wstring suf_string;
508
509 if (dot_a == NULL) {
510 MBSTOWCS(wcs_buffer, ".a");
511 dot_a = GETNAME(wcs_buffer, FIND_LENGTH);
512 }
513 target_end = targ_string.get_string() + true_target->hash.length;
514
515 /*
516 * We compare the tail of the target name with the suffixes
517 * from .SUFFIXES.
518 */
519 if (debug_level > 1) {
520 (void) printf("%*sfind_ar_suffix_rule(%s)\n",
521 recursion_level,
522 "",
523 true_target->string_mb);
524 }
525 /*
526 * Scan the .SUFFIXES list to see if the target matches any of
527 * those suffixes.
528 */
529 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
530 /* Compare one suffix. */
531 suffix_length = suffix->name->hash.length;
532 suf_string.init(suffix->name);
533 if (!IS_WEQUALN(suf_string.get_string(),
534 target_end - suffix_length,
535 suffix_length)) {
536 goto not_this_one;
537 }
538 /*
539 * The target tail matched a suffix from the .SUFFIXES list.
540 * Now check for a rule to match.
601
602 Wstring targ_string;
603 Wstring suf_string;
604
605 /*
606 * If the target is a constructed one for a "::" target,
607 * we need to consider that.
608 */
609 if (target->has_target_prop) {
610 true_target = get_prop(target->prop,
611 target_prop)->body.target.target;
612 }
613 targ_string.init(true_target);
614
615 /*
616 * We compare the tail of the target name with the
617 * suffixes from .SUFFIXES.
618 */
619 target_end = targ_string.get_string() + true_target->hash.length;
620 if (debug_level > 1) {
621 (void) printf("%*sfind_double_suffix_rule(%s)\n",
622 recursion_level,
623 "",
624 true_target->string_mb);
625 }
626 /*
627 * Scan the .SUFFIXES list to see if the target matches
628 * any of those suffixes.
629 */
630 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
631 target->suffix_scan_done = false;
632 true_target->suffix_scan_done = false;
633 /* Compare one suffix. */
634 suffix_length = suffix->name->hash.length;
635 suf_string.init(suffix->name);
636 /* Check the lengths, or else RTC will report rua. */
637 if (true_target->hash.length < suffix_length) {
638 goto not_this_one;
639 } else if (!IS_WEQUALN(suf_string.get_string(),
640 (target_end - suffix_length),
641 suffix_length)) {
693 * debug_level Indicates how much tracing to do
694 * recursion_level Used for tracing
695 * suffixes List of suffixes used for scan (from .SUFFIXES)
696 * working_on_targets Indicates that this is a real target
697 */
698 void
699 build_suffix_list(register Name target_suffix)
700 {
701 register Dependency source_suffix;
702 wchar_t rule_name[MAXPATHLEN];
703 register Property line;
704 register Property suffix;
705 Name rule;
706
707 /* If this is before default.mk has been read we just return to try */
708 /* again later */
709 if ((suffixes == NULL) || !working_on_targets) {
710 return;
711 }
712 if (debug_level > 1) {
713 (void) printf("%*sbuild_suffix_list(%s) ",
714 recursion_level,
715 "",
716 target_suffix->string_mb);
717 }
718 /* Mark the target suffix saying we cashed its list */
719 target_suffix->has_read_suffixes = true;
720 /* Scan the .SUFFIXES list */
721 for (source_suffix = suffixes;
722 source_suffix != NULL;
723 source_suffix = source_suffix->next) {
724 /*
725 * Build the name "<suffix-on-list><target-suffix>".
726 * (a popular one would be ".c.o").
727 */
728 (void) mbstowcs(rule_name,
729 source_suffix->name->string_mb,
730 (int) source_suffix->name->hash.length);
731 (void) mbstowcs(rule_name + source_suffix->name->hash.length,
732 target_suffix->string_mb,
733 (int) target_suffix->hash.length);
806 wchar_t percent_buf[STRING_BUFFER_LENGTH];
807 Name true_target = target;
808 Name less;
809 Boolean nonpattern_less;
810 Boolean dep_name_found = false;
811 Doname result = build_dont_know;
812 Percent rule_candidate = NULL;
813 Boolean rule_maybe_ok;
814 Boolean is_pattern;
815
816 /* If the target is constructed for a "::" target we consider that */
817 if (target->has_target_prop) {
818 true_target = get_prop(target->prop,
819 target_prop)->body.target.target;
820 }
821 if (target->has_long_member_name) {
822 true_target = get_prop(target->prop,
823 long_member_name_prop)->body.long_member_name.member_name;
824 }
825 if (debug_level > 1) {
826 (void) printf(gettext("%*sLooking for %% rule for %s\n"),
827 recursion_level,
828 "",
829 true_target->string_mb);
830 }
831 for (pat_rule = percent_list;
832 pat_rule != NULL;
833 pat_rule = pat_rule->next) {
834 /* Avoid infinite recursion when expanding patterns */
835 if (pat_rule->being_expanded == true) {
836 continue;
837 }
838
839 /* Mark this pat_rule as "maybe ok". If no % rule is found
840 make will use this rule. The following algorithm is used:
841 1) make scans all pattern rules in order to find the rule
842 where ALL dependencies, including nonpattern ones, exist or
843 can be built (GNU behaviour). If such rule is found make
844 will apply it.
845 2) During this check make also remembers the first pattern rule
846 where all PATTERN dependencies can be build (no matter what
887 is_pattern = false;
888 depe_to_check = pat_depe->name;
889 if(depe_to_check->dollar) {
890 INIT_STRING_FROM_STACK(string, string_buf);
891 expand_value(depe_to_check, &string, false);
892 depe_to_check = getname_fn(string.buffer.start,
893 FIND_LENGTH,
894 false,
895 &dep_name_found
896 );
897 }
898 if (less == NULL) {
899 less = depe_to_check;
900 }
901 }
902
903 if (depe_to_check == empty_name) {
904 result = build_ok;
905 } else {
906 if (debug_level > 1) {
907 (void) printf(gettext("%*sTrying %s\n"),
908 recursion_level,
909 "",
910 depe_to_check->string_mb);
911 }
912
913 pat_rule->being_expanded = true;
914
915 /* suppress message output */
916 int save_debug_level = debug_level;
917 debug_level = 0;
918
919 /* check whether dependency can be built */
920 if (dependency_exists(depe_to_check,
921 get_prop(target->prop,
922 line_prop)))
923 {
924 result = (Doname) depe_to_check->state;
925 } else {
926 if(actual_doname) {
927 result = doname(depe_to_check, true, true);
977 or return build_dont_know if there is no candidate.
978 */
979 if (result != build_ok && result != build_running) {
980 if(rule_candidate) {
981 pat_rule = rule_candidate;
982 } else {
983 return build_dont_know;
984 }
985 }
986
987 /* if we are performing only check whether dependency could be built with existing rules,
988 return success */
989 if (command == NULL) {
990 if(pat_rule != NULL) {
991 pat_rule->being_expanded = false;
992 }
993 return result;
994 }
995
996 if (debug_level > 1) {
997 (void) printf(gettext("%*sMatched %s:"),
998 recursion_level,
999 "",
1000 target->string_mb);
1001
1002 for (pat_depe = pat_rule->dependencies;
1003 pat_depe != NULL;
1004 pat_depe = pat_depe->next) {
1005 if (pat_depe->name->percent) {
1006 INIT_STRING_FROM_STACK(string, string_buf);
1007 construct_string_from_pattern(pat_depe, &percent, &string);
1008 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1009 } else {
1010 depe_to_check = pat_depe->name;
1011 if(depe_to_check->dollar) {
1012 INIT_STRING_FROM_STACK(string, string_buf);
1013 expand_value(depe_to_check, &string, false);
1014 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1015 }
1016 }
1017
1018 if (depe_to_check != empty_name) {
1019 (void) printf(" %s", depe_to_check->string_mb);
1020 }
1021 }
1022
1023 (void) printf(gettext(" from: %s:"),
1024 pat_rule->name->string_mb);
1025
1026 for (pat_depe = pat_rule->dependencies;
1027 pat_depe != NULL;
1028 pat_depe = pat_depe->next) {
1029 (void) printf(" %s", pat_depe->name->string_mb);
1030 }
1031
1032 (void) printf("\n");
1033 }
1034
1035 if (true_target->colons == no_colon) {
1036 true_target->colons = one_colon;
1037 }
1038
1039 /* create deppendency list and target group from matched pattern rule */
1040 create_target_group_and_dependencies_list(target, pat_rule, &percent);
1041
1042 /* save command */
1043 line = get_prop(target->prop, line_prop);
1053 if (line->body.line.dependencies != NULL) {
1054 /* build all collected dependencies */
1055 for (depe = line->body.line.dependencies;
1056 depe != NULL;
1057 depe = depe->next) {
1058 actual_doname = true;
1059 result = doname_check(depe->name, true, true, depe->automatic);
1060
1061 actual_doname = false;
1062 if (result == build_failed) {
1063 pat_rule->being_expanded = false;
1064 return build_failed;
1065 }
1066 if (result == build_running) {
1067 pat_rule->being_expanded = false;
1068 return build_running;
1069 }
1070
1071 if ((depe->name->stat.time > line->body.line.dependency_time) &&
1072 (debug_level > 1)) {
1073 (void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
1074 recursion_level,
1075 "",
1076 depe->name->string_mb,
1077 time_to_string(depe->name->stat.time),
1078 true_target->string_mb,
1079 time_to_string(line->body.line.dependency_time));
1080 }
1081
1082 line->body.line.dependency_time =
1083 MAX(line->body.line.dependency_time, depe->name->stat.time);
1084
1085 /* determine whether this dependency made target out of date */
1086 Boolean out_of_date;
1087 if (target->is_member || depe->name->is_member) {
1088 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time);
1089 } else {
1090 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time);
1091 }
1092 if (build_unconditional || out_of_date) {
1093 if(!rechecking) {
1094 line->body.line.is_out_of_date = true;
1095 }
1096 add_target_to_chain(depe->name, &(line->body.line.query));
1097
1098 if (debug_level > 0) {
1099 (void) printf(gettext("%*sBuilding %s using pattern rule %s:"),
1100 recursion_level,
1101 "",
1102 true_target->string_mb,
1103 pat_rule->name->string_mb);
1104
1105 for (pat_depe = pat_rule->dependencies;
1106 pat_depe != NULL;
1107 pat_depe = pat_depe->next) {
1108 (void) printf(" %s", pat_depe->name->string_mb);
1109 }
1110
1111 (void) printf(gettext(" because it is out of date relative to %s\n"),
1112 depe->name->string_mb);
1113 }
1114 }
1115 }
1116 } else {
1117 if ((true_target->stat.time <= file_doesnt_exist) ||
1118 (true_target->stat.time < line->body.line.dependency_time)) {
1119 if(!rechecking) {
1120 line->body.line.is_out_of_date = true;
1121 }
1122 if (debug_level > 0) {
1123 (void) printf(gettext("%*sBuilding %s using pattern rule %s: "),
1124 recursion_level,
1125 "",
1126 true_target->string_mb,
1127 pat_rule->name->string_mb,
1128 (target->stat.time > file_doesnt_exist) ?
1129 gettext("because it is out of date") :
1130 gettext("because it does not exist"));
1131 }
1132 }
1133 }
1134
1135 /* enter explicit rule from percent rule */
1136 Name lmn_target = true_target;
1137 if (true_target->has_long_member_name) {
1138 lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name;
1139 }
1140 line->body.line.sccs_command = false;
1141 line->body.line.target = true_target;
1142 line->body.line.command_template = pat_rule->command_template;
1143 line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH);
1144 line->body.line.less = less;
1145
1146 if (lmn_target->parenleft) {
1147 Wstring lmn_string(lmn_target);
1148
1149 wchar_t *left = (wchar_t *) wschr(lmn_string.get_string(), (int) parenleft_char);
1150 wchar_t *right = (wchar_t *) wschr(lmn_string.get_string(), (int) parenright_char);
|