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