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