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 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 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 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 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 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 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 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 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 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 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