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