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 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); 59 extern void build_suffix_list(register Name target_suffix); 60 extern Doname find_percent_rule(register Name target, Property *command, Boolean rechecking); 61 static void create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent); 62 static Boolean match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf); 63 static void construct_string_from_pattern(Percent pat_rule, String percent, String result); 64 static Boolean dependency_exists(Name target, Property line); 65 extern Property maybe_append_prop(Name, Property_id); 66 extern void add_target_to_chain(Name target, Chain * query); 67 68 /* 69 * find_suffix_rule(target, target_body, target_suffix, command, rechecking) 70 * 71 * Does the lookup for single and double suffix rules. 72 * It calls build_suffix_list() to build the list of possible suffixes 73 * for the given target. 74 * It then scans the list to find the first possible source file that 75 * exists. This is done by concatenating the body of the target name 76 * (target name less target suffix) and the source suffix and checking 77 * if the resulting file exists. 78 * 79 * Return value: 80 * Indicates if search failed or not 81 * 82 * Parameters: 83 * target The target we need a rule for 84 * target_body The target name without the suffix 85 * target_suffix The suffix of the target 86 * command Pointer to slot to deposit cmd in if found 87 * rechecking true if we are rechecking target which depends 88 * on conditional macro and keep_state is set 89 * 90 * Global variables used: 91 * debug_level Indicates how much tracing to do 92 * recursion_level Used for tracing 93 */ 94 95 extern int printf (const char *, ...); 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 register wchar_t *put_suffix; 117 register Property source_suffix; 118 register Name source; 119 Doname result; 120 register 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 case build_running: 328 if(!name_found) { 329 store_name(source); 330 } 331 true_target->suffix_scan_done = false; 332 line = maybe_append_prop(target, line_prop); 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) && 461 ((*command)->body.line.star == NULL)) { 462 (*command)->body.line.star = target_body; 463 } 464 } 465 if (sourcename != static_string_buf_3M) { 466 retmem(sourcename); 467 } 468 /* Return here in case no rule matched the target */ 469 return build_dont_know; 470 } 471 472 /* 473 * find_ar_suffix_rule(target, true_target, command, rechecking) 474 * 475 * Scans the .SUFFIXES list and tries 476 * to find a suffix on it that matches the tail of the target member name. 477 * If it finds a matching suffix it calls find_suffix_rule() to find 478 * a rule for the target using the suffix ".a". 479 * 480 * Return value: 481 * Indicates if search failed or not 482 * 483 * Parameters: 484 * target The target we need a rule for 485 * true_target The proper name 486 * command Pointer to slot where we stuff cmd, if found 487 * rechecking true if we are rechecking target which depends 488 * on conditional macro and keep_state is set 489 * 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. 541 */ 542 target->suffix_scan_done = false; 543 body = GETNAME(targ_string.get_string(), 544 (int)(true_target->hash.length - 545 suffix_length)); 546 we_are_in_tilde = false; 547 switch (find_suffix_rule(target, 548 body, 549 dot_a, 550 command, 551 rechecking)) { 552 case build_ok: 553 line = get_prop(target->prop, line_prop); 554 line->body.line.star = body; 555 return build_ok; 556 case build_running: 557 return build_running; 558 } 559 /* 560 * If no rule was found, we try the next suffix to see 561 * if it matches the target tail, and so on. 562 * Go here if the suffix did not match the target tail. 563 */ 564 not_this_one:; 565 } 566 return build_dont_know; 567 } 568 569 /* 570 * find_double_suffix_rule(target, command, rechecking) 571 * 572 * Scans the .SUFFIXES list and tries 573 * to find a suffix on it that matches the tail of the target name. 574 * If it finds a matching suffix it calls find_suffix_rule() to find 575 * a rule for the target. 576 * 577 * Return value: 578 * Indicates if scan failed or not 579 * 580 * Parameters: 581 * target Target we need a rule for 582 * command Pointer to slot where we stuff cmd, if found 583 * rechecking true if we are rechecking target which depends 584 * on conditional macro and keep_state is set 585 * 586 * Global variables used: 587 * debug_level Indicates how much tracing to do 588 * recursion_level Used for tracing 589 * suffixes List of suffixes used for scan (from .SUFFIXES) 590 */ 591 Doname 592 find_double_suffix_rule(register Name target, Property *command, Boolean rechecking) 593 { 594 Name true_target = target; 595 Name target_body; 596 register wchar_t *target_end; 597 register Dependency suffix; 598 register int suffix_length; 599 Boolean scanned_once = false; 600 Boolean name_found = true; 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)) { 642 goto not_this_one; 643 } 644 /* 645 * The target tail matched a suffix from the .SUFFIXES list. 646 * Now check for a rule to match. 647 */ 648 we_are_in_tilde = false; 649 target_body = GETNAME( 650 targ_string.get_string(), 651 (int)(true_target->hash.length - suffix_length) 652 ); 653 switch (find_suffix_rule(target, 654 target_body, 655 suffix->name, 656 command, 657 rechecking)) { 658 case build_ok: 659 return build_ok; 660 case build_running: 661 return build_running; 662 } 663 if (true_target->suffix_scan_done == true) { 664 scanned_once = true; 665 } 666 /* 667 * If no rule was found, we try the next suffix to see 668 * if it matches the target tail. And so on. 669 * Go here if the suffix did not match the target tail. 670 */ 671 not_this_one:; 672 } 673 if (scanned_once) 674 true_target->suffix_scan_done = true; 675 return build_dont_know; 676 } 677 678 /* 679 * build_suffix_list(target_suffix) 680 * 681 * Scans the .SUFFIXES list and figures out 682 * which suffixes this target can be derived from. 683 * The target itself is not know here, we just know the suffix of the 684 * target. For each suffix on the list the target can be derived iff 685 * a rule exists for the name "<suffix-on-list><target-suffix>". 686 * A list of all possible building suffixes is built, with the rule for 687 * each, and tacked to the target suffix nameblock. 688 * 689 * Parameters: 690 * target_suffix The suffix we build a match list for 691 * 692 * Global variables used: 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); 734 /* 735 * Check if that name has a rule. If not, it cannot match 736 * any implicit rule scan and is ignored. 737 * The GETNAME() call only checks for presence, it will not 738 * enter the name if it is not defined. 739 */ 740 if (((rule = getname_fn(rule_name, 741 (int) (source_suffix->name-> 742 hash.length + 743 target_suffix->hash.length), 744 true)) != NULL) && 745 ((line = get_prop(rule->prop, line_prop)) != NULL)) { 746 if (debug_level > 1) { 747 (void) printf("%s ", rule->string_mb); 748 } 749 /* 750 * This makes it possible to quickly determine if 751 * it will pay to look for a suffix property. 752 */ 753 target_suffix->has_suffixes = true; 754 /* 755 * Add the suffix property to the target suffix 756 * and save the rule with it. 757 * All information the implicit rule scanner need 758 * is saved in the suffix property. 759 */ 760 suffix = append_prop(target_suffix, suffix_prop); 761 suffix->body.suffix.suffix = source_suffix->name; 762 suffix->body.suffix.command_template = 763 line->body.line.command_template; 764 } 765 } 766 if (debug_level > 1) { 767 (void) printf("\n"); 768 } 769 } 770 771 /* 772 * find_percent_rule(target, command, rechecking) 773 * 774 * Tries to find a rule from the list of wildcard matched rules. 775 * It scans the list attempting to match the target. 776 * For each target match it checks if the corresponding source exists. 777 * If it does the match is returned. 778 * The percent_list is built at makefile read time. 779 * Each percent rule get one entry on the list. 780 * 781 * Return value: 782 * Indicates if the scan failed or not 783 * 784 * Parameters: 785 * target The target we need a rule for 786 * command Pointer to slot where we stuff cmd, if found 787 * rechecking true if we are rechecking target which depends 788 * on conditional macro and keep_state is set 789 * 790 * Global variables used: 791 * debug_level Indicates how much tracing to do 792 * percent_list List of all percent rules 793 * recursion_level Used for tracing 794 * empty_name 795 */ 796 Doname 797 find_percent_rule(register Name target, Property *command, Boolean rechecking) 798 { 799 register Percent pat_rule, pat_depe; 800 register Name depe_to_check; 801 register Dependency depe; 802 register Property line; 803 String_rec string; 804 wchar_t string_buf[STRING_BUFFER_LENGTH]; 805 String_rec percent; 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 847 happens with nonpattern dependencies). 848 3) If no rule satisfying 1) is found, make will apply the rule 849 remembered in 2) if there is one. 850 */ 851 rule_maybe_ok = true; 852 853 /* used to track first percent dependency */ 854 less = NULL; 855 nonpattern_less = true; 856 857 /* check whether pattern matches. 858 if it matches, percent string will contain matched percent part of pattern */ 859 if (!match_found_with_pattern(true_target, pat_rule, &percent, percent_buf)) { 860 continue; 861 } 862 if (pat_rule->dependencies != NULL) { 863 for (pat_depe = pat_rule->dependencies; 864 pat_depe != NULL; 865 pat_depe = pat_depe->next) { 866 /* checking result for dependency */ 867 result = build_dont_know; 868 869 dep_name_found = true; 870 if (pat_depe->name->percent) { 871 is_pattern = true; 872 /* build dependency name */ 873 INIT_STRING_FROM_STACK(string, string_buf); 874 construct_string_from_pattern(pat_depe, &percent, &string); 875 depe_to_check = getname_fn(string.buffer.start, 876 FIND_LENGTH, 877 false, 878 &dep_name_found 879 ); 880 881 if ((less == NULL) || nonpattern_less) { 882 less = depe_to_check; 883 nonpattern_less = false; 884 } 885 } else { 886 /* nonpattern dependency */ 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); 928 } else { 929 result = target_can_be_built(depe_to_check); 930 } 931 if(!dep_name_found) { 932 if(result != build_ok && result != build_running) { 933 free_name(depe_to_check); 934 } else { 935 store_name(depe_to_check); 936 } 937 } 938 } 939 if(result != build_ok && is_pattern) { 940 rule_maybe_ok = false; 941 } 942 943 /* restore debug_level */ 944 debug_level = save_debug_level; 945 } 946 947 if (pat_depe->name->percent) { 948 if (string.free_after_use) { 949 retmem(string.buffer.start); 950 } 951 } 952 /* make can't figure out how to make this dependency */ 953 if (result != build_ok && result != build_running) { 954 pat_rule->being_expanded = false; 955 break; 956 } 957 } 958 } else { 959 result = build_ok; 960 } 961 962 /* this pattern rule is the needed one since all dependencies could be built */ 963 if (result == build_ok || result == build_running) { 964 break; 965 } 966 967 /* Make does not know how to build some of dependencies from this rule. 968 But if all "pattern" dependencies can be built, we remember this rule 969 as a candidate for the case if no other pattern rule found. 970 */ 971 if(rule_maybe_ok && rule_candidate == NULL) { 972 rule_candidate = pat_rule; 973 } 974 } 975 976 /* if no pattern matching rule was found, use the remembered candidate 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); 1044 *command = line; 1045 1046 /* free query chain if one exist */ 1047 while(line->body.line.query != NULL) { 1048 Chain to_free = line->body.line.query; 1049 line->body.line.query = line->body.line.query->next; 1050 retmem_mb((char *) to_free); 1051 } 1052 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 *) wcschr(lmn_string.get_string(), (int) parenleft_char); 1150 wchar_t *right = (wchar_t *) wcschr(lmn_string.get_string(), (int) parenright_char); 1151 1152 if ((left == NULL) || (right == NULL)) { 1153 line->body.line.percent = NULL; 1154 } else { 1155 line->body.line.percent = GETNAME(left + 1, right - left - 1); 1156 } 1157 } else { 1158 line->body.line.percent = NULL; 1159 } 1160 pat_rule->being_expanded = false; 1161 1162 return result; 1163 } 1164 1165 /* 1166 * match_found_with_pattern 1167 * ( target, pat_rule, percent, percent_buf) 1168 * 1169 * matches "target->string" with a % pattern. 1170 * If pattern contains a MACRO definition, it's expanded first. 1171 * 1172 * Return value: 1173 * true if a match was found 1174 * 1175 * Parameters: 1176 * target The target we're trying to match 1177 * pattern 1178 * percent record that contains "percent_buf" below 1179 * percent_buf This is where the patched % part of pattern is stored 1180 * 1181 */ 1182 1183 static Boolean 1184 match_found_with_pattern(Name target, Percent pat_rule, String percent, wchar_t *percent_buf) { 1185 String_rec string; 1186 wchar_t string_buf[STRING_BUFFER_LENGTH]; 1187 1188 /* construct prefix string and check whether prefix matches */ 1189 Name prefix = pat_rule->patterns[0]; 1190 int prefix_length; 1191 1192 Wstring targ_string(target); 1193 Wstring pref_string(prefix); 1194 Wstring suf_string; 1195 1196 if (prefix->dollar) { 1197 INIT_STRING_FROM_STACK(string, string_buf); 1198 expand_value(prefix, &string, false); 1199 prefix_length = string.text.p - string.buffer.start; 1200 if ((string.buffer.start[0] == (int) period_char) && 1201 (string.buffer.start[1] == (int) slash_char)) { 1202 string.buffer.start += 2; 1203 prefix_length -= 2; 1204 } 1205 if (!targ_string.equaln(string.buffer.start, prefix_length)) { 1206 return false; 1207 } 1208 } else { 1209 prefix_length = prefix->hash.length; 1210 if (!targ_string.equaln(&pref_string, prefix_length)) { 1211 return false; 1212 } 1213 } 1214 1215 /* do the same with pattern suffix */ 1216 Name suffix = pat_rule->patterns[pat_rule->patterns_total - 1]; 1217 suf_string.init(suffix); 1218 1219 int suffix_length; 1220 if (suffix->dollar) { 1221 INIT_STRING_FROM_STACK(string, string_buf); 1222 expand_value(suffix, &string, false); 1223 suffix_length = string.text.p - string.buffer.start; 1224 if(suffix_length > target->hash.length) { 1225 return false; 1226 } 1227 if (!targ_string.equal(string.buffer.start, target->hash.length - suffix_length)) { 1228 return false; 1229 } 1230 } else { 1231 suffix_length = (int) suffix->hash.length; 1232 if(suffix_length > target->hash.length) { 1233 return false; 1234 } 1235 if (!targ_string.equal(&suf_string, target->hash.length - suffix_length)) { 1236 return false; 1237 } 1238 } 1239 1240 Boolean match_found = false; 1241 int percent_length = target->hash.length - prefix_length - suffix_length; 1242 1243 while (!match_found && (percent_length >= 0)) { 1244 /* init result string */ 1245 INIT_STRING_FROM_STACK(string, string_buf); 1246 1247 /* init percent string */ 1248 percent->buffer.start = percent_buf; 1249 percent->text.p = percent_buf; 1250 percent->text.end = NULL; 1251 percent->free_after_use = false; 1252 percent->buffer.end = percent_buf + STRING_BUFFER_LENGTH; 1253 1254 /* construct percent and result strings */ 1255 targ_string.append_to_str(percent, prefix_length, percent_length); 1256 construct_string_from_pattern(pat_rule, percent, &string); 1257 1258 /* check for match */ 1259 if (targ_string.equal(string.buffer.start, 0)) { 1260 match_found = true; 1261 } else { 1262 percent_length--; 1263 } 1264 } 1265 1266 /* result */ 1267 return match_found; 1268 } 1269 1270 1271 /* 1272 * create_target_group_and_dependencies_list 1273 * (target, pat_rule, percent) 1274 * 1275 * constructs dependency list and a target group from pattern. 1276 * 1277 * If we have the lines 1278 * %/%.a + %/%.b + C%/CC%.c: yyy %.d bb%/BB%.e 1279 * commands 1280 * 1281 * and we have matched the pattern xx/xx.a with %/%.a, then we 1282 * construct a target group that looks like this: 1283 * xx/xx.a + xx/xx.b + Cxx/CCxx.c: dependencies 1284 * 1285 * and construct dependency list that looks like this: 1286 * yyy xx.d bbxx/BBxx.e + already existed dependencies 1287 * 1288 * Return value: 1289 * none 1290 * 1291 * Parameters: 1292 * target The target we are building, in the previous 1293 * example, this is xx/xx.a 1294 * pat_rule the % pattern that matched "target", here %/%.a 1295 * percent string containing matched % part. In the example=xx. 1296 * 1297 * Global variables used: 1298 * empty_name 1299 */ 1300 1301 static void 1302 create_target_group_and_dependencies_list(Name target, Percent pat_rule, String percent) { 1303 String_rec string; 1304 wchar_t string_buf[STRING_BUFFER_LENGTH]; 1305 Percent pat_depe; 1306 Name depe; 1307 Property line = maybe_append_prop(target, line_prop); 1308 Chain new_target_group = NULL; 1309 Chain *new_target_group_tail = &new_target_group; 1310 Chain group_member; 1311 1312 /* create and append dependencies from rule */ 1313 for (pat_depe = pat_rule->dependencies; pat_depe != NULL; pat_depe = pat_depe->next) { 1314 if (pat_depe->name->percent) { 1315 INIT_STRING_FROM_STACK(string, string_buf); 1316 construct_string_from_pattern(pat_depe, percent, &string); 1317 depe = GETNAME(string.buffer.start, FIND_LENGTH); 1318 if (depe != empty_name) { 1319 enter_dependency(line, depe, false); 1320 } 1321 } else { 1322 depe = pat_depe->name; 1323 if(depe->dollar) { 1324 INIT_STRING_FROM_STACK(string, string_buf); 1325 expand_value(depe, &string, false); 1326 depe = GETNAME(string.buffer.start, FIND_LENGTH); 1327 } 1328 enter_dependency(line, depe, false); 1329 } 1330 } 1331 1332 /* if matched pattern is a group member, create new target group */ 1333 for (group_member = pat_rule->target_group; group_member != NULL; group_member = group_member->next) { 1334 Name new_target = group_member->name; 1335 if (group_member->name->percent) { 1336 INIT_STRING_FROM_STACK(string, string_buf); 1337 construct_string_from_pattern(group_member->percent_member, percent, &string); 1338 new_target = GETNAME(string.buffer.start, FIND_LENGTH); 1339 if (new_target == empty_name) { 1340 continue; 1341 } 1342 } 1343 1344 /* check for duplicates */ 1345 Chain tgm; 1346 for (tgm = new_target_group; tgm != NULL; tgm = tgm->next) { 1347 if (new_target == tgm->name) { 1348 break; 1349 } 1350 } 1351 if (tgm != NULL) { 1352 continue; 1353 } 1354 1355 /* insert it into the targets list */ 1356 (*new_target_group_tail) = ALLOC(Chain); 1357 (*new_target_group_tail)->name = new_target; 1358 (*new_target_group_tail)->next = NULL; 1359 new_target_group_tail = &(*new_target_group_tail)->next; 1360 } 1361 1362 /* now we gathered all dependencies and created target group */ 1363 line->body.line.target_group = new_target_group; 1364 1365 /* update properties for group members */ 1366 for (group_member = new_target_group; group_member != NULL; group_member = group_member->next) { 1367 if (group_member->name != target) { 1368 group_member->name->prop = target->prop; 1369 group_member->name->conditional_cnt = target->conditional_cnt; 1370 } 1371 } 1372 } 1373 1374 /* 1375 * construct_string_from_pattern 1376 * (pat_rule, percent, result) 1377 * 1378 * after pattern matched a target this routine is called to construct targets and dependencies 1379 * strings from this matched pattern rule and a string (percent) with substitutes % sign in pattern. 1380 * 1381 * Return value: 1382 * none 1383 * 1384 * Parameters: 1385 * pat_rule matched pattern rule 1386 * percent string containing matched % sign part. 1387 * result holds the result of string construction. 1388 * 1389 */ 1390 static void 1391 construct_string_from_pattern(Percent pat_rule, String percent, String result) { 1392 for (int i = 0; i < pat_rule->patterns_total; i++) { 1393 if (pat_rule->patterns[i]->dollar) { 1394 expand_value(pat_rule->patterns[i], 1395 result, 1396 false); 1397 1398 } else { 1399 append_string(pat_rule->patterns[i]->string_mb, 1400 result, 1401 pat_rule->patterns[i]->hash.length); 1402 } 1403 1404 if (i < pat_rule->patterns_total - 1) { 1405 append_string(percent->buffer.start, 1406 result, 1407 percent->text.p - percent->buffer.start); 1408 } 1409 } 1410 1411 if ((result->buffer.start[0] == (int) period_char) && 1412 (result->buffer.start[1] == (int) slash_char)) { 1413 result->buffer.start += 2; 1414 } 1415 } 1416 1417 /* 1418 * dependency_exists(target, line) 1419 * 1420 * Returns true if the target exists in the 1421 * dependency list of the line. 1422 * 1423 * Return value: 1424 * True if target is on dependency list 1425 * 1426 * Parameters: 1427 * target Target we scan for 1428 * line We get the dependency list from here 1429 * 1430 * Global variables used: 1431 */ 1432 static Boolean 1433 dependency_exists(Name target, Property line) 1434 { 1435 Dependency dp; 1436 1437 if (line == NULL) { 1438 return false; 1439 } 1440 for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) { 1441 if (dp->name == target) { 1442 return true; 1443 } 1444 } 1445 return false; 1446 } 1447 1448 void 1449 add_target_to_chain(Name target, Chain * query) 1450 { 1451 if (target->is_member && (get_prop(target->prop, member_prop) != NULL)) { 1452 target = get_prop(target->prop, member_prop)->body.member.member; 1453 } 1454 Chain *query_tail; 1455 for (query_tail = query; *query_tail != NULL; query_tail = &(*query_tail)->next) { 1456 if ((*query_tail)->name == target) { 1457 return; 1458 } 1459 } 1460 *query_tail = ALLOC(Chain); 1461 (*query_tail)->name = target; 1462 (*query_tail)->next = NULL; 1463 } 1464