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 2004 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2019 RackTop Systems.
26 */
27
28 /*
29 * implicit.c
30 *
31 * Handle suffix and percent rules
32 */
33
34 /*
35 * Included files
36 */
37 #include <mk/defs.h>
38 #include <mksh/macro.h> /* expand_value() */
39 #include <mksh/misc.h> /* retmem() */
40 #include <libintl.h>
41
42 /*
43 * Defined macros
44 */
45
46 /*
47 * typedefs & structs
48 */
49
50 /*
51 * Static variables
52 */
53 static wchar_t WIDE_NULL[1] = {(wchar_t) nul_char};
54
55 /*
56 * File table of contents
57 */
58 extern Doname find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking);
59 extern Doname find_ar_suffix_rule(Name target, Name true_target, Property *command, Boolean rechecking);
60 extern Doname find_double_suffix_rule(Name target, Property *command, Boolean rechecking);
61 extern void build_suffix_list(Name target_suffix);
62 extern Doname find_percent_rule(Name target, Property *command, Boolean rechecking);
63 static void create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent);
64 static Boolean match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf);
65 static void construct_string_from_pattern(Percent pat_rule, String percent, String result);
66 static Boolean dependency_exists(Name target, Property line);
67 extern Property maybe_append_prop(Name, Property_id);
68 extern void add_target_to_chain(Name target, Chain * query);
69
70 /*
71 * find_suffix_rule(target, target_body, target_suffix, command, rechecking)
72 *
73 * Does the lookup for single and double suffix rules.
74 * It calls build_suffix_list() to build the list of possible suffixes
75 * for the given target.
76 * It then scans the list to find the first possible source file that
77 * exists. This is done by concatenating the body of the target name
78 * (target name less target suffix) and the source suffix and checking
79 * if the resulting file exists.
80 *
81 * Return value:
82 * Indicates if search failed or not
83 *
84 * Parameters:
85 * target The target we need a rule for
86 * target_body The target name without the suffix
87 * target_suffix The suffix of the target
88 * command Pointer to slot to deposit cmd in if found
89 * rechecking true if we are rechecking target which depends
90 * on conditional macro and keep_state is set
91 *
92 * Global variables used:
93 * debug_level Indicates how much tracing to do
94 * recursion_level Used for tracing
95 */
96
97 static Boolean actual_doname = false;
98
99 /* /tolik/
100 * fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules.
101 * When make attemps to apply % rule it didn't look for a single suffix rule because
102 * if "doname" is called from "find_percent_rule" argument "implicit" is set to true
103 * and find_suffix_rule was not called. I've commented the checking of "implicit"
104 * in "doname" and make got infinite recursion for SVR4 tilde rules.
105 * Usage of "we_are_in_tilde" is intended to avoid this recursion.
106 */
107
108 static Boolean we_are_in_tilde = false;
109
110 Doname
find_suffix_rule(Name target,Name target_body,Name target_suffix,Property * command,Boolean rechecking)111 find_suffix_rule(Name target, Name target_body, Name target_suffix, Property *command, Boolean rechecking)
112 {
113 static wchar_t static_string_buf_3M [ 3 * MAXPATHLEN ];
114 Name true_target = target;
115 wchar_t *sourcename = (wchar_t*)static_string_buf_3M;
116 wchar_t *put_suffix;
117 Property source_suffix;
118 Name source;
119 Doname result;
120 Property line;
121 extern Boolean tilde_rule;
122 Boolean name_found = true;
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) {
164 build_suffix_list(target_suffix);
165 }
166 /* Preload the sourcename vector with the head of the target name. */
167 if (src_len >= sizeof(static_string_buf_3M)) {
168 sourcename = ALLOC_WC(src_len);
169 }
170 (void) mbstowcs(sourcename,
171 target_body->string_mb,
172 (int) target_body->hash.length);
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 }
214
215 /* following code will ensure that the corresponding
216 ** tilde rules are executed when corresponding s. file
217 ** exists in the current directory. Though the current
218 ** target ends with a ~ character, there wont be any
219 ** any file in the current directory with that suffix
220 ** as it's fictitious. Even if it exists, it'll
221 ** execute all the rules for the ~ target.
222 */
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) {
270 free_name(source);
271 }
272 continue;
273 }
274 }
275 }
276
277 if (command != NULL) {
278 if(!name_found) {
279 store_name(source);
280 }
281 /*
282 * The source file is a file.
283 * Make sure it is up to date.
284 */
285 if (dependency_exists(source,
286 get_prop(target->prop,
287 line_prop))) {
288 result = (Doname) source->state;
289 } else {
290 #if 0 /* with_squiggle sends false, which is buggy. : djay */
291 result = doname(source,
292 (Boolean) source_suffix->body.
293 suffix.suffix->with_squiggle,
294 true);
295 #else
296 result = doname(source,
297 true,
298 true);
299 #endif
300 }
301 } else {
302 result = target_can_be_built(source);
303
304 if (result == build_ok) {
305 return result;
306 } else {
307 if(!name_found) {
308 free_name(source);
309 }
310 continue;
311 }
312 }
313
314 switch (result) {
315 case build_dont_know:
316 /*
317 * If we still can't build the source,
318 * this rule is not a match,
319 * try the next one.
320 */
321 if (source->stat.time == file_doesnt_exist) {
322 if(!name_found) {
323 free_name(source);
324 }
325 continue;
326 }
327 /* FALLTHROUGH */
328 case build_running:
329 if(!name_found) {
330 store_name(source);
331 }
332 true_target->suffix_scan_done = false;
333 line = maybe_append_prop(target, line_prop);
334 enter_dependency(line, source, false);
335 line->body.line.target = true_target;
336 return build_running;
337 case build_ok:
338 if(!name_found) {
339 store_name(source);
340 }
341 break;
342 case build_failed:
343 if(!name_found) {
344 store_name(source);
345 }
346 if (sourcename != static_string_buf_3M) {
347 retmem(sourcename);
348 }
349 return build_failed;
350 }
351
352 if (debug_level > 1) {
353 WCSTOMBS(mbs_buffer, sourcename);
354 (void) printf(gettext("%*sFound %s\n"),
355 recursion_level,
356 "",
357 mbs_buffer);
358 }
359
360 if (source->depends_on_conditional) {
361 target->depends_on_conditional = true;
362 }
363 /*
364 * Since it is possible that the same target is built several times during
365 * the make run, we have to patch the target with all information we found
366 * here. Thus, the target will have an explicit rule the next time around.
367 */
368 line = maybe_append_prop(target, line_prop);
369 if (*command == NULL) {
370 *command = line;
371 }
372 if ((source->stat.time > (*command)->body.line.dependency_time) &&
373 (debug_level > 1)) {
374 (void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
375 recursion_level,
376 "",
377 source->string_mb,
378 time_to_string(source->
379 stat.time),
380 true_target->string_mb,
381 time_to_string((*command)->
382 body.line.
383 dependency_time));
384 }
385 /*
386 * Determine if this new dependency made the
387 * target out of date.
388 */
389 (*command)->body.line.dependency_time =
390 MAX((*command)->body.line.dependency_time,
391 source->stat.time);
392 Boolean out_of_date;
393 if (target->is_member) {
394 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time,
395 (*command)->body.line.dependency_time);
396 } else {
397 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time,
398 (*command)->body.line.dependency_time);
399 }
400 if (build_unconditional || out_of_date) {
401 if(!rechecking) {
402 line->body.line.is_out_of_date = true;
403 }
404 if (debug_level > 0) {
405 (void) printf(gettext("%*sBuilding %s using suffix rule for %s%s because it is out of date relative to %s\n"),
406 recursion_level,
407 "",
408 true_target->string_mb,
409 source_suffix->body.suffix.suffix->string_mb,
410 target_suffix->string_mb,
411 source->string_mb);
412 }
413 }
414 /*
415 * Add the implicit rule as the target's explicit
416 * rule if none actually given, and register
417 * dependency.
418 * The time checking above really should be
419 * conditional on actual use of implicit rule
420 * as well.
421 */
422 line->body.line.sccs_command = false;
423 if (line->body.line.command_template == NULL) {
424 line->body.line.command_template =
425 source_suffix->body.suffix.command_template;
426 }
427 enter_dependency(line, source, false);
428 line->body.line.target = true_target;
429 /*
430 * Also make sure the rule is built with
431 * $* and $< bound properly.
432 */
433 line->body.line.star = target_body;
434 if(svr4|posix) {
435 char * p;
436 char tstr[256];
437 extern Boolean dollarless_flag;
438 extern Name dollarless_value;
439
440 if(tilde_rule) {
441 MBSTOWCS(wcs_buffer, source->string_mb);
442 dollarless_value = GETNAME(wcs_buffer,FIND_LENGTH);
443 }
444 else {
445 dollarless_flag = false;
446 }
447 }
448 line->body.line.less = source;
449 line->body.line.percent = NULL;
450 add_target_to_chain(source, &(line->body.line.query));
451 if (sourcename != static_string_buf_3M) {
452 retmem(sourcename);
453 }
454 return build_ok;
455 }
456 if(posix && posix_tilde_attempt) {
457 posix_tilde_attempt = false;
458 goto posix_attempts;
459 }
460 if ((command != NULL) &&
461 ((*command) != NULL) &&
462 ((*command)->body.line.star == NULL)) {
463 (*command)->body.line.star = target_body;
464 }
465 }
466 if (sourcename != static_string_buf_3M) {
467 retmem(sourcename);
468 }
469 /* Return here in case no rule matched the target */
470 return build_dont_know;
471 }
472
473 /*
474 * find_ar_suffix_rule(target, true_target, command, rechecking)
475 *
476 * Scans the .SUFFIXES list and tries
477 * to find a suffix on it that matches the tail of the target member name.
478 * If it finds a matching suffix it calls find_suffix_rule() to find
479 * a rule for the target using the suffix ".a".
480 *
481 * Return value:
482 * Indicates if search failed or not
483 *
484 * Parameters:
485 * target The target we need a rule for
486 * true_target The proper name
487 * command Pointer to slot where we stuff cmd, if found
488 * rechecking true if we are rechecking target which depends
489 * on conditional macro and keep_state is set
490 *
491 * Global variables used:
492 * debug_level Indicates how much tracing to do
493 * dot_a The Name ".a", compared against
494 * recursion_level Used for tracing
495 * suffixes List of suffixes used for scan (from .SUFFIXES)
496 */
497 Doname
find_ar_suffix_rule(Name target,Name true_target,Property * command,Boolean rechecking)498 find_ar_suffix_rule(Name target, Name true_target, Property *command, Boolean rechecking)
499 {
500 wchar_t *target_end;
501 Dependency suffix;
502 int suffix_length;
503 Property line;
504 Name body;
505 static Name dot_a;
506
507 Wstring targ_string(true_target);
508 Wstring suf_string;
509
510 if (dot_a == NULL) {
511 MBSTOWCS(wcs_buffer, ".a");
512 dot_a = GETNAME(wcs_buffer, FIND_LENGTH);
513 }
514 target_end = targ_string.get_string() + true_target->hash.length;
515
516 /*
517 * We compare the tail of the target name with the suffixes
518 * from .SUFFIXES.
519 */
520 if (debug_level > 1) {
521 (void) printf("%*sfind_ar_suffix_rule(%s)\n",
522 recursion_level,
523 "",
524 true_target->string_mb);
525 }
526 /*
527 * Scan the .SUFFIXES list to see if the target matches any of
528 * those suffixes.
529 */
530 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
531 /* Compare one suffix. */
532 suffix_length = suffix->name->hash.length;
533 suf_string.init(suffix->name);
534 if (!IS_WEQUALN(suf_string.get_string(),
535 target_end - suffix_length,
536 suffix_length)) {
537 goto not_this_one;
538 }
539 /*
540 * The target tail matched a suffix from the .SUFFIXES list.
541 * Now check for a rule to match.
542 */
543 target->suffix_scan_done = false;
544 body = GETNAME(targ_string.get_string(),
545 (int)(true_target->hash.length -
546 suffix_length));
547 we_are_in_tilde = false;
548 switch (find_suffix_rule(target,
549 body,
550 dot_a,
551 command,
552 rechecking)) {
553 case build_ok:
554 line = get_prop(target->prop, line_prop);
555 line->body.line.star = body;
556 return build_ok;
557 case build_running:
558 return build_running;
559 }
560 /*
561 * If no rule was found, we try the next suffix to see
562 * if it matches the target tail, and so on.
563 * Go here if the suffix did not match the target tail.
564 */
565 not_this_one:;
566 }
567 return build_dont_know;
568 }
569
570 /*
571 * find_double_suffix_rule(target, command, rechecking)
572 *
573 * Scans the .SUFFIXES list and tries
574 * to find a suffix on it that matches the tail of the target name.
575 * If it finds a matching suffix it calls find_suffix_rule() to find
576 * a rule for the target.
577 *
578 * Return value:
579 * Indicates if scan failed or not
580 *
581 * Parameters:
582 * target Target we need a rule for
583 * command Pointer to slot where we stuff cmd, if found
584 * rechecking true if we are rechecking target which depends
585 * on conditional macro and keep_state is set
586 *
587 * Global variables used:
588 * debug_level Indicates how much tracing to do
589 * recursion_level Used for tracing
590 * suffixes List of suffixes used for scan (from .SUFFIXES)
591 */
592 Doname
find_double_suffix_rule(Name target,Property * command,Boolean rechecking)593 find_double_suffix_rule(Name target, Property *command, Boolean rechecking)
594 {
595 Name true_target = target;
596 Name target_body;
597 wchar_t *target_end;
598 Dependency suffix;
599 int suffix_length;
600 Boolean scanned_once = false;
601 Boolean name_found = true;
602
603 Wstring targ_string;
604 Wstring suf_string;
605
606 /*
607 * If the target is a constructed one for a "::" target,
608 * we need to consider that.
609 */
610 if (target->has_target_prop) {
611 true_target = get_prop(target->prop,
612 target_prop)->body.target.target;
613 }
614 targ_string.init(true_target);
615
616 /*
617 * We compare the tail of the target name with the
618 * suffixes from .SUFFIXES.
619 */
620 target_end = targ_string.get_string() + true_target->hash.length;
621 if (debug_level > 1) {
622 (void) printf("%*sfind_double_suffix_rule(%s)\n",
623 recursion_level,
624 "",
625 true_target->string_mb);
626 }
627 /*
628 * Scan the .SUFFIXES list to see if the target matches
629 * any of those suffixes.
630 */
631 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) {
632 target->suffix_scan_done = false;
633 true_target->suffix_scan_done = false;
634 /* Compare one suffix. */
635 suffix_length = suffix->name->hash.length;
636 suf_string.init(suffix->name);
637 /* Check the lengths, or else RTC will report rua. */
638 if (true_target->hash.length < suffix_length) {
639 goto not_this_one;
640 } else if (!IS_WEQUALN(suf_string.get_string(),
641 (target_end - suffix_length),
642 suffix_length)) {
643 goto not_this_one;
644 }
645 /*
646 * The target tail matched a suffix from the .SUFFIXES list.
647 * Now check for a rule to match.
648 */
649 we_are_in_tilde = false;
650 target_body = GETNAME(
651 targ_string.get_string(),
652 (int)(true_target->hash.length - suffix_length)
653 );
654 switch (find_suffix_rule(target,
655 target_body,
656 suffix->name,
657 command,
658 rechecking)) {
659 case build_ok:
660 return build_ok;
661 case build_running:
662 return build_running;
663 }
664 if (true_target->suffix_scan_done == true) {
665 scanned_once = true;
666 }
667 /*
668 * If no rule was found, we try the next suffix to see
669 * if it matches the target tail. And so on.
670 * Go here if the suffix did not match the target tail.
671 */
672 not_this_one:;
673 }
674 if (scanned_once)
675 true_target->suffix_scan_done = true;
676 return build_dont_know;
677 }
678
679 /*
680 * build_suffix_list(target_suffix)
681 *
682 * Scans the .SUFFIXES list and figures out
683 * which suffixes this target can be derived from.
684 * The target itself is not know here, we just know the suffix of the
685 * target. For each suffix on the list the target can be derived iff
686 * a rule exists for the name "<suffix-on-list><target-suffix>".
687 * A list of all possible building suffixes is built, with the rule for
688 * each, and tacked to the target suffix nameblock.
689 *
690 * Parameters:
691 * target_suffix The suffix we build a match list for
692 *
693 * Global variables used:
694 * debug_level Indicates how much tracing to do
695 * recursion_level Used for tracing
696 * suffixes List of suffixes used for scan (from .SUFFIXES)
697 * working_on_targets Indicates that this is a real target
698 */
699 void
build_suffix_list(Name target_suffix)700 build_suffix_list(Name target_suffix)
701 {
702 Dependency source_suffix;
703 wchar_t rule_name[MAXPATHLEN];
704 Property line;
705 Property suffix;
706 Name rule;
707
708 /* If this is before default.mk has been read we just return to try */
709 /* again later */
710 if ((suffixes == NULL) || !working_on_targets) {
711 return;
712 }
713 if (debug_level > 1) {
714 (void) printf("%*sbuild_suffix_list(%s) ",
715 recursion_level,
716 "",
717 target_suffix->string_mb);
718 }
719 /* Mark the target suffix saying we cashed its list */
720 target_suffix->has_read_suffixes = true;
721 /* Scan the .SUFFIXES list */
722 for (source_suffix = suffixes;
723 source_suffix != NULL;
724 source_suffix = source_suffix->next) {
725 /*
726 * Build the name "<suffix-on-list><target-suffix>".
727 * (a popular one would be ".c.o").
728 */
729 (void) mbstowcs(rule_name,
730 source_suffix->name->string_mb,
731 (int) source_suffix->name->hash.length);
732 (void) mbstowcs(rule_name + source_suffix->name->hash.length,
733 target_suffix->string_mb,
734 (int) target_suffix->hash.length);
735 /*
736 * Check if that name has a rule. If not, it cannot match
737 * any implicit rule scan and is ignored.
738 * The GETNAME() call only checks for presence, it will not
739 * enter the name if it is not defined.
740 */
741 if (((rule = getname_fn(rule_name,
742 (int) (source_suffix->name->
743 hash.length +
744 target_suffix->hash.length),
745 true)) != NULL) &&
746 ((line = get_prop(rule->prop, line_prop)) != NULL)) {
747 if (debug_level > 1) {
748 (void) printf("%s ", rule->string_mb);
749 }
750 /*
751 * This makes it possible to quickly determine if
752 * it will pay to look for a suffix property.
753 */
754 target_suffix->has_suffixes = true;
755 /*
756 * Add the suffix property to the target suffix
757 * and save the rule with it.
758 * All information the implicit rule scanner need
759 * is saved in the suffix property.
760 */
761 suffix = append_prop(target_suffix, suffix_prop);
762 suffix->body.suffix.suffix = source_suffix->name;
763 suffix->body.suffix.command_template =
764 line->body.line.command_template;
765 }
766 }
767 if (debug_level > 1) {
768 (void) printf("\n");
769 }
770 }
771
772 /*
773 * find_percent_rule(target, command, rechecking)
774 *
775 * Tries to find a rule from the list of wildcard matched rules.
776 * It scans the list attempting to match the target.
777 * For each target match it checks if the corresponding source exists.
778 * If it does the match is returned.
779 * The percent_list is built at makefile read time.
780 * Each percent rule get one entry on the list.
781 *
782 * Return value:
783 * Indicates if the scan failed or not
784 *
785 * Parameters:
786 * target The target we need a rule for
787 * command Pointer to slot where we stuff cmd, if found
788 * rechecking true if we are rechecking target which depends
789 * on conditional macro and keep_state is set
790 *
791 * Global variables used:
792 * debug_level Indicates how much tracing to do
793 * percent_list List of all percent rules
794 * recursion_level Used for tracing
795 * empty_name
796 */
797 Doname
find_percent_rule(Name target,Property * command,Boolean rechecking)798 find_percent_rule(Name target, Property *command, Boolean rechecking)
799 {
800 Percent pat_rule, pat_depe;
801 Name depe_to_check;
802 Dependency depe;
803 Property line;
804 String_rec string;
805 wchar_t string_buf[STRING_BUFFER_LENGTH];
806 String_rec percent;
807 wchar_t percent_buf[STRING_BUFFER_LENGTH];
808 Name true_target = target;
809 Name less;
810 Boolean nonpattern_less;
811 Boolean dep_name_found = false;
812 Doname result = build_dont_know;
813 Percent rule_candidate = NULL;
814 Boolean rule_maybe_ok;
815 Boolean is_pattern;
816
817 /* If the target is constructed for a "::" target we consider that */
818 if (target->has_target_prop) {
819 true_target = get_prop(target->prop,
820 target_prop)->body.target.target;
821 }
822 if (target->has_long_member_name) {
823 true_target = get_prop(target->prop,
824 long_member_name_prop)->body.long_member_name.member_name;
825 }
826 if (debug_level > 1) {
827 (void) printf(gettext("%*sLooking for %% rule for %s\n"),
828 recursion_level,
829 "",
830 true_target->string_mb);
831 }
832 for (pat_rule = percent_list;
833 pat_rule != NULL;
834 pat_rule = pat_rule->next) {
835 /* Avoid infinite recursion when expanding patterns */
836 if (pat_rule->being_expanded == true) {
837 continue;
838 }
839
840 /* Mark this pat_rule as "maybe ok". If no % rule is found
841 make will use this rule. The following algorithm is used:
842 1) make scans all pattern rules in order to find the rule
843 where ALL dependencies, including nonpattern ones, exist or
844 can be built (GNU behaviour). If such rule is found make
845 will apply it.
846 2) During this check make also remembers the first pattern rule
847 where all PATTERN dependencies can be build (no matter what
848 happens with nonpattern dependencies).
849 3) If no rule satisfying 1) is found, make will apply the rule
850 remembered in 2) if there is one.
851 */
852 rule_maybe_ok = true;
853
854 /* used to track first percent dependency */
855 less = NULL;
856 nonpattern_less = true;
857
858 /* check whether pattern matches.
859 if it matches, percent string will contain matched percent part of pattern */
860 if (!match_found_with_pattern(true_target, pat_rule, &percent, percent_buf)) {
861 continue;
862 }
863 if (pat_rule->dependencies != NULL) {
864 for (pat_depe = pat_rule->dependencies;
865 pat_depe != NULL;
866 pat_depe = pat_depe->next) {
867 /* checking result for dependency */
868 result = build_dont_know;
869
870 dep_name_found = true;
871 if (pat_depe->name->percent) {
872 is_pattern = true;
873 /* build dependency name */
874 INIT_STRING_FROM_STACK(string, string_buf);
875 construct_string_from_pattern(pat_depe, &percent, &string);
876 depe_to_check = getname_fn(string.buffer.start,
877 FIND_LENGTH,
878 false,
879 &dep_name_found
880 );
881
882 if ((less == NULL) || nonpattern_less) {
883 less = depe_to_check;
884 nonpattern_less = false;
885 }
886 } else {
887 /* nonpattern dependency */
888 is_pattern = false;
889 depe_to_check = pat_depe->name;
890 if(depe_to_check->dollar) {
891 INIT_STRING_FROM_STACK(string, string_buf);
892 expand_value(depe_to_check, &string, false);
893 depe_to_check = getname_fn(string.buffer.start,
894 FIND_LENGTH,
895 false,
896 &dep_name_found
897 );
898 }
899 if (less == NULL) {
900 less = depe_to_check;
901 }
902 }
903
904 if (depe_to_check == empty_name) {
905 result = build_ok;
906 } else {
907 if (debug_level > 1) {
908 (void) printf(gettext("%*sTrying %s\n"),
909 recursion_level,
910 "",
911 depe_to_check->string_mb);
912 }
913
914 pat_rule->being_expanded = true;
915
916 /* suppress message output */
917 int save_debug_level = debug_level;
918 debug_level = 0;
919
920 /* check whether dependency can be built */
921 if (dependency_exists(depe_to_check,
922 get_prop(target->prop,
923 line_prop)))
924 {
925 result = (Doname) depe_to_check->state;
926 } else {
927 if(actual_doname) {
928 result = doname(depe_to_check, true, true);
929 } else {
930 result = target_can_be_built(depe_to_check);
931 }
932 if(!dep_name_found) {
933 if(result != build_ok && result != build_running) {
934 free_name(depe_to_check);
935 } else {
936 store_name(depe_to_check);
937 }
938 }
939 }
940 if(result != build_ok && is_pattern) {
941 rule_maybe_ok = false;
942 }
943
944 /* restore debug_level */
945 debug_level = save_debug_level;
946 }
947
948 if (pat_depe->name->percent) {
949 if (string.free_after_use) {
950 retmem(string.buffer.start);
951 }
952 }
953 /* make can't figure out how to make this dependency */
954 if (result != build_ok && result != build_running) {
955 pat_rule->being_expanded = false;
956 break;
957 }
958 }
959 } else {
960 result = build_ok;
961 }
962
963 /* this pattern rule is the needed one since all dependencies could be built */
964 if (result == build_ok || result == build_running) {
965 break;
966 }
967
968 /* Make does not know how to build some of dependencies from this rule.
969 But if all "pattern" dependencies can be built, we remember this rule
970 as a candidate for the case if no other pattern rule found.
971 */
972 if(rule_maybe_ok && rule_candidate == NULL) {
973 rule_candidate = pat_rule;
974 }
975 }
976
977 /* if no pattern matching rule was found, use the remembered candidate
978 or return build_dont_know if there is no candidate.
979 */
980 if (result != build_ok && result != build_running) {
981 if(rule_candidate) {
982 pat_rule = rule_candidate;
983 } else {
984 return build_dont_know;
985 }
986 }
987
988 /* if we are performing only check whether dependency could be built with existing rules,
989 return success */
990 if (command == NULL) {
991 if(pat_rule != NULL) {
992 pat_rule->being_expanded = false;
993 }
994 return result;
995 }
996
997 if (debug_level > 1) {
998 (void) printf(gettext("%*sMatched %s:"),
999 recursion_level,
1000 "",
1001 target->string_mb);
1002
1003 for (pat_depe = pat_rule->dependencies;
1004 pat_depe != NULL;
1005 pat_depe = pat_depe->next) {
1006 if (pat_depe->name->percent) {
1007 INIT_STRING_FROM_STACK(string, string_buf);
1008 construct_string_from_pattern(pat_depe, &percent, &string);
1009 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1010 } else {
1011 depe_to_check = pat_depe->name;
1012 if(depe_to_check->dollar) {
1013 INIT_STRING_FROM_STACK(string, string_buf);
1014 expand_value(depe_to_check, &string, false);
1015 depe_to_check = GETNAME(string.buffer.start, FIND_LENGTH);
1016 }
1017 }
1018
1019 if (depe_to_check != empty_name) {
1020 (void) printf(" %s", depe_to_check->string_mb);
1021 }
1022 }
1023
1024 (void) printf(gettext(" from: %s:"),
1025 pat_rule->name->string_mb);
1026
1027 for (pat_depe = pat_rule->dependencies;
1028 pat_depe != NULL;
1029 pat_depe = pat_depe->next) {
1030 (void) printf(" %s", pat_depe->name->string_mb);
1031 }
1032
1033 (void) printf("\n");
1034 }
1035
1036 if (true_target->colons == no_colon) {
1037 true_target->colons = one_colon;
1038 }
1039
1040 /* create deppendency list and target group from matched pattern rule */
1041 create_target_group_and_dependencies_list(target, pat_rule, &percent);
1042
1043 /* save command */
1044 line = get_prop(target->prop, line_prop);
1045 *command = line;
1046
1047 /* free query chain if one exist */
1048 while(line->body.line.query != NULL) {
1049 Chain to_free = line->body.line.query;
1050 line->body.line.query = line->body.line.query->next;
1051 retmem_mb((char *) to_free);
1052 }
1053
1054 if (line->body.line.dependencies != NULL) {
1055 /* build all collected dependencies */
1056 for (depe = line->body.line.dependencies;
1057 depe != NULL;
1058 depe = depe->next) {
1059 actual_doname = true;
1060 result = doname_check(depe->name, true, true, depe->automatic);
1061
1062 actual_doname = false;
1063 if (result == build_failed) {
1064 pat_rule->being_expanded = false;
1065 return build_failed;
1066 }
1067 if (result == build_running) {
1068 pat_rule->being_expanded = false;
1069 return build_running;
1070 }
1071
1072 if ((depe->name->stat.time > line->body.line.dependency_time) &&
1073 (debug_level > 1)) {
1074 (void) printf(gettext("%*sDate(%s)=%s Date-dependencies(%s)=%s\n"),
1075 recursion_level,
1076 "",
1077 depe->name->string_mb,
1078 time_to_string(depe->name->stat.time),
1079 true_target->string_mb,
1080 time_to_string(line->body.line.dependency_time));
1081 }
1082
1083 line->body.line.dependency_time =
1084 MAX(line->body.line.dependency_time, depe->name->stat.time);
1085
1086 /* determine whether this dependency made target out of date */
1087 Boolean out_of_date;
1088 if (target->is_member || depe->name->is_member) {
1089 out_of_date = (Boolean) OUT_OF_DATE_SEC(target->stat.time, depe->name->stat.time);
1090 } else {
1091 out_of_date = (Boolean) OUT_OF_DATE(target->stat.time, depe->name->stat.time);
1092 }
1093 if (build_unconditional || out_of_date) {
1094 if(!rechecking) {
1095 line->body.line.is_out_of_date = true;
1096 }
1097 add_target_to_chain(depe->name, &(line->body.line.query));
1098
1099 if (debug_level > 0) {
1100 (void) printf(gettext("%*sBuilding %s using pattern rule %s:"),
1101 recursion_level,
1102 "",
1103 true_target->string_mb,
1104 pat_rule->name->string_mb);
1105
1106 for (pat_depe = pat_rule->dependencies;
1107 pat_depe != NULL;
1108 pat_depe = pat_depe->next) {
1109 (void) printf(" %s", pat_depe->name->string_mb);
1110 }
1111
1112 (void) printf(gettext(" because it is out of date relative to %s\n"),
1113 depe->name->string_mb);
1114 }
1115 }
1116 }
1117 } else {
1118 if ((true_target->stat.time <= file_doesnt_exist) ||
1119 (true_target->stat.time < line->body.line.dependency_time)) {
1120 if(!rechecking) {
1121 line->body.line.is_out_of_date = true;
1122 }
1123 if (debug_level > 0) {
1124 (void) printf(gettext("%*sBuilding %s using pattern rule %s: "),
1125 recursion_level,
1126 "",
1127 true_target->string_mb,
1128 pat_rule->name->string_mb,
1129 (target->stat.time > file_doesnt_exist) ?
1130 gettext("because it is out of date") :
1131 gettext("because it does not exist"));
1132 }
1133 }
1134 }
1135
1136 /* enter explicit rule from percent rule */
1137 Name lmn_target = true_target;
1138 if (true_target->has_long_member_name) {
1139 lmn_target = get_prop(true_target->prop, long_member_name_prop)->body.long_member_name.member_name;
1140 }
1141 line->body.line.sccs_command = false;
1142 line->body.line.target = true_target;
1143 line->body.line.command_template = pat_rule->command_template;
1144 line->body.line.star = GETNAME(percent.buffer.start, FIND_LENGTH);
1145 line->body.line.less = less;
1146
1147 if (lmn_target->parenleft) {
1148 Wstring lmn_string(lmn_target);
1149
1150 wchar_t *left = (wchar_t *) wcschr(lmn_string.get_string(), (int) parenleft_char);
1151 wchar_t *right = (wchar_t *) wcschr(lmn_string.get_string(), (int) parenright_char);
1152
1153 if ((left == NULL) || (right == NULL)) {
1154 line->body.line.percent = NULL;
1155 } else {
1156 line->body.line.percent = GETNAME(left + 1, right - left - 1);
1157 }
1158 } else {
1159 line->body.line.percent = NULL;
1160 }
1161 pat_rule->being_expanded = false;
1162
1163 return result;
1164 }
1165
1166 /*
1167 * match_found_with_pattern
1168 * ( target, pat_rule, percent, percent_buf)
1169 *
1170 * matches "target->string" with a % pattern.
1171 * If pattern contains a MACRO definition, it's expanded first.
1172 *
1173 * Return value:
1174 * true if a match was found
1175 *
1176 * Parameters:
1177 * target The target we're trying to match
1178 * pattern
1179 * percent record that contains "percent_buf" below
1180 * percent_buf This is where the patched % part of pattern is stored
1181 *
1182 */
1183
1184 static Boolean
match_found_with_pattern(Name target,Percent pat_rule,String percent,wchar_t * percent_buf)1185 match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf) {
1186 String_rec string;
1187 wchar_t string_buf[STRING_BUFFER_LENGTH];
1188
1189 /* construct prefix string and check whether prefix matches */
1190 Name prefix = pat_rule->patterns[0];
1191 int prefix_length;
1192
1193 Wstring targ_string(target);
1194 Wstring pref_string(prefix);
1195 Wstring suf_string;
1196
1197 if (prefix->dollar) {
1198 INIT_STRING_FROM_STACK(string, string_buf);
1199 expand_value(prefix, &string, false);
1200 prefix_length = string.text.p - string.buffer.start;
1201 if ((string.buffer.start[0] == (int) period_char) &&
1202 (string.buffer.start[1] == (int) slash_char)) {
1203 string.buffer.start += 2;
1204 prefix_length -= 2;
1205 }
1206 if (!targ_string.equaln(string.buffer.start, prefix_length)) {
1207 return false;
1208 }
1209 } else {
1210 prefix_length = prefix->hash.length;
1211 if (!targ_string.equaln(&pref_string, prefix_length)) {
1212 return false;
1213 }
1214 }
1215
1216 /* do the same with pattern suffix */
1217 Name suffix = pat_rule->patterns[pat_rule->patterns_total - 1];
1218 suf_string.init(suffix);
1219
1220 int suffix_length;
1221 if (suffix->dollar) {
1222 INIT_STRING_FROM_STACK(string, string_buf);
1223 expand_value(suffix, &string, false);
1224 suffix_length = string.text.p - string.buffer.start;
1225 if(suffix_length > target->hash.length) {
1226 return false;
1227 }
1228 if (!targ_string.equal(string.buffer.start, target->hash.length - suffix_length)) {
1229 return false;
1230 }
1231 } else {
1232 suffix_length = (int) suffix->hash.length;
1233 if(suffix_length > target->hash.length) {
1234 return false;
1235 }
1236 if (!targ_string.equal(&suf_string, target->hash.length - suffix_length)) {
1237 return false;
1238 }
1239 }
1240
1241 Boolean match_found = false;
1242 int percent_length = target->hash.length - prefix_length - suffix_length;
1243
1244 while (!match_found && (percent_length >= 0)) {
1245 /* init result string */
1246 INIT_STRING_FROM_STACK(string, string_buf);
1247
1248 /* init percent string */
1249 percent->buffer.start = percent_buf;
1250 percent->text.p = percent_buf;
1251 percent->text.end = NULL;
1252 percent->free_after_use = false;
1253 percent->buffer.end = percent_buf + STRING_BUFFER_LENGTH;
1254
1255 /* construct percent and result strings */
1256 targ_string.append_to_str(percent, prefix_length, percent_length);
1257 construct_string_from_pattern(pat_rule, percent, &string);
1258
1259 /* check for match */
1260 if (targ_string.equal(string.buffer.start, 0)) {
1261 match_found = true;
1262 } else {
1263 percent_length--;
1264 }
1265 }
1266
1267 /* result */
1268 return match_found;
1269 }
1270
1271
1272 /*
1273 * create_target_group_and_dependencies_list
1274 * (target, pat_rule, percent)
1275 *
1276 * constructs dependency list and a target group from pattern.
1277 *
1278 * If we have the lines
1279 * %/%.a + %/%.b + C%/CC%.c: yyy %.d bb%/BB%.e
1280 * commands
1281 *
1282 * and we have matched the pattern xx/xx.a with %/%.a, then we
1283 * construct a target group that looks like this:
1284 * xx/xx.a + xx/xx.b + Cxx/CCxx.c: dependencies
1285 *
1286 * and construct dependency list that looks like this:
1287 * yyy xx.d bbxx/BBxx.e + already existed dependencies
1288 *
1289 * Return value:
1290 * none
1291 *
1292 * Parameters:
1293 * target The target we are building, in the previous
1294 * example, this is xx/xx.a
1295 * pat_rule the % pattern that matched "target", here %/%.a
1296 * percent string containing matched % part. In the example=xx.
1297 *
1298 * Global variables used:
1299 * empty_name
1300 */
1301
1302 static void
create_target_group_and_dependencies_list(Name target,Percent pat_rule,String percent)1303 create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent) {
1304 String_rec string;
1305 wchar_t string_buf[STRING_BUFFER_LENGTH];
1306 Percent pat_depe;
1307 Name depe;
1308 Property line = maybe_append_prop(target, line_prop);
1309 Chain new_target_group = NULL;
1310 Chain *new_target_group_tail = &new_target_group;
1311 Chain group_member;
1312
1313 /* create and append dependencies from rule */
1314 for (pat_depe = pat_rule->dependencies; pat_depe != NULL; pat_depe = pat_depe->next) {
1315 if (pat_depe->name->percent) {
1316 INIT_STRING_FROM_STACK(string, string_buf);
1317 construct_string_from_pattern(pat_depe, percent, &string);
1318 depe = GETNAME(string.buffer.start, FIND_LENGTH);
1319 if (depe != empty_name) {
1320 enter_dependency(line, depe, false);
1321 }
1322 } else {
1323 depe = pat_depe->name;
1324 if(depe->dollar) {
1325 INIT_STRING_FROM_STACK(string, string_buf);
1326 expand_value(depe, &string, false);
1327 depe = GETNAME(string.buffer.start, FIND_LENGTH);
1328 }
1329 enter_dependency(line, depe, false);
1330 }
1331 }
1332
1333 /* if matched pattern is a group member, create new target group */
1334 for (group_member = pat_rule->target_group; group_member != NULL; group_member = group_member->next) {
1335 Name new_target = group_member->name;
1336 if (group_member->name->percent) {
1337 INIT_STRING_FROM_STACK(string, string_buf);
1338 construct_string_from_pattern(group_member->percent_member, percent, &string);
1339 new_target = GETNAME(string.buffer.start, FIND_LENGTH);
1340 if (new_target == empty_name) {
1341 continue;
1342 }
1343 }
1344
1345 /* check for duplicates */
1346 Chain tgm;
1347 for (tgm = new_target_group; tgm != NULL; tgm = tgm->next) {
1348 if (new_target == tgm->name) {
1349 break;
1350 }
1351 }
1352 if (tgm != NULL) {
1353 continue;
1354 }
1355
1356 /* insert it into the targets list */
1357 (*new_target_group_tail) = ALLOC(Chain);
1358 (*new_target_group_tail)->name = new_target;
1359 (*new_target_group_tail)->next = NULL;
1360 new_target_group_tail = &(*new_target_group_tail)->next;
1361 }
1362
1363 /* now we gathered all dependencies and created target group */
1364 line->body.line.target_group = new_target_group;
1365
1366 /* update properties for group members */
1367 for (group_member = new_target_group; group_member != NULL; group_member = group_member->next) {
1368 if (group_member->name != target) {
1369 group_member->name->prop = target->prop;
1370 group_member->name->conditional_cnt = target->conditional_cnt;
1371 }
1372 }
1373 }
1374
1375 /*
1376 * construct_string_from_pattern
1377 * (pat_rule, percent, result)
1378 *
1379 * after pattern matched a target this routine is called to construct targets and dependencies
1380 * strings from this matched pattern rule and a string (percent) with substitutes % sign in pattern.
1381 *
1382 * Return value:
1383 * none
1384 *
1385 * Parameters:
1386 * pat_rule matched pattern rule
1387 * percent string containing matched % sign part.
1388 * result holds the result of string construction.
1389 *
1390 */
1391 static void
construct_string_from_pattern(Percent pat_rule,String percent,String result)1392 construct_string_from_pattern(Percent pat_rule, String percent, String result) {
1393 for (int i = 0; i < pat_rule->patterns_total; i++) {
1394 if (pat_rule->patterns[i]->dollar) {
1395 expand_value(pat_rule->patterns[i],
1396 result,
1397 false);
1398
1399 } else {
1400 append_string(pat_rule->patterns[i]->string_mb,
1401 result,
1402 pat_rule->patterns[i]->hash.length);
1403 }
1404
1405 if (i < pat_rule->patterns_total - 1) {
1406 append_string(percent->buffer.start,
1407 result,
1408 percent->text.p - percent->buffer.start);
1409 }
1410 }
1411
1412 if ((result->buffer.start[0] == (int) period_char) &&
1413 (result->buffer.start[1] == (int) slash_char)) {
1414 result->buffer.start += 2;
1415 }
1416 }
1417
1418 /*
1419 * dependency_exists(target, line)
1420 *
1421 * Returns true if the target exists in the
1422 * dependency list of the line.
1423 *
1424 * Return value:
1425 * True if target is on dependency list
1426 *
1427 * Parameters:
1428 * target Target we scan for
1429 * line We get the dependency list from here
1430 *
1431 * Global variables used:
1432 */
1433 static Boolean
dependency_exists(Name target,Property line)1434 dependency_exists(Name target, Property line)
1435 {
1436 Dependency dp;
1437
1438 if (line == NULL) {
1439 return false;
1440 }
1441 for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
1442 if (dp->name == target) {
1443 return true;
1444 }
1445 }
1446 return false;
1447 }
1448
1449 void
add_target_to_chain(Name target,Chain * query)1450 add_target_to_chain(Name target, Chain * query)
1451 {
1452 if (target->is_member && (get_prop(target->prop, member_prop) != NULL)) {
1453 target = get_prop(target->prop, member_prop)->body.member.member;
1454 }
1455 Chain *query_tail;
1456 for (query_tail = query; *query_tail != NULL; query_tail = &(*query_tail)->next) {
1457 if ((*query_tail)->name == target) {
1458 return;
1459 }
1460 }
1461 *query_tail = ALLOC(Chain);
1462 (*query_tail)->name = target;
1463 (*query_tail)->next = NULL;
1464 }
1465
1466