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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * doname.c 28 * 29 * Figure out which targets are out of date and rebuild them 30 */ 31 32 /* 33 * Included files 34 */ 35 #include <alloca.h> /* alloca() */ 36 37 38 #include <fcntl.h> 39 #include <mk/defs.h> 40 #include <mksh/i18n.h> /* get_char_semantics_value() */ 41 #include <mksh/macro.h> /* getvar(), expand_value() */ 42 #include <mksh/misc.h> /* getmem() */ 43 #include <poll.h> 44 45 46 #include <signal.h> 47 48 # include <stropts.h> 49 50 #include <sys/errno.h> 51 #include <sys/stat.h> 52 #include <sys/types.h> 53 #include <sys/utsname.h> /* uname() */ 54 #include <sys/wait.h> 55 #include <unistd.h> /* close() */ 56 57 /* 58 * Defined macros 59 */ 60 # define LOCALHOST "localhost" 61 62 #define MAXRULES 100 63 64 #define SEND_MTOOL_MSG(cmds) 65 66 // Sleep for .1 seconds between stat()'s 67 const int STAT_RETRY_SLEEP_TIME = 100000; 68 69 /* 70 * typedefs & structs 71 */ 72 73 /* 74 * Static variables 75 */ 76 static char hostName[MAXNAMELEN] = ""; 77 static char userName[MAXNAMELEN] = ""; 78 79 80 static int second_pass = 0; 81 82 /* 83 * File table of contents 84 */ 85 extern Doname doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic); 86 extern Doname doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic); 87 static Boolean check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals); 88 void dynamic_dependencies(Name target); 89 static Doname run_command(register Property line, Boolean print_machine); 90 extern Doname execute_serial(Property line); 91 extern Name vpath_translation(register Name cmd); 92 extern void check_state(Name temp_file_name); 93 static void read_dependency_file(register Name filename); 94 static void check_read_state_file(void); 95 static void do_assign(register Name line, register Name target); 96 static void build_command_strings(Name target, register Property line); 97 static Doname touch_command(register Property line, register Name target, Doname result); 98 extern void update_target(Property line, Doname result); 99 static Doname sccs_get(register Name target, register Property *command); 100 extern void read_directory_of_file(register Name file); 101 static void add_pattern_conditionals(register Name target); 102 extern void set_locals(register Name target, register Property old_locals); 103 extern void reset_locals(register Name target, register Property old_locals, register Property conditional, register int index); 104 extern Boolean check_auto_dependencies(Name target, int auto_count, Name *automatics); 105 static void delete_query_chain(Chain ch); 106 107 // From read2.cc 108 extern Name normalize_name(register wchar_t *name_string, register int length); 109 110 111 112 /* 113 * DONE. 114 * 115 * doname_check(target, do_get, implicit, automatic) 116 * 117 * Will call doname() and then inspect the return value 118 * 119 * Return value: 120 * Indication if the build failed or not 121 * 122 * Parameters: 123 * target The target to build 124 * do_get Passed thru to doname() 125 * implicit Passed thru to doname() 126 * automatic Are we building a hidden dependency? 127 * 128 * Global variables used: 129 * build_failed_seen Set if -k is on and error occurs 130 * continue_after_error Indicates that -k is on 131 * report_dependencies No error msg if -P is on 132 */ 133 Doname 134 doname_check(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic) 135 { 136 int first_time = 1; 137 (void) fflush(stdout); 138 try_again: 139 switch (doname(target, do_get, implicit, automatic)) { 140 case build_ok: 141 second_pass = 0; 142 return build_ok; 143 case build_running: 144 second_pass = 0; 145 return build_running; 146 case build_failed: 147 if (!continue_after_error) { 148 fatal(catgets(catd, 1, 13, "Target `%s' not remade because of errors"), 149 target->string_mb); 150 } 151 build_failed_seen = true; 152 second_pass = 0; 153 return build_failed; 154 case build_dont_know: 155 /* 156 * If we can't figure out how to build an automatic 157 * (hidden) dependency, we just ignore it. 158 * We later declare the target to be out of date just in 159 * case something changed. 160 * Also, don't complain if just reporting the dependencies 161 * and not building anything. 162 */ 163 if (automatic || (report_dependencies_level > 0)) { 164 second_pass = 0; 165 return build_dont_know; 166 } 167 if(first_time) { 168 first_time = 0; 169 second_pass = 1; 170 goto try_again; 171 } 172 second_pass = 0; 173 if (continue_after_error && !svr4) { 174 warning(catgets(catd, 1, 14, "Don't know how to make target `%s'"), 175 target->string_mb); 176 build_failed_seen = true; 177 return build_failed; 178 } 179 fatal(catgets(catd, 1, 15, "Don't know how to make target `%s'"), target->string_mb); 180 break; 181 } 182 #ifdef lint 183 return build_failed; 184 #endif 185 } 186 187 188 void 189 enter_explicit_rule_from_dynamic_rule(Name target, Name source) 190 { 191 Property line, source_line; 192 Dependency dependency; 193 194 source_line = get_prop(source->prop, line_prop); 195 line = maybe_append_prop(target, line_prop); 196 line->body.line.sccs_command = false; 197 line->body.line.target = target; 198 if (line->body.line.command_template == NULL) { 199 line->body.line.command_template = source_line->body.line.command_template; 200 for (dependency = source_line->body.line.dependencies; 201 dependency != NULL; 202 dependency = dependency->next) { 203 enter_dependency(line, dependency->name, false); 204 } 205 line->body.line.less = target; 206 } 207 line->body.line.percent = NULL; 208 } 209 210 211 212 Name 213 find_dyntarget(Name target) 214 { 215 Dyntarget p; 216 int i; 217 String_rec string; 218 wchar_t buffer[STRING_BUFFER_LENGTH]; 219 wchar_t *pp, * bufend; 220 wchar_t tbuffer[MAXPATHLEN]; 221 Wstring wcb(target); 222 223 for (p = dyntarget_list; p != NULL; p = p->next) { 224 INIT_STRING_FROM_STACK(string, buffer); 225 expand_value(p->name, &string, false); 226 i = 0; 227 pp = string.buffer.start; 228 bufend = pp + STRING_BUFFER_LENGTH; 229 while((*pp != nul_char) && (pp < bufend)) { 230 if(iswspace(*pp)) { 231 tbuffer[i] = nul_char; 232 if(i > 0) { 233 if (wcb.equal(tbuffer)) { 234 enter_explicit_rule_from_dynamic_rule(target, p->name); 235 return(target); 236 } 237 } 238 pp++; 239 i = 0; 240 continue; 241 } 242 tbuffer[i] = *pp; 243 i++; 244 pp++; 245 if(*pp == nul_char) { 246 tbuffer[i] = nul_char; 247 if(i > 0) { 248 if (wcb.equal(tbuffer)) { 249 enter_explicit_rule_from_dynamic_rule(target, p->name); 250 return(target); 251 } 252 } 253 break; 254 } 255 } 256 } 257 return(NULL); 258 } 259 260 /* 261 * DONE. 262 * 263 * doname(target, do_get, implicit) 264 * 265 * Chases all files the target depends on and builds any that 266 * are out of date. If the target is out of date it is then rebuilt. 267 * 268 * Return value: 269 * Indiates if build failed or nt 270 * 271 * Parameters: 272 * target Target to build 273 * do_get Run sccs get is nessecary 274 * implicit doname is trying to find an implicit rule 275 * 276 * Global variables used: 277 * assign_done True if command line assgnment has happened 278 * commands_done Preserved for the case that we need local value 279 * debug_level Should we trace make's actions? 280 * default_rule The rule for ".DEFAULT", used as last resort 281 * empty_name The Name "", used when looking for single sfx 282 * keep_state Indicates that .KEEP_STATE is on 283 * parallel True if building in parallel 284 * recursion_level Used for tracing 285 * report_dependencies make -P is on 286 */ 287 Doname 288 doname(register Name target, register Boolean do_get, register Boolean implicit, register Boolean automatic) 289 { 290 Doname result = build_dont_know; 291 Chain out_of_date_list = NULL; 292 Chain target_group; 293 Property old_locals = NULL; 294 register Property line; 295 Property command = NULL; 296 register Dependency dependency; 297 Name less = NULL; 298 Name true_target = target; 299 Name *automatics = NULL; 300 register int auto_count; 301 Boolean rechecking_target = false; 302 Boolean saved_commands_done; 303 Boolean restart = false; 304 Boolean save_parallel = parallel; 305 Boolean doing_subtree = false; 306 307 Boolean recheck_conditionals = false; 308 309 if (target->state == build_running) { 310 return build_running; 311 } 312 line = get_prop(target->prop, line_prop); 313 if (line != NULL) { 314 /* 315 * If this target is a member of target group and one of the 316 * other members of the group is running, mark this target 317 * as running. 318 */ 319 for (target_group = line->body.line.target_group; 320 target_group != NULL; 321 target_group = target_group->next) { 322 if (is_running(target_group->name)) { 323 target->state = build_running; 324 add_pending(target, 325 recursion_level, 326 do_get, 327 implicit, 328 false); 329 return build_running; 330 } 331 } 332 } 333 /* 334 * If the target is a constructed one for a "::" target, 335 * we need to consider that. 336 */ 337 if (target->has_target_prop) { 338 true_target = get_prop(target->prop, 339 target_prop)->body.target.target; 340 if (true_target->colon_splits > 0) { 341 /* Make sure we have a valid time for :: targets */ 342 Property time; 343 344 time = get_prop(true_target->prop, time_prop); 345 if (time != NULL) { 346 true_target->stat.time = time->body.time.time; 347 } 348 } 349 } 350 (void) exists(true_target); 351 /* 352 * If the target has been processed, we don't need to do it again, 353 * unless it depends on conditional macros or a delayed assignment, 354 * or it has been done when KEEP_STATE is on. 355 */ 356 if (target->state == build_ok) { 357 if((!keep_state || (!target->depends_on_conditional && !assign_done))) { 358 return build_ok; 359 } else { 360 recheck_conditionals = true; 361 } 362 } 363 if (target->state == build_subtree) { 364 /* A dynamic macro subtree is being built */ 365 target->state = build_dont_know; 366 doing_subtree = true; 367 if (!target->checking_subtree) { 368 /* 369 * This target has been started before and therefore 370 * not all dependencies have to be built. 371 */ 372 restart = true; 373 } 374 } else if (target->state == build_pending) { 375 target->state = build_dont_know; 376 restart = true; 377 /* 378 } else if (parallel && 379 keep_state && 380 (target->conditional_cnt > 0)) { 381 if (!parallel_ok(target, false)) { 382 add_subtree(target, recursion_level, do_get, implicit); 383 target->state = build_running; 384 return build_running; 385 } 386 */ 387 } 388 /* 389 * If KEEP_STATE is on, we have to rebuild the target if the 390 * building of it caused new automatic dependencies to be reported. 391 * This is where we restart the build. 392 */ 393 if (line != NULL) { 394 line->body.line.percent = NULL; 395 } 396 recheck_target: 397 /* Init all local variables */ 398 result = build_dont_know; 399 out_of_date_list = NULL; 400 command = NULL; 401 less = NULL; 402 auto_count = 0; 403 if (!restart && line != NULL) { 404 /* 405 * If this target has never been built before, mark all 406 * of the dependencies as never built. 407 */ 408 for (dependency = line->body.line.dependencies; 409 dependency != NULL; 410 dependency = dependency->next) { 411 dependency->built = false; 412 } 413 } 414 /* Save the set of automatic depes defined for this target */ 415 if (keep_state && 416 (line != NULL) && 417 (line->body.line.dependencies != NULL)) { 418 Name *p; 419 420 /* 421 * First run thru the dependency list to see how many 422 * autos there are. 423 */ 424 for (dependency = line->body.line.dependencies; 425 dependency != NULL; 426 dependency = dependency->next) { 427 if (dependency->automatic && !dependency->stale) { 428 auto_count++; 429 } 430 } 431 /* Create vector to hold the current autos */ 432 automatics = 433 (Name *) alloca((int) (auto_count * sizeof (Name))); 434 /* Copy them */ 435 for (p = automatics, dependency = line->body.line.dependencies; 436 dependency != NULL; 437 dependency = dependency->next) { 438 if (dependency->automatic && !dependency->stale) { 439 *p++ = dependency->name; 440 } 441 } 442 } 443 if (debug_level > 1) { 444 (void) printf(NOCATGETS("%*sdoname(%s)\n"), 445 recursion_level, 446 "", 447 target->string_mb); 448 } 449 recursion_level++; 450 /* Avoid infinite loops */ 451 if (target->state == build_in_progress) { 452 warning(catgets(catd, 1, 16, "Infinite loop: Target `%s' depends on itself"), 453 target->string_mb); 454 return build_ok; 455 } 456 target->state = build_in_progress; 457 458 /* Activate conditional macros for the target */ 459 if (!target->added_pattern_conditionals) { 460 add_pattern_conditionals(target); 461 target->added_pattern_conditionals = true; 462 } 463 if (target->conditional_cnt > 0) { 464 old_locals = (Property) alloca(target->conditional_cnt * 465 sizeof (Property_rec)); 466 set_locals(target, old_locals); 467 } 468 469 /* 470 * after making the call to dynamic_dependecies unconditional we can handle 471 * target names that are same as file name. In this case $$@ in the 472 * dependencies did not mean anything. WIth this change it expands it 473 * as expected. 474 */ 475 if (!target->has_depe_list_expanded) 476 { 477 dynamic_dependencies(target); 478 } 479 480 /* 481 * FIRST SECTION -- GO THROUGH DEPENDENCIES AND COLLECT EXPLICIT 482 * COMMANDS TO RUN 483 */ 484 if ((line = get_prop(target->prop, line_prop)) != NULL) { 485 if (check_dependencies(&result, 486 line, 487 do_get, 488 target, 489 true_target, 490 doing_subtree, 491 &out_of_date_list, 492 old_locals, 493 implicit, 494 &command, 495 less, 496 rechecking_target, 497 recheck_conditionals)) { 498 return build_running; 499 } 500 if (line->body.line.query != NULL) { 501 delete_query_chain(line->body.line.query); 502 } 503 line->body.line.query = out_of_date_list; 504 } 505 506 507 /* 508 * If the target is a :: type, do not try to find the rule for the target, 509 * all actions will be taken by separate branches. 510 * Else, we try to find an implicit rule using various methods, 511 * we quit as soon as one is found. 512 * 513 * [tolik, 12 Sep 2002] Do not try to find implicit rule for the target 514 * being rechecked - the target is being rechecked means that it already 515 * has explicit dependencies derived from an implicit rule found 516 * in previous step. 517 */ 518 if (target->colon_splits == 0 && !rechecking_target) { 519 /* Look for percent matched rule */ 520 if ((result == build_dont_know) && 521 (command == NULL)) { 522 switch (find_percent_rule( 523 target, 524 &command, 525 recheck_conditionals)) { 526 case build_failed: 527 result = build_failed; 528 break; 529 case build_running: 530 target->state = build_running; 531 add_pending(target, 532 --recursion_level, 533 do_get, 534 implicit, 535 false); 536 if (target->conditional_cnt > 0) { 537 reset_locals(target, 538 old_locals, 539 get_prop(target->prop, 540 conditional_prop), 541 0); 542 } 543 return build_running; 544 case build_ok: 545 result = build_ok; 546 break; 547 } 548 } 549 /* Look for double suffix rule */ 550 if (result == build_dont_know) { 551 Property member; 552 553 if (target->is_member && 554 ((member = get_prop(target->prop, member_prop)) != 555 NULL)) { 556 switch (find_ar_suffix_rule(target, 557 member->body. 558 member.member, 559 &command, 560 recheck_conditionals)) { 561 case build_failed: 562 result = build_failed; 563 break; 564 case build_running: 565 target->state = build_running; 566 add_pending(target, 567 --recursion_level, 568 do_get, 569 implicit, 570 false); 571 if (target->conditional_cnt > 0) { 572 reset_locals(target, 573 old_locals, 574 get_prop(target->prop, 575 conditional_prop), 576 0); 577 } 578 return build_running; 579 default: 580 /* ALWAYS bind $% for old style */ 581 /* ar rules */ 582 if (line == NULL) { 583 line = 584 maybe_append_prop(target, 585 line_prop); 586 } 587 line->body.line.percent = 588 member->body.member.member; 589 break; 590 } 591 } else { 592 switch (find_double_suffix_rule(target, 593 &command, 594 recheck_conditionals)) { 595 case build_failed: 596 result = build_failed; 597 break; 598 case build_running: 599 target->state = build_running; 600 add_pending(target, 601 --recursion_level, 602 do_get, 603 implicit, 604 false); 605 if (target->conditional_cnt > 0) { 606 reset_locals(target, 607 old_locals, 608 get_prop(target-> 609 prop, 610 conditional_prop), 611 0); 612 } 613 return build_running; 614 } 615 } 616 } 617 /* Look for single suffix rule */ 618 619 /* /tolik/ 620 * I commented !implicit to fix bug 1247448: Suffix Rules failed when combine with Pattern Matching Rules. 621 * This caused problem with SVR4 tilde rules (infinite recursion). So I made some changes in "implicit.cc" 622 */ 623 /* /tolik, 06.21.96/ 624 * Regression! See BugId 1255360 625 * If more than one percent rules are defined for the same target then 626 * the behaviour of 'make' with my previous fix may be different from one 627 * of the 'old make'. 628 * The global variable second_pass (maybe it should be an argument to doname()) 629 * is intended to avoid this regression. It is set in doname_check(). 630 * First, 'make' will work as it worked before. Only when it is 631 * going to say "don't know how to make target" it sets second_pass to true and 632 * run 'doname' again but now trying to use Single Suffix Rules. 633 */ 634 if ((result == build_dont_know) && !automatic && (!implicit || second_pass) && 635 ((line == NULL) || 636 ((line->body.line.target != NULL) && 637 !line->body.line.target->has_regular_dependency))) { 638 switch (find_suffix_rule(target, 639 target, 640 empty_name, 641 &command, 642 recheck_conditionals)) { 643 case build_failed: 644 result = build_failed; 645 break; 646 case build_running: 647 target->state = build_running; 648 add_pending(target, 649 --recursion_level, 650 do_get, 651 implicit, 652 false); 653 if (target->conditional_cnt > 0) { 654 reset_locals(target, 655 old_locals, 656 get_prop(target->prop, 657 conditional_prop), 658 0); 659 } 660 return build_running; 661 } 662 } 663 /* Try to sccs get */ 664 if ((command == NULL) && 665 (result == build_dont_know) && 666 do_get) { 667 result = sccs_get(target, &command); 668 } 669 670 /* Use .DEFAULT rule if it is defined. */ 671 if ((command == NULL) && 672 (result == build_dont_know) && 673 (true_target->colons == no_colon) && 674 default_rule && 675 !implicit) { 676 /* Make sure we have a line prop */ 677 line = maybe_append_prop(target, line_prop); 678 command = line; 679 Boolean out_of_date; 680 if (true_target->is_member) { 681 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time, 682 line->body.line.dependency_time); 683 } else { 684 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time, 685 line->body.line.dependency_time); 686 } 687 if (build_unconditional || out_of_date) { 688 line->body.line.is_out_of_date = true; 689 if (debug_level > 0) { 690 (void) printf(catgets(catd, 1, 17, "%*sBuilding %s using .DEFAULT because it is out of date\n"), 691 recursion_level, 692 "", 693 true_target->string_mb); 694 } 695 } 696 line->body.line.sccs_command = false; 697 line->body.line.command_template = default_rule; 698 line->body.line.target = true_target; 699 line->body.line.star = NULL; 700 line->body.line.less = true_target; 701 line->body.line.percent = NULL; 702 } 703 } 704 705 /* We say "target up to date" if no cmd were executed for the target */ 706 if (!target->is_double_colon_parent) { 707 commands_done = false; 708 } 709 710 silent = silent_all; 711 ignore_errors = ignore_errors_all; 712 if (posix) 713 { 714 if (!silent) 715 { 716 silent = (Boolean) target->silent_mode; 717 } 718 if (!ignore_errors) 719 { 720 ignore_errors = (Boolean) target->ignore_error_mode; 721 } 722 } 723 724 int doname_dyntarget = 0; 725 r_command: 726 /* Run commands if any. */ 727 if ((command != NULL) && 728 (command->body.line.command_template != NULL)) { 729 if (result != build_failed) { 730 result = run_command(command, 731 (Boolean) ((parallel || save_parallel) && !silent)); 732 } 733 switch (result) { 734 case build_running: 735 add_running(target, 736 true_target, 737 command, 738 --recursion_level, 739 auto_count, 740 automatics, 741 do_get, 742 implicit); 743 target->state = build_running; 744 if ((line = get_prop(target->prop, 745 line_prop)) != NULL) { 746 if (line->body.line.query != NULL) { 747 delete_query_chain(line->body.line.query); 748 } 749 line->body.line.query = NULL; 750 } 751 if (target->conditional_cnt > 0) { 752 reset_locals(target, 753 old_locals, 754 get_prop(target->prop, 755 conditional_prop), 756 0); 757 } 758 return build_running; 759 case build_serial: 760 add_serial(target, 761 --recursion_level, 762 do_get, 763 implicit); 764 target->state = build_running; 765 line = get_prop(target->prop, line_prop); 766 if (line != NULL) { 767 if (line->body.line.query != NULL) { 768 delete_query_chain(line->body.line.query); 769 } 770 line->body.line.query = NULL; 771 } 772 if (target->conditional_cnt > 0) { 773 reset_locals(target, 774 old_locals, 775 get_prop(target->prop, 776 conditional_prop), 777 0); 778 } 779 return build_running; 780 case build_ok: 781 /* If all went OK set a nice timestamp */ 782 if (true_target->stat.time == file_doesnt_exist) { 783 true_target->stat.time = file_max_time; 784 } 785 break; 786 } 787 } else { 788 /* 789 * If no command was found for the target, and it doesn't 790 * exist, and it is mentioned as a target in the makefile, 791 * we say it is extremely new and that it is OK. 792 */ 793 if (target->colons != no_colon) { 794 if (true_target->stat.time == file_doesnt_exist){ 795 true_target->stat.time = file_max_time; 796 } 797 result = build_ok; 798 } 799 /* 800 * Trying dynamic targets. 801 */ 802 if(!doname_dyntarget) { 803 doname_dyntarget = 1; 804 Name dtarg = find_dyntarget(target); 805 if(dtarg!=NULL) { 806 if (!target->has_depe_list_expanded) { 807 dynamic_dependencies(target); 808 } 809 if ((line = get_prop(target->prop, line_prop)) != NULL) { 810 if (check_dependencies(&result, 811 line, 812 do_get, 813 target, 814 true_target, 815 doing_subtree, 816 &out_of_date_list, 817 old_locals, 818 implicit, 819 &command, 820 less, 821 rechecking_target, 822 recheck_conditionals)) 823 { 824 return build_running; 825 } 826 if (line->body.line.query != NULL) { 827 delete_query_chain(line->body.line.query); 828 } 829 line->body.line.query = out_of_date_list; 830 } 831 goto r_command; 832 } 833 } 834 /* 835 * If the file exists, it is OK that we couldnt figure 836 * out how to build it. 837 */ 838 (void) exists(target); 839 if ((target->stat.time != file_doesnt_exist) && 840 (result == build_dont_know)) { 841 result = build_ok; 842 } 843 } 844 845 /* 846 * Some of the following is duplicated in the function finish_doname. 847 * If anything is changed here, check to see if it needs to be 848 * changed there. 849 */ 850 if ((line = get_prop(target->prop, line_prop)) != NULL) { 851 if (line->body.line.query != NULL) { 852 delete_query_chain(line->body.line.query); 853 } 854 line->body.line.query = NULL; 855 } 856 target->state = result; 857 parallel = save_parallel; 858 if (target->conditional_cnt > 0) { 859 reset_locals(target, 860 old_locals, 861 get_prop(target->prop, conditional_prop), 862 0); 863 } 864 recursion_level--; 865 if (target->is_member) { 866 Property member; 867 868 /* Propagate the timestamp from the member file to the member*/ 869 if ((target->stat.time != file_max_time) && 870 ((member = get_prop(target->prop, member_prop)) != NULL) && 871 (exists(member->body.member.member) > file_doesnt_exist)) { 872 target->stat.time = 873 member->body.member.member->stat.time; 874 } 875 } 876 /* 877 * Check if we found any new auto dependencies when we 878 * built the target. 879 */ 880 if ((result == build_ok) && check_auto_dependencies(target, 881 auto_count, 882 automatics)) { 883 if (debug_level > 0) { 884 (void) printf(catgets(catd, 1, 18, "%*sTarget `%s' acquired new dependencies from build, rechecking all dependencies\n"), 885 recursion_level, 886 "", 887 true_target->string_mb); 888 } 889 rechecking_target = true; 890 saved_commands_done = commands_done; 891 goto recheck_target; 892 } 893 894 if (rechecking_target && !commands_done) { 895 commands_done = saved_commands_done; 896 } 897 898 return result; 899 } 900 901 /* 902 * DONE. 903 * 904 * check_dependencies(result, line, do_get, 905 * target, true_target, doing_subtree, out_of_date_tail, 906 * old_locals, implicit, command, less, rechecking_target) 907 * 908 * Return value: 909 * True returned if some dependencies left running 910 * 911 * Parameters: 912 * result Pointer to cell we update if build failed 913 * line We get the dependencies from here 914 * do_get Allow use of sccs get in recursive doname() 915 * target The target to chase dependencies for 916 * true_target The real one for :: and lib(member) 917 * doing_subtree True if building a conditional macro subtree 918 * out_of_date_tail Used to set the $? list 919 * old_locals Used for resetting the local macros 920 * implicit Called when scanning for implicit rules? 921 * command Place to stuff command 922 * less Set to $< value 923 * 924 * Global variables used: 925 * command_changed Set if we suspect .make.state needs rewrite 926 * debug_level Should we trace actions? 927 * force The Name " FORCE", compared against 928 * recursion_level Used for tracing 929 * rewrite_statefile Set if .make.state needs rewriting 930 * wait_name The Name ".WAIT", compared against 931 */ 932 static Boolean 933 check_dependencies(Doname *result, Property line, Boolean do_get, Name target, Name true_target, Boolean doing_subtree, Chain *out_of_date_tail, Property old_locals, Boolean implicit, Property *command, Name less, Boolean rechecking_target, Boolean recheck_conditionals) 934 { 935 Boolean dependencies_running; 936 register Dependency dependency; 937 Doname dep_result; 938 Boolean dependency_changed = false; 939 940 line->body.line.dependency_time = file_doesnt_exist; 941 if (line->body.line.query != NULL) { 942 delete_query_chain(line->body.line.query); 943 } 944 line->body.line.query = NULL; 945 line->body.line.is_out_of_date = false; 946 dependencies_running = false; 947 /* 948 * Run thru all the dependencies and call doname() recursively 949 * on each of them. 950 */ 951 for (dependency = line->body.line.dependencies; 952 dependency != NULL; 953 dependency = dependency->next) { 954 Boolean this_dependency_changed = false; 955 956 if (!dependency->automatic && 957 (rechecking_target || target->rechecking_target)) { 958 /* 959 * We only bother with the autos when rechecking 960 */ 961 continue; 962 } 963 964 if (dependency->name == wait_name) { 965 /* 966 * The special target .WAIT means finish all of 967 * the prior dependencies before continuing. 968 */ 969 if (dependencies_running) { 970 break; 971 } 972 } else if ((!parallel_ok(dependency->name, false)) && 973 (dependencies_running)) { 974 /* 975 * If we can't execute the current dependency in 976 * parallel, hold off the dependency processing 977 * to preserve the order of the dependencies. 978 */ 979 break; 980 } else { 981 timestruc_t depe_time = file_doesnt_exist; 982 983 984 if (true_target->is_member) { 985 depe_time = exists(dependency->name); 986 } 987 if (dependency->built || 988 (dependency->name->state == build_failed)) { 989 dep_result = (Doname) dependency->name->state; 990 } else { 991 dep_result = doname_check(dependency->name, 992 do_get, 993 false, 994 (Boolean) dependency->automatic); 995 } 996 if (true_target->is_member || dependency->name->is_member) { 997 /* should compare only secs, cause lib members does not have nsec time resolution */ 998 if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) { 999 this_dependency_changed = 1000 dependency_changed = 1001 true; 1002 } 1003 } else { 1004 if (depe_time != dependency->name->stat.time) { 1005 this_dependency_changed = 1006 dependency_changed = 1007 true; 1008 } 1009 } 1010 dependency->built = true; 1011 switch (dep_result) { 1012 case build_running: 1013 dependencies_running = true; 1014 continue; 1015 case build_failed: 1016 *result = build_failed; 1017 break; 1018 case build_dont_know: 1019 /* 1020 * If make can't figure out how to make a dependency, maybe the dependency 1021 * is out of date. In this case, we just declare the target out of date 1022 * and go on. If we really need the dependency, the make'ing of the target 1023 * will fail. This will only happen for automatic (hidden) dependencies. 1024 */ 1025 if(!recheck_conditionals) { 1026 line->body.line.is_out_of_date = true; 1027 } 1028 /* 1029 * Make sure the dependency is not saved 1030 * in the state file. 1031 */ 1032 dependency->stale = true; 1033 rewrite_statefile = 1034 command_changed = 1035 true; 1036 if (debug_level > 0) { 1037 (void) printf(catgets(catd, 1, 19, "Target %s rebuilt because dependency %s does not exist\n"), 1038 true_target->string_mb, 1039 dependency->name->string_mb); 1040 } 1041 break; 1042 } 1043 if (dependency->name->depends_on_conditional) { 1044 target->depends_on_conditional = true; 1045 } 1046 if (dependency->name == force) { 1047 target->stat.time = 1048 dependency->name->stat.time; 1049 } 1050 /* 1051 * Propagate new timestamp from "member" to 1052 * "lib.a(member)". 1053 */ 1054 (void) exists(dependency->name); 1055 1056 /* Collect the timestamp of the youngest dependency */ 1057 line->body.line.dependency_time = 1058 MAX(dependency->name->stat.time, 1059 line->body.line.dependency_time); 1060 1061 /* Correction: do not consider nanosecs for members */ 1062 if(true_target->is_member || dependency->name->is_member) { 1063 line->body.line.dependency_time.tv_nsec = 0; 1064 } 1065 1066 if (debug_level > 1) { 1067 (void) printf(catgets(catd, 1, 20, "%*sDate(%s)=%s \n"), 1068 recursion_level, 1069 "", 1070 dependency->name->string_mb, 1071 time_to_string(dependency->name-> 1072 stat.time)); 1073 if (dependency->name->stat.time > line->body.line.dependency_time) { 1074 (void) printf(catgets(catd, 1, 21, "%*sDate-dependencies(%s) set to %s\n"), 1075 recursion_level, 1076 "", 1077 true_target->string_mb, 1078 time_to_string(line->body.line. 1079 dependency_time)); 1080 } 1081 } 1082 1083 /* Build the $? list */ 1084 if (true_target->is_member) { 1085 if (this_dependency_changed == true) { 1086 true_target->stat.time = dependency->name->stat.time; 1087 true_target->stat.time.tv_sec--; 1088 } else { 1089 /* Dina: 1090 * The next statement is commented 1091 * out as a fix for bug #1051032. 1092 * if dependency hasn't changed 1093 * then there's no need to invalidate 1094 * true_target. This statemnt causes 1095 * make to take much longer to process 1096 * an already-built archive. Soren 1097 * said it was a quick fix for some 1098 * problem he doesn't remember. 1099 true_target->stat.time = file_no_time; 1100 */ 1101 (void) exists(true_target); 1102 } 1103 } else { 1104 (void) exists(true_target); 1105 } 1106 Boolean out_of_date; 1107 if (true_target->is_member || dependency->name->is_member) { 1108 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time, 1109 dependency->name->stat.time); 1110 } else { 1111 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time, 1112 dependency->name->stat.time); 1113 } 1114 if ((build_unconditional || out_of_date) && 1115 (dependency->name != force) && 1116 (dependency->stale == false)) { 1117 *out_of_date_tail = ALLOC(Chain); 1118 if (dependency->name->is_member && 1119 (get_prop(dependency->name->prop, 1120 member_prop) != NULL)) { 1121 (*out_of_date_tail)->name = 1122 get_prop(dependency->name->prop, 1123 member_prop)-> 1124 body.member.member; 1125 } else { 1126 (*out_of_date_tail)->name = 1127 dependency->name; 1128 } 1129 (*out_of_date_tail)->next = NULL; 1130 out_of_date_tail = &(*out_of_date_tail)->next; 1131 if (debug_level > 0) { 1132 if (dependency->name->stat.time == file_max_time) { 1133 (void) printf(catgets(catd, 1, 22, "%*sBuilding %s because %s does not exist\n"), 1134 recursion_level, 1135 "", 1136 true_target->string_mb, 1137 dependency->name->string_mb); 1138 } else { 1139 (void) printf(catgets(catd, 1, 23, "%*sBuilding %s because it is out of date relative to %s\n"), 1140 recursion_level, 1141 "", 1142 true_target->string_mb, 1143 dependency->name->string_mb); 1144 } 1145 } 1146 } 1147 if (dependency->name == force) { 1148 force->stat.time = 1149 file_max_time; 1150 force->state = build_dont_know; 1151 } 1152 } 1153 } 1154 if (dependencies_running) { 1155 if (doing_subtree) { 1156 if (target->conditional_cnt > 0) { 1157 reset_locals(target, 1158 old_locals, 1159 get_prop(target->prop, 1160 conditional_prop), 1161 0); 1162 } 1163 return true; 1164 } else { 1165 target->state = build_running; 1166 add_pending(target, 1167 --recursion_level, 1168 do_get, 1169 implicit, 1170 false); 1171 if (target->conditional_cnt > 0) { 1172 reset_locals(target, 1173 old_locals, 1174 get_prop(target->prop, 1175 conditional_prop), 1176 0); 1177 } 1178 return true; 1179 } 1180 } 1181 /* 1182 * Collect the timestamp of the youngest double colon target 1183 * dependency. 1184 */ 1185 if (target->is_double_colon_parent) { 1186 for (dependency = line->body.line.dependencies; 1187 dependency != NULL; 1188 dependency = dependency->next) { 1189 Property tmp_line; 1190 1191 if ((tmp_line = get_prop(dependency->name->prop, line_prop)) != NULL) { 1192 if(tmp_line->body.line.dependency_time != file_max_time) { 1193 target->stat.time = 1194 MAX(tmp_line->body.line.dependency_time, 1195 target->stat.time); 1196 } 1197 } 1198 } 1199 } 1200 if ((true_target->is_member) && (dependency_changed == true)) { 1201 true_target->stat.time = file_no_time; 1202 } 1203 /* 1204 * After scanning all the dependencies, we check the rule 1205 * if we found one. 1206 */ 1207 if (line->body.line.command_template != NULL) { 1208 if (line->body.line.command_template_redefined) { 1209 warning(catgets(catd, 1, 24, "Too many rules defined for target %s"), 1210 target->string_mb); 1211 } 1212 *command = line; 1213 /* Check if the target is out of date */ 1214 Boolean out_of_date; 1215 if (true_target->is_member) { 1216 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time, 1217 line->body.line.dependency_time); 1218 } else { 1219 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time, 1220 line->body.line.dependency_time); 1221 } 1222 if (build_unconditional || out_of_date){ 1223 if(!recheck_conditionals) { 1224 line->body.line.is_out_of_date = true; 1225 } 1226 } 1227 line->body.line.sccs_command = false; 1228 line->body.line.target = true_target; 1229 if(gnu_style) { 1230 1231 // set $< for explicit rule 1232 if(line->body.line.dependencies != NULL) { 1233 less = line->body.line.dependencies->name; 1234 } 1235 1236 // set $* for explicit rule 1237 Name target_body; 1238 Name tt = true_target; 1239 Property member; 1240 register wchar_t *target_end; 1241 register Dependency suffix; 1242 register int suffix_length; 1243 Wstring targ_string; 1244 Wstring suf_string; 1245 1246 if (true_target->is_member && 1247 ((member = get_prop(target->prop, member_prop)) != 1248 NULL)) { 1249 tt = member->body.member.member; 1250 } 1251 targ_string.init(tt); 1252 target_end = targ_string.get_string() + tt->hash.length; 1253 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) { 1254 suffix_length = suffix->name->hash.length; 1255 suf_string.init(suffix->name); 1256 if (tt->hash.length < suffix_length) { 1257 continue; 1258 } else if (!IS_WEQUALN(suf_string.get_string(), 1259 (target_end - suffix_length), 1260 suffix_length)) { 1261 continue; 1262 } 1263 target_body = GETNAME( 1264 targ_string.get_string(), 1265 (int)(tt->hash.length - suffix_length) 1266 ); 1267 line->body.line.star = target_body; 1268 } 1269 1270 // set result = build_ok so that implicit rules are not used. 1271 if(*result == build_dont_know) { 1272 *result = build_ok; 1273 } 1274 } 1275 if (less != NULL) { 1276 line->body.line.less = less; 1277 } 1278 } 1279 1280 return false; 1281 } 1282 1283 /* 1284 * dynamic_dependencies(target) 1285 * 1286 * Checks if any dependency contains a macro ref 1287 * If so, it replaces the dependency with the expanded version. 1288 * Here, "$@" gets translated to target->string. That is 1289 * the current name on the left of the colon in the 1290 * makefile. Thus, 1291 * xyz: s.$@.c 1292 * translates into 1293 * xyz: s.xyz.c 1294 * 1295 * Also, "$(@F)" translates to the same thing without a preceeding 1296 * directory path (if one exists). 1297 * Note, to enter "$@" on a dependency line in a makefile 1298 * "$$@" must be typed. This is because make expands 1299 * macros in dependency lists upon reading them. 1300 * dynamic_dependencies() also expands file wildcards. 1301 * If there are any Shell meta characters in the name, 1302 * search the directory, and replace the dependency 1303 * with the set of files the pattern matches 1304 * 1305 * Parameters: 1306 * target Target to sanitize dependencies for 1307 * 1308 * Global variables used: 1309 * c_at The Name "@", used to set macro value 1310 * debug_level Should we trace actions? 1311 * dot The Name ".", used to read directory 1312 * recursion_level Used for tracing 1313 */ 1314 void 1315 dynamic_dependencies(Name target) 1316 { 1317 wchar_t pattern[MAXPATHLEN]; 1318 register wchar_t *p; 1319 Property line; 1320 register Dependency dependency; 1321 register Dependency *remove; 1322 String_rec string; 1323 wchar_t buffer[MAXPATHLEN]; 1324 register Boolean set_at = false; 1325 register wchar_t *start; 1326 Dependency new_depe; 1327 register Boolean reuse_cell; 1328 Dependency first_member; 1329 Name directory; 1330 Name lib; 1331 Name member; 1332 Property prop; 1333 Name true_target = target; 1334 wchar_t *library; 1335 1336 if ((line = get_prop(target->prop, line_prop)) == NULL) { 1337 return; 1338 } 1339 /* If the target is constructed from a "::" target we consider that */ 1340 if (target->has_target_prop) { 1341 true_target = get_prop(target->prop, 1342 target_prop)->body.target.target; 1343 } 1344 /* Scan all dependencies and process the ones that contain "$" chars */ 1345 for (dependency = line->body.line.dependencies; 1346 dependency != NULL; 1347 dependency = dependency->next) { 1348 if (!dependency->name->dollar) { 1349 continue; 1350 } 1351 target->has_depe_list_expanded = true; 1352 1353 /* The make macro $@ is bound to the target name once per */ 1354 /* invocation of dynamic_dependencies() */ 1355 if (!set_at) { 1356 (void) SETVAR(c_at, true_target, false); 1357 set_at = true; 1358 } 1359 /* Expand this dependency string */ 1360 INIT_STRING_FROM_STACK(string, buffer); 1361 expand_value(dependency->name, &string, false); 1362 /* Scan the expanded string. It could contain whitespace */ 1363 /* which mean it expands to several dependencies */ 1364 start = string.buffer.start; 1365 while (iswspace(*start)) { 1366 start++; 1367 } 1368 /* Remove the cell (later) if the macro was empty */ 1369 if (start[0] == (int) nul_char) { 1370 dependency->name = NULL; 1371 } 1372 1373 /* azv 10/26/95 to fix bug BID_1170218 */ 1374 if ((start[0] == (int) period_char) && 1375 (start[1] == (int) slash_char)) { 1376 start += 2; 1377 } 1378 /* azv */ 1379 1380 first_member = NULL; 1381 /* We use the original dependency cell for the first */ 1382 /* dependency from the expansion */ 1383 reuse_cell = true; 1384 /* We also have to deal with dependencies that expand to */ 1385 /* lib.a(members) notation */ 1386 for (p = start; *p != (int) nul_char; p++) { 1387 if ((*p == (int) parenleft_char)) { 1388 lib = GETNAME(start, p - start); 1389 lib->is_member = true; 1390 first_member = dependency; 1391 start = p + 1; 1392 while (iswspace(*start)) { 1393 start++; 1394 } 1395 break; 1396 } 1397 } 1398 do { 1399 /* First skip whitespace */ 1400 for (p = start; *p != (int) nul_char; p++) { 1401 if ((*p == (int) nul_char) || 1402 iswspace(*p) || 1403 (*p == (int) parenright_char)) { 1404 break; 1405 } 1406 } 1407 /* Enter dependency from expansion */ 1408 if (p != start) { 1409 /* Create new dependency cell if */ 1410 /* this is not the first dependency */ 1411 /* picked from the expansion */ 1412 if (!reuse_cell) { 1413 new_depe = ALLOC(Dependency); 1414 new_depe->next = dependency->next; 1415 new_depe->automatic = false; 1416 new_depe->stale = false; 1417 new_depe->built = false; 1418 dependency->next = new_depe; 1419 dependency = new_depe; 1420 } 1421 reuse_cell = false; 1422 /* Internalize the dependency name */ 1423 // tolik. Fix for bug 4110429: inconsistent expansion for macros that 1424 // include "//" and "/./" 1425 //dependency->name = GETNAME(start, p - start); 1426 dependency->name = normalize_name(start, p - start); 1427 if ((debug_level > 0) && 1428 (first_member == NULL)) { 1429 (void) printf(catgets(catd, 1, 25, "%*sDynamic dependency `%s' for target `%s'\n"), 1430 recursion_level, 1431 "", 1432 dependency->name->string_mb, 1433 true_target->string_mb); 1434 } 1435 for (start = p; iswspace(*start); start++); 1436 p = start; 1437 } 1438 } while ((*p != (int) nul_char) && 1439 (*p != (int) parenright_char)); 1440 /* If the expansion was of lib.a(members) format we now */ 1441 /* enter the proper member cells */ 1442 if (first_member != NULL) { 1443 /* Scan the new dependencies and transform them from */ 1444 /* "foo" to "lib.a(foo)" */ 1445 for (; 1; first_member = first_member->next) { 1446 /* Build "lib.a(foo)" name */ 1447 INIT_STRING_FROM_STACK(string, buffer); 1448 APPEND_NAME(lib, 1449 &string, 1450 (int) lib->hash.length); 1451 append_char((int) parenleft_char, &string); 1452 APPEND_NAME(first_member->name, 1453 &string, 1454 FIND_LENGTH); 1455 append_char((int) parenright_char, &string); 1456 member = first_member->name; 1457 /* Replace "foo" with "lib.a(foo)" */ 1458 first_member->name = 1459 GETNAME(string.buffer.start, FIND_LENGTH); 1460 if (string.free_after_use) { 1461 retmem(string.buffer.start); 1462 } 1463 if (debug_level > 0) { 1464 (void) printf(catgets(catd, 1, 26, "%*sDynamic dependency `%s' for target `%s'\n"), 1465 recursion_level, 1466 "", 1467 first_member->name-> 1468 string_mb, 1469 true_target->string_mb); 1470 } 1471 first_member->name->is_member = lib->is_member; 1472 /* Add member property to member */ 1473 prop = maybe_append_prop(first_member->name, 1474 member_prop); 1475 prop->body.member.library = lib; 1476 prop->body.member.entry = NULL; 1477 prop->body.member.member = member; 1478 if (first_member == dependency) { 1479 break; 1480 } 1481 } 1482 } 1483 } 1484 Wstring wcb; 1485 /* Then scan all the dependencies again. This time we want to expand */ 1486 /* shell file wildcards */ 1487 for (remove = &line->body.line.dependencies, dependency = *remove; 1488 dependency != NULL; 1489 dependency = *remove) { 1490 if (dependency->name == NULL) { 1491 dependency = *remove = (*remove)->next; 1492 continue; 1493 } 1494 /* If dependency name string contains shell wildcards */ 1495 /* replace the name with the expansion */ 1496 if (dependency->name->wildcard) { 1497 wcb.init(dependency->name); 1498 if ((start = (wchar_t *) wschr(wcb.get_string(), 1499 (int) parenleft_char)) != NULL) { 1500 /* lib(*) type pattern */ 1501 library = buffer; 1502 (void) wsncpy(buffer, 1503 wcb.get_string(), 1504 start - wcb.get_string()); 1505 buffer[start-wcb.get_string()] = 1506 (int) nul_char; 1507 (void) wsncpy(pattern, 1508 start + 1, 1509 (int) (dependency->name->hash.length-(start-wcb.get_string())-2)); 1510 pattern[dependency->name->hash.length - 1511 (start-wcb.get_string()) - 2] = 1512 (int) nul_char; 1513 } else { 1514 library = NULL; 1515 (void) wsncpy(pattern, 1516 wcb.get_string(), 1517 (int) dependency->name->hash.length); 1518 pattern[dependency->name->hash.length] = 1519 (int) nul_char; 1520 } 1521 start = (wchar_t *) wsrchr(pattern, (int) slash_char); 1522 if (start == NULL) { 1523 directory = dot; 1524 p = pattern; 1525 } else { 1526 directory = GETNAME(pattern, start-pattern); 1527 p = start+1; 1528 } 1529 /* The expansion is handled by the read_dir() routine*/ 1530 if (read_dir(directory, p, line, library)) { 1531 *remove = (*remove)->next; 1532 } else { 1533 remove = &dependency->next; 1534 } 1535 } else { 1536 remove = &dependency->next; 1537 } 1538 } 1539 1540 /* Then unbind $@ */ 1541 (void) SETVAR(c_at, (Name) NULL, false); 1542 } 1543 1544 /* 1545 * DONE. 1546 * 1547 * run_command(line) 1548 * 1549 * Takes one Cmd_line and runs the commands from it. 1550 * 1551 * Return value: 1552 * Indicates if the command failed or not 1553 * 1554 * Parameters: 1555 * line The command line to run 1556 * 1557 * Global variables used: 1558 * commands_done Set if we do run command 1559 * current_line Set to the line we run a command from 1560 * current_target Set to the target we run a command for 1561 * file_number Used to form temp file name 1562 * keep_state Indicates that .KEEP_STATE is on 1563 * make_state The Name ".make.state", used to check timestamp 1564 * parallel True if currently building in parallel 1565 * parallel_process_cnt Count of parallel processes running 1566 * quest Indicates that make -q is on 1567 * rewrite_statefile Set if we do run a command 1568 * sunpro_dependencies The Name "SUNPRO_DEPENDENCIES", set value 1569 * temp_file_directory Used to form temp fie name 1570 * temp_file_name Set to the name of the temp file 1571 * touch Indicates that make -t is on 1572 */ 1573 static Doname 1574 run_command(register Property line, Boolean) 1575 { 1576 register Doname result = build_ok; 1577 register Boolean remember_only = false; 1578 register Name target = line->body.line.target; 1579 wchar_t *string; 1580 char tmp_file_path[MAXPATHLEN]; 1581 1582 if (!line->body.line.is_out_of_date && target->rechecking_target) { 1583 target->rechecking_target = false; 1584 return build_ok; 1585 } 1586 1587 /* 1588 * Build the command if we know the target is out of date, 1589 * or if we want to check cmd consistency. 1590 */ 1591 if (line->body.line.is_out_of_date || keep_state) { 1592 /* Hack for handling conditional macros in DMake. */ 1593 if (!line->body.line.dont_rebuild_command_used) { 1594 build_command_strings(target, line); 1595 } 1596 } 1597 /* Never mind */ 1598 if (!line->body.line.is_out_of_date) { 1599 return build_ok; 1600 } 1601 /* If quest, then exit(1) because the target is out of date */ 1602 if (quest) { 1603 if (posix) { 1604 result = execute_parallel(line, true); 1605 } 1606 exit_status = 1; 1607 exit(1); 1608 } 1609 /* We actually had to do something this time */ 1610 rewrite_statefile = commands_done = true; 1611 /* 1612 * If this is an sccs command, we have to do some extra checking 1613 * and possibly complain. If the file can't be gotten because it's 1614 * checked out, we complain and behave as if the command was 1615 * executed eventhough we ignored the command. 1616 */ 1617 if (!touch && 1618 line->body.line.sccs_command && 1619 (target->stat.time != file_doesnt_exist) && 1620 ((target->stat.mode & 0222) != 0)) { 1621 fatal(catgets(catd, 1, 27, "%s is writable so it cannot be sccs gotten"), 1622 target->string_mb); 1623 target->has_complained = remember_only = true; 1624 } 1625 /* 1626 * If KEEP_STATE is on, we make sure we have the timestamp for 1627 * .make.state. If .make.state changes during the command run, 1628 * we reread .make.state after the command. We also setup the 1629 * environment variable that asks utilities to report dependencies. 1630 */ 1631 if (!touch && 1632 keep_state && 1633 !remember_only) { 1634 (void) exists(make_state); 1635 if((strlen(temp_file_directory) == 1) && 1636 (temp_file_directory[0] == '/')) { 1637 tmp_file_path[0] = '\0'; 1638 } else { 1639 strcpy(tmp_file_path, temp_file_directory); 1640 } 1641 sprintf(mbs_buffer, 1642 NOCATGETS("%s/.make.dependency.%08x.%d.%d"), 1643 tmp_file_path, 1644 hostid, 1645 getpid(), 1646 file_number++); 1647 MBSTOWCS(wcs_buffer, mbs_buffer); 1648 Boolean fnd; 1649 temp_file_name = getname_fn(wcs_buffer, FIND_LENGTH, false, &fnd); 1650 temp_file_name->stat.is_file = true; 1651 int len = 2*MAXPATHLEN + strlen(target->string_mb) + 2; 1652 wchar_t *to = string = ALLOC_WC(len); 1653 for (wchar_t *from = wcs_buffer; *from != (int) nul_char; ) { 1654 if (*from == (int) space_char) { 1655 *to++ = (int) backslash_char; 1656 } 1657 *to++ = *from++; 1658 } 1659 *to++ = (int) space_char; 1660 MBSTOWCS(to, target->string_mb); 1661 Name sprodep_name = getname_fn(string, FIND_LENGTH, false, &fnd); 1662 (void) SETVAR(sunpro_dependencies, 1663 sprodep_name, 1664 false); 1665 retmem(string); 1666 } else { 1667 temp_file_name = NULL; 1668 } 1669 1670 /* 1671 * In case we are interrupted, we need to know what was going on. 1672 */ 1673 current_target = target; 1674 /* 1675 * We also need to be able to save an empty command instead of the 1676 * interrupted one in .make.state. 1677 */ 1678 current_line = line; 1679 if (remember_only) { 1680 /* Empty block!!! */ 1681 } else if (touch) { 1682 result = touch_command(line, target, result); 1683 if (posix) { 1684 result = execute_parallel(line, true); 1685 } 1686 } else { 1687 /* 1688 * If this is not a touch run, we need to execute the 1689 * proper command(s) for the target. 1690 */ 1691 if (parallel) { 1692 if (!parallel_ok(target, true)) { 1693 /* 1694 * We are building in parallel, but 1695 * this target must be built in serial. 1696 */ 1697 /* 1698 * If nothing else is building, 1699 * do this one, else wait. 1700 */ 1701 if (parallel_process_cnt == 0) { 1702 result = execute_parallel(line, true, target->localhost); 1703 } else { 1704 current_target = NULL; 1705 current_line = NULL; 1706 /* 1707 line->body.line.command_used = NULL; 1708 */ 1709 line->body.line.dont_rebuild_command_used = true; 1710 return build_serial; 1711 } 1712 } else { 1713 result = execute_parallel(line, false); 1714 switch (result) { 1715 case build_running: 1716 return build_running; 1717 case build_serial: 1718 if (parallel_process_cnt == 0) { 1719 result = execute_parallel(line, true, target->localhost); 1720 } else { 1721 current_target = NULL; 1722 current_line = NULL; 1723 target->parallel = false; 1724 line->body.line.command_used = 1725 NULL; 1726 return build_serial; 1727 } 1728 } 1729 } 1730 } else { 1731 result = execute_parallel(line, true, target->localhost); 1732 } 1733 } 1734 temp_file_name = NULL; 1735 if (report_dependencies_level == 0){ 1736 update_target(line, result); 1737 } 1738 current_target = NULL; 1739 current_line = NULL; 1740 return result; 1741 } 1742 1743 /* 1744 * execute_serial(line) 1745 * 1746 * Runs thru the command line for the target and 1747 * executes the rules one by one. 1748 * 1749 * Return value: 1750 * The result of the command build 1751 * 1752 * Parameters: 1753 * line The command to execute 1754 * 1755 * Static variables used: 1756 * 1757 * Global variables used: 1758 * continue_after_error -k flag 1759 * do_not_exec_rule -n flag 1760 * report_dependencies -P flag 1761 * silent Don't echo commands before executing 1762 * temp_file_name Temp file for auto dependencies 1763 * vpath_defined If true, translate path for command 1764 */ 1765 Doname 1766 execute_serial(Property line) 1767 { 1768 int child_pid = 0; 1769 Boolean printed_serial; 1770 Doname result = build_ok; 1771 Cmd_line rule, cmd_tail, command = NULL; 1772 char mbstring[MAXPATHLEN]; 1773 int filed; 1774 Name target = line->body.line.target; 1775 1776 SEND_MTOOL_MSG( 1777 if (!sent_rsrc_info_msg) { 1778 if (userName[0] == '\0') { 1779 avo_get_user(userName, NULL); 1780 } 1781 if (hostName[0] == '\0') { 1782 strcpy(hostName, avo_hostname()); 1783 } 1784 send_rsrc_info_msg(1, hostName, userName); 1785 sent_rsrc_info_msg = 1; 1786 } 1787 send_job_start_msg(line); 1788 job_result_msg = new Avo_MToolJobResultMsg(); 1789 ); 1790 1791 target->has_recursive_dependency = false; 1792 // We have to create a copy of the rules chain for processing because 1793 // the original one can be destroyed during .make.state file rereading. 1794 for (rule = line->body.line.command_used; 1795 rule != NULL; 1796 rule = rule->next) { 1797 if (command == NULL) { 1798 command = cmd_tail = ALLOC(Cmd_line); 1799 } else { 1800 cmd_tail->next = ALLOC(Cmd_line); 1801 cmd_tail = cmd_tail->next; 1802 } 1803 *cmd_tail = *rule; 1804 } 1805 if (command) { 1806 cmd_tail->next = NULL; 1807 } 1808 for (rule = command; rule != NULL; rule = rule->next) { 1809 if (posix && (touch || quest) && !rule->always_exec) { 1810 continue; 1811 } 1812 if (vpath_defined) { 1813 rule->command_line = 1814 vpath_translation(rule->command_line); 1815 } 1816 /* Echo command line, maybe. */ 1817 if ((rule->command_line->hash.length > 0) && 1818 !silent && 1819 (!rule->silent || do_not_exec_rule) && 1820 (report_dependencies_level == 0)) { 1821 (void) printf("%s\n", rule->command_line->string_mb); 1822 SEND_MTOOL_MSG( 1823 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb)); 1824 ); 1825 } 1826 if (rule->command_line->hash.length > 0) { 1827 SEND_MTOOL_MSG( 1828 (void) sprintf(mbstring, 1829 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"), 1830 tmpdir, 1831 getpid(), 1832 file_number++); 1833 1834 int tmp_fd = mkstemp(mbstring); 1835 if(tmp_fd) { 1836 (void) close(tmp_fd); 1837 } 1838 1839 stdout_file = strdup(mbstring); 1840 stderr_file = NULL; 1841 child_pid = pollResults(stdout_file, 1842 (char *)NULL, 1843 (char *)NULL); 1844 ); 1845 /* Do assignment if command line prefixed with "=" */ 1846 if (rule->assign) { 1847 result = build_ok; 1848 do_assign(rule->command_line, target); 1849 } else if (report_dependencies_level == 0) { 1850 /* Execute command line. */ 1851 setvar_envvar(); 1852 result = dosys(rule->command_line, 1853 (Boolean) rule->ignore_error, 1854 (Boolean) rule->make_refd, 1855 /* ds 98.04.23 bug #4085164. make should always show error messages */ 1856 false, 1857 /* BOOLEAN(rule->silent && 1858 rule->ignore_error), */ 1859 (Boolean) rule->always_exec, 1860 target, 1861 send_mtool_msgs); 1862 check_state(temp_file_name); 1863 } 1864 SEND_MTOOL_MSG( 1865 append_job_result_msg(job_result_msg); 1866 if (child_pid > 0) { 1867 kill(child_pid, SIGUSR1); 1868 while (!((waitpid(child_pid, 0, 0) == -1) 1869 && (errno == ECHILD))); 1870 } 1871 child_pid = 0; 1872 (void) unlink(stdout_file); 1873 retmem_mb(stdout_file); 1874 stdout_file = NULL; 1875 ); 1876 } else { 1877 result = build_ok; 1878 } 1879 if (result == build_failed) { 1880 if (silent || rule->silent) { 1881 (void) printf(catgets(catd, 1, 242, "The following command caused the error:\n%s\n"), 1882 rule->command_line->string_mb); 1883 SEND_MTOOL_MSG( 1884 job_result_msg->appendOutput(AVO_STRDUP(catgets(catd, 1, 243, "The following command caused the error:"))); 1885 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb)); 1886 ); 1887 } 1888 if (!rule->ignore_error && !ignore_errors) { 1889 if (!continue_after_error) { 1890 SEND_MTOOL_MSG( 1891 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE); 1892 xdr_msg = (RWCollectable*) 1893 job_result_msg; 1894 xdr(&xdrs, xdr_msg); 1895 (void) fflush(mtool_msgs_fp); 1896 delete job_result_msg; 1897 ); 1898 fatal(catgets(catd, 1, 244, "Command failed for target `%s'"), 1899 target->string_mb); 1900 } 1901 /* 1902 * Make sure a failing command is not 1903 * saved in .make.state. 1904 */ 1905 line->body.line.command_used = NULL; 1906 break; 1907 } else { 1908 result = build_ok; 1909 } 1910 } 1911 } 1912 for (rule = command; rule != NULL; rule = cmd_tail) { 1913 cmd_tail = rule->next; 1914 free(rule); 1915 } 1916 command = NULL; 1917 SEND_MTOOL_MSG( 1918 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE); 1919 xdr_msg = (RWCollectable*) job_result_msg; 1920 xdr(&xdrs, xdr_msg); 1921 (void) fflush(mtool_msgs_fp); 1922 1923 delete job_result_msg; 1924 ); 1925 if (temp_file_name != NULL) { 1926 free_name(temp_file_name); 1927 } 1928 temp_file_name = NULL; 1929 1930 Property spro = get_prop(sunpro_dependencies->prop, macro_prop); 1931 if(spro != NULL) { 1932 Name val = spro->body.macro.value; 1933 if(val != NULL) { 1934 free_name(val); 1935 spro->body.macro.value = NULL; 1936 } 1937 } 1938 spro = get_prop(sunpro_dependencies->prop, env_mem_prop); 1939 if(spro) { 1940 char *val = spro->body.env_mem.value; 1941 if(val != NULL) { 1942 /* 1943 * Do not return memory allocated for SUNPRO_DEPENDENCIES 1944 * It will be returned in setvar_daemon() in macro.cc 1945 */ 1946 // retmem_mb(val); 1947 spro->body.env_mem.value = NULL; 1948 } 1949 } 1950 1951 return result; 1952 } 1953 1954 1955 1956 /* 1957 * vpath_translation(cmd) 1958 * 1959 * Translates one command line by 1960 * checking each word. If the word has an alias it is translated. 1961 * 1962 * Return value: 1963 * The translated command 1964 * 1965 * Parameters: 1966 * cmd Command to translate 1967 * 1968 * Global variables used: 1969 */ 1970 Name 1971 vpath_translation(register Name cmd) 1972 { 1973 wchar_t buffer[STRING_BUFFER_LENGTH]; 1974 String_rec new_cmd; 1975 wchar_t *p; 1976 wchar_t *start; 1977 1978 if (!vpath_defined || (cmd == NULL) || (cmd->hash.length == 0)) { 1979 return cmd; 1980 } 1981 INIT_STRING_FROM_STACK(new_cmd, buffer); 1982 1983 Wstring wcb(cmd); 1984 p = wcb.get_string(); 1985 1986 while (*p != (int) nul_char) { 1987 while (iswspace(*p) && (*p != (int) nul_char)) { 1988 append_char(*p++, &new_cmd); 1989 } 1990 start = p; 1991 while (!iswspace(*p) && (*p != (int) nul_char)) { 1992 p++; 1993 } 1994 cmd = GETNAME(start, p - start); 1995 if (cmd->has_vpath_alias_prop) { 1996 cmd = get_prop(cmd->prop, vpath_alias_prop)-> 1997 body.vpath_alias.alias; 1998 APPEND_NAME(cmd, 1999 &new_cmd, 2000 (int) cmd->hash.length); 2001 } else { 2002 append_string(start, &new_cmd, p - start); 2003 } 2004 } 2005 cmd = GETNAME(new_cmd.buffer.start, FIND_LENGTH); 2006 if (new_cmd.free_after_use) { 2007 retmem(new_cmd.buffer.start); 2008 } 2009 return cmd; 2010 } 2011 2012 /* 2013 * check_state(temp_file_name) 2014 * 2015 * Reads and checks the state changed by the previously executed command. 2016 * 2017 * Parameters: 2018 * temp_file_name The auto dependency temp file 2019 * 2020 * Global variables used: 2021 */ 2022 void 2023 check_state(Name temp_file_name) 2024 { 2025 if (!keep_state) { 2026 return; 2027 } 2028 2029 /* 2030 * Then read the temp file that now might 2031 * contain dependency reports from utilities 2032 */ 2033 read_dependency_file(temp_file_name); 2034 2035 /* 2036 * And reread .make.state if it 2037 * changed (the command ran recursive makes) 2038 */ 2039 check_read_state_file(); 2040 if (temp_file_name != NULL) { 2041 (void) unlink(temp_file_name->string_mb); 2042 } 2043 } 2044 2045 /* 2046 * read_dependency_file(filename) 2047 * 2048 * Read the temp file used for reporting dependencies to make 2049 * 2050 * Parameters: 2051 * filename The name of the file with the state info 2052 * 2053 * Global variables used: 2054 * makefile_type The type of makefile being read 2055 * read_trace_level Debug flag 2056 * temp_file_number The always increasing number for unique files 2057 * trace_reader Debug flag 2058 */ 2059 static void 2060 read_dependency_file(register Name filename) 2061 { 2062 register Makefile_type save_makefile_type; 2063 2064 if (filename == NULL) { 2065 return; 2066 } 2067 filename->stat.time = file_no_time; 2068 if (exists(filename) > file_doesnt_exist) { 2069 save_makefile_type = makefile_type; 2070 makefile_type = reading_cpp_file; 2071 if (read_trace_level > 1) { 2072 trace_reader = true; 2073 } 2074 temp_file_number++; 2075 (void) read_simple_file(filename, 2076 false, 2077 false, 2078 false, 2079 false, 2080 false, 2081 false); 2082 trace_reader = false; 2083 makefile_type = save_makefile_type; 2084 } 2085 } 2086 2087 /* 2088 * check_read_state_file() 2089 * 2090 * Check if .make.state has changed 2091 * If it has we reread it 2092 * 2093 * Parameters: 2094 * 2095 * Global variables used: 2096 * make_state Make state file name 2097 * makefile_type Type of makefile being read 2098 * read_trace_level Debug flag 2099 * trace_reader Debug flag 2100 */ 2101 static void 2102 check_read_state_file(void) 2103 { 2104 timestruc_t previous = make_state->stat.time; 2105 register Makefile_type save_makefile_type; 2106 register Property makefile; 2107 2108 make_state->stat.time = file_no_time; 2109 if ((exists(make_state) == file_doesnt_exist) || 2110 (make_state->stat.time == previous)) { 2111 return; 2112 } 2113 save_makefile_type = makefile_type; 2114 makefile_type = rereading_statefile; 2115 /* Make sure we clear the old cached contents of .make.state */ 2116 makefile = maybe_append_prop(make_state, makefile_prop); 2117 if (makefile->body.makefile.contents != NULL) { 2118 retmem(makefile->body.makefile.contents); 2119 makefile->body.makefile.contents = NULL; 2120 } 2121 if (read_trace_level > 1) { 2122 trace_reader = true; 2123 } 2124 temp_file_number++; 2125 (void) read_simple_file(make_state, 2126 false, 2127 false, 2128 false, 2129 false, 2130 false, 2131 true); 2132 trace_reader = false; 2133 makefile_type = save_makefile_type; 2134 } 2135 2136 /* 2137 * do_assign(line, target) 2138 * 2139 * Handles runtime assignments for command lines prefixed with "=". 2140 * 2141 * Parameters: 2142 * line The command that contains an assignment 2143 * target The Name of the target, used for error reports 2144 * 2145 * Global variables used: 2146 * assign_done Set to indicate doname needs to reprocess 2147 */ 2148 static void 2149 do_assign(register Name line, register Name target) 2150 { 2151 Wstring wcb(line); 2152 register wchar_t *string = wcb.get_string(); 2153 register wchar_t *equal; 2154 register Name name; 2155 register Boolean append = false; 2156 2157 /* 2158 * If any runtime assignments are done, doname() must reprocess all 2159 * targets in the future since the macro values used to build the 2160 * command lines for the targets might have changed. 2161 */ 2162 assign_done = true; 2163 /* Skip white space. */ 2164 while (iswspace(*string)) { 2165 string++; 2166 } 2167 equal = string; 2168 /* Find "+=" or "=". */ 2169 while (!iswspace(*equal) && 2170 (*equal != (int) plus_char) && 2171 (*equal != (int) equal_char)) { 2172 equal++; 2173 } 2174 /* Internalize macro name. */ 2175 name = GETNAME(string, equal - string); 2176 /* Skip over "+=" "=". */ 2177 while (!((*equal == (int) nul_char) || 2178 (*equal == (int) equal_char) || 2179 (*equal == (int) plus_char))) { 2180 equal++; 2181 } 2182 switch (*equal) { 2183 case nul_char: 2184 fatal(catgets(catd, 1, 31, "= expected in rule `%s' for target `%s'"), 2185 line->string_mb, 2186 target->string_mb); 2187 case plus_char: 2188 append = true; 2189 equal++; 2190 break; 2191 } 2192 equal++; 2193 /* Skip over whitespace in front of value. */ 2194 while (iswspace(*equal)) { 2195 equal++; 2196 } 2197 /* Enter new macro value. */ 2198 enter_equal(name, 2199 GETNAME(equal, wcb.get_string() + line->hash.length - equal), 2200 append); 2201 } 2202 2203 /* 2204 * build_command_strings(target, line) 2205 * 2206 * Builds the command string to used when 2207 * building a target. If the string is different from the previous one 2208 * is_out_of_date is set. 2209 * 2210 * Parameters: 2211 * target Target to build commands for 2212 * line Where to stuff result 2213 * 2214 * Global variables used: 2215 * c_at The Name "@", used to set macro value 2216 * command_changed Set if command is different from old 2217 * debug_level Should we trace activities? 2218 * do_not_exec_rule Always echo when running -n 2219 * empty_name The Name "", used for empty rule 2220 * funny Semantics of characters 2221 * ignore_errors Used to init field for line 2222 * is_conditional Set to false befor evaling macro, checked 2223 * after expanding macros 2224 * keep_state Indicates that .KEEP_STATE is on 2225 * make_word_mentioned Set by macro eval, inits field for cmd 2226 * query The Name "?", used to set macro value 2227 * query_mentioned Set by macro eval, inits field for cmd 2228 * recursion_level Used for tracing 2229 * silent Used to init field for line 2230 */ 2231 static void 2232 build_command_strings(Name target, register Property line) 2233 { 2234 String_rec command_line; 2235 register Cmd_line command_template = line->body.line.command_template; 2236 register Cmd_line *insert = &line->body.line.command_used; 2237 register Cmd_line used = *insert; 2238 wchar_t buffer[STRING_BUFFER_LENGTH]; 2239 wchar_t *start; 2240 Name new_command_line; 2241 register Boolean new_command_longer = false; 2242 register Boolean ignore_all_command_dependency = true; 2243 Property member; 2244 static Name less_name; 2245 static Name percent_name; 2246 static Name star; 2247 Name tmp_name; 2248 2249 if (less_name == NULL) { 2250 MBSTOWCS(wcs_buffer, "<"); 2251 less_name = GETNAME(wcs_buffer, FIND_LENGTH); 2252 MBSTOWCS(wcs_buffer, "%"); 2253 percent_name = GETNAME(wcs_buffer, FIND_LENGTH); 2254 MBSTOWCS(wcs_buffer, "*"); 2255 star = GETNAME(wcs_buffer, FIND_LENGTH); 2256 } 2257 2258 /* We have to check if a target depends on conditional macros */ 2259 /* Targets that do must be reprocessed by doname() each time around */ 2260 /* since the macro values used when building the target might have */ 2261 /* changed */ 2262 conditional_macro_used = false; 2263 /* If we are building a lib.a(member) target $@ should be bound */ 2264 /* to lib.a */ 2265 if (target->is_member && 2266 ((member = get_prop(target->prop, member_prop)) != NULL)) { 2267 target = member->body.member.library; 2268 } 2269 /* If we are building a "::" help target $@ should be bound to */ 2270 /* the real target name */ 2271 /* A lib.a(member) target is never :: */ 2272 if (target->has_target_prop) { 2273 target = get_prop(target->prop, target_prop)-> 2274 body.target.target; 2275 } 2276 /* Bind the magic macros that make supplies */ 2277 tmp_name = target; 2278 if(tmp_name != NULL) { 2279 if (tmp_name->has_vpath_alias_prop) { 2280 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)-> 2281 body.vpath_alias.alias; 2282 } 2283 } 2284 (void) SETVAR(c_at, tmp_name, false); 2285 2286 tmp_name = line->body.line.star; 2287 if(tmp_name != NULL) { 2288 if (tmp_name->has_vpath_alias_prop) { 2289 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)-> 2290 body.vpath_alias.alias; 2291 } 2292 } 2293 (void) SETVAR(star, tmp_name, false); 2294 2295 tmp_name = line->body.line.less; 2296 if(tmp_name != NULL) { 2297 if (tmp_name->has_vpath_alias_prop) { 2298 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)-> 2299 body.vpath_alias.alias; 2300 } 2301 } 2302 (void) SETVAR(less_name, tmp_name, false); 2303 2304 tmp_name = line->body.line.percent; 2305 if(tmp_name != NULL) { 2306 if (tmp_name->has_vpath_alias_prop) { 2307 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)-> 2308 body.vpath_alias.alias; 2309 } 2310 } 2311 (void) SETVAR(percent_name, tmp_name, false); 2312 2313 /* $? is seldom used and it is expensive to build */ 2314 /* so we store the list form and build the string on demand */ 2315 Chain query_list = NULL; 2316 Chain *query_list_tail = &query_list; 2317 2318 for (Chain ch = line->body.line.query; ch != NULL; ch = ch->next) { 2319 *query_list_tail = ALLOC(Chain); 2320 (*query_list_tail)->name = ch->name; 2321 if ((*query_list_tail)->name->has_vpath_alias_prop) { 2322 (*query_list_tail)->name = 2323 get_prop((*query_list_tail)->name->prop, 2324 vpath_alias_prop)->body.vpath_alias.alias; 2325 } 2326 (*query_list_tail)->next = NULL; 2327 query_list_tail = &(*query_list_tail)->next; 2328 } 2329 (void) setvar_daemon(query, 2330 (Name) query_list, 2331 false, 2332 chain_daemon, 2333 false, 2334 debug_level); 2335 2336 /* build $^ */ 2337 Chain hat_list = NULL; 2338 Chain *hat_list_tail = &hat_list; 2339 2340 for (Dependency dependency = line->body.line.dependencies; 2341 dependency != NULL; 2342 dependency = dependency->next) { 2343 /* skip automatic dependencies */ 2344 if (!dependency->automatic) { 2345 if ((dependency->name != force) && 2346 (dependency->stale == false)) { 2347 *hat_list_tail = ALLOC(Chain); 2348 2349 if (dependency->name->is_member && 2350 (get_prop(dependency->name->prop, member_prop) != NULL)) { 2351 (*hat_list_tail)->name = 2352 get_prop(dependency->name->prop, 2353 member_prop)->body.member.member; 2354 } else { 2355 (*hat_list_tail)->name = dependency->name; 2356 } 2357 2358 if((*hat_list_tail)->name != NULL) { 2359 if ((*hat_list_tail)->name->has_vpath_alias_prop) { 2360 (*hat_list_tail)->name = 2361 get_prop((*hat_list_tail)->name->prop, 2362 vpath_alias_prop)->body.vpath_alias.alias; 2363 } 2364 } 2365 2366 (*hat_list_tail)->next = NULL; 2367 hat_list_tail = &(*hat_list_tail)->next; 2368 } 2369 } 2370 } 2371 (void) setvar_daemon(hat, 2372 (Name) hat_list, 2373 false, 2374 chain_daemon, 2375 false, 2376 debug_level); 2377 2378 /* We have two command sequences we need to handle */ 2379 /* The old one that we probably read from .make.state */ 2380 /* and the new one we are building that will replace the old one */ 2381 /* Even when KEEP_STATE is not on we build a new command sequence and store */ 2382 /* it in the line prop. This command sequence is then executed by */ 2383 /* run_command(). If KEEP_STATE is on it is also later written to */ 2384 /* .make.state. The routine replaces the old command line by line with the */ 2385 /* new one trying to reuse Cmd_lines */ 2386 2387 /* If there is no old command_used we have to start creating */ 2388 /* Cmd_lines to keep the new cmd in */ 2389 if (used == NULL) { 2390 new_command_longer = true; 2391 *insert = used = ALLOC(Cmd_line); 2392 used->next = NULL; 2393 used->command_line = NULL; 2394 insert = &used->next; 2395 } 2396 /* Run thru the template for the new command and build the expanded */ 2397 /* new command lines */ 2398 for (; 2399 command_template != NULL; 2400 command_template = command_template->next, insert = &used->next, used = *insert) { 2401 /* If there is no old command_used Cmd_line we need to */ 2402 /* create one and say that cmd consistency failed */ 2403 if (used == NULL) { 2404 new_command_longer = true; 2405 *insert = used = ALLOC(Cmd_line); 2406 used->next = NULL; 2407 used->command_line = empty_name; 2408 } 2409 /* Prepare the Cmd_line for the processing */ 2410 /* The command line prefixes "@-=?" are stripped and that */ 2411 /* information is saved in the Cmd_line */ 2412 used->assign = false; 2413 used->ignore_error = ignore_errors; 2414 used->silent = silent; 2415 used->always_exec = false; 2416 /* Expand the macros in the command line */ 2417 INIT_STRING_FROM_STACK(command_line, buffer); 2418 make_word_mentioned = 2419 query_mentioned = 2420 false; 2421 expand_value(command_template->command_line, &command_line, true); 2422 /* If the macro $(MAKE) is mentioned in the command */ 2423 /* "make -n" runs actually execute the command */ 2424 used->make_refd = make_word_mentioned; 2425 used->ignore_command_dependency = query_mentioned; 2426 /* Strip the prefixes */ 2427 start = command_line.buffer.start; 2428 for (; 2429 iswspace(*start) || 2430 (get_char_semantics_value(*start) & (int) command_prefix_sem); 2431 start++) { 2432 switch (*start) { 2433 case question_char: 2434 used->ignore_command_dependency = true; 2435 break; 2436 case exclam_char: 2437 used->ignore_command_dependency = false; 2438 break; 2439 case equal_char: 2440 used->assign = true; 2441 break; 2442 case hyphen_char: 2443 used->ignore_error = true; 2444 break; 2445 case at_char: 2446 if (!do_not_exec_rule) { 2447 used->silent = true; 2448 } 2449 break; 2450 case plus_char: 2451 if(posix) { 2452 used->always_exec = true; 2453 } 2454 break; 2455 } 2456 } 2457 /* If all command lines of the template are prefixed with "?"*/ 2458 /* the VIRTUAL_ROOT is not used for cmd consistency checks */ 2459 if (!used->ignore_command_dependency) { 2460 ignore_all_command_dependency = false; 2461 } 2462 /* Internalize the expanded and stripped command line */ 2463 new_command_line = GETNAME(start, FIND_LENGTH); 2464 if ((used->command_line == NULL) && 2465 (line->body.line.sccs_command)) { 2466 used->command_line = new_command_line; 2467 new_command_longer = false; 2468 } 2469 /* Compare it with the old one for command consistency */ 2470 if (used->command_line != new_command_line) { 2471 Name vpath_translated = vpath_translation(new_command_line); 2472 if (keep_state && 2473 !used->ignore_command_dependency && (vpath_translated != used->command_line)) { 2474 if (debug_level > 0) { 2475 if (used->command_line != NULL 2476 && *used->command_line->string_mb != 2477 '\0') { 2478 (void) printf(catgets(catd, 1, 32, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from old\n\t%s\n"), 2479 recursion_level, 2480 "", 2481 target->string_mb, 2482 vpath_translated->string_mb, 2483 recursion_level, 2484 "", 2485 used-> 2486 command_line-> 2487 string_mb); 2488 } else { 2489 (void) printf(catgets(catd, 1, 33, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from empty old command\n"), 2490 recursion_level, 2491 "", 2492 target->string_mb, 2493 vpath_translated->string_mb, 2494 recursion_level, 2495 ""); 2496 } 2497 } 2498 command_changed = true; 2499 line->body.line.is_out_of_date = true; 2500 } 2501 used->command_line = new_command_line; 2502 } 2503 if (command_line.free_after_use) { 2504 retmem(command_line.buffer.start); 2505 } 2506 } 2507 /* Check if the old command is longer than the new for */ 2508 /* command consistency */ 2509 if (used != NULL) { 2510 *insert = NULL; 2511 if (keep_state && 2512 !ignore_all_command_dependency) { 2513 if (debug_level > 0) { 2514 (void) printf(catgets(catd, 1, 34, "%*sBuilding %s because new command shorter than old\n"), 2515 recursion_level, 2516 "", 2517 target->string_mb); 2518 } 2519 command_changed = true; 2520 line->body.line.is_out_of_date = true; 2521 } 2522 } 2523 /* Check if the new command is longer than the old command for */ 2524 /* command consistency */ 2525 if (new_command_longer && 2526 !ignore_all_command_dependency && 2527 keep_state) { 2528 if (debug_level > 0) { 2529 (void) printf(catgets(catd, 1, 35, "%*sBuilding %s because new command longer than old\n"), 2530 recursion_level, 2531 "", 2532 target->string_mb); 2533 } 2534 command_changed = true; 2535 line->body.line.is_out_of_date = true; 2536 } 2537 /* Unbind the magic macros */ 2538 (void) SETVAR(c_at, (Name) NULL, false); 2539 (void) SETVAR(star, (Name) NULL, false); 2540 (void) SETVAR(less_name, (Name) NULL, false); 2541 (void) SETVAR(percent_name, (Name) NULL, false); 2542 (void) SETVAR(query, (Name) NULL, false); 2543 if (query_list != NULL) { 2544 delete_query_chain(query_list); 2545 } 2546 (void) SETVAR(hat, (Name) NULL, false); 2547 if (hat_list != NULL) { 2548 delete_query_chain(hat_list); 2549 } 2550 2551 if (conditional_macro_used) { 2552 target->conditional_macro_list = cond_macro_list; 2553 cond_macro_list = NULL; 2554 target->depends_on_conditional = true; 2555 } 2556 } 2557 2558 /* 2559 * touch_command(line, target, result) 2560 * 2561 * If this is an "make -t" run we do this. 2562 * We touch all targets in the target group ("foo + fie:") if any. 2563 * 2564 * Return value: 2565 * Indicates if the command failed or not 2566 * 2567 * Parameters: 2568 * line The command line to update 2569 * target The target we are touching 2570 * result Initial value for the result we return 2571 * 2572 * Global variables used: 2573 * do_not_exec_rule Indicates that -n is on 2574 * silent Do not echo commands 2575 */ 2576 static Doname 2577 touch_command(register Property line, register Name target, Doname result) 2578 { 2579 Name name; 2580 register Chain target_group; 2581 String_rec touch_string; 2582 wchar_t buffer[MAXPATHLEN]; 2583 Name touch_cmd; 2584 Cmd_line rule; 2585 2586 2587 SEND_MTOOL_MSG( 2588 if (!sent_rsrc_info_msg) { 2589 if (userName[0] == '\0') { 2590 avo_get_user(userName, NULL); 2591 } 2592 if (hostName[0] == '\0') { 2593 strcpy(hostName, avo_hostname()); 2594 } 2595 send_rsrc_info_msg(1, hostName, userName); 2596 sent_rsrc_info_msg = 1; 2597 } 2598 send_job_start_msg(line); 2599 job_result_msg = new Avo_MToolJobResultMsg(); 2600 ); 2601 for (name = target, target_group = NULL; name != NULL;) { 2602 if (!name->is_member) { 2603 /* 2604 * Build a touch command that can be passed 2605 * to dosys(). If KEEP_STATE is on, "make -t" 2606 * will save the proper command, not the 2607 * "touch" in .make.state. 2608 */ 2609 INIT_STRING_FROM_STACK(touch_string, buffer); 2610 MBSTOWCS(wcs_buffer, NOCATGETS("touch ")); 2611 append_string(wcs_buffer, &touch_string, FIND_LENGTH); 2612 touch_cmd = name; 2613 if (name->has_vpath_alias_prop) { 2614 touch_cmd = get_prop(name->prop, 2615 vpath_alias_prop)-> 2616 body.vpath_alias.alias; 2617 } 2618 APPEND_NAME(touch_cmd, 2619 &touch_string, 2620 FIND_LENGTH); 2621 touch_cmd = GETNAME(touch_string.buffer.start, 2622 FIND_LENGTH); 2623 if (touch_string.free_after_use) { 2624 retmem(touch_string.buffer.start); 2625 } 2626 if (!silent || 2627 do_not_exec_rule && 2628 (target_group == NULL)) { 2629 (void) printf("%s\n", touch_cmd->string_mb); 2630 SEND_MTOOL_MSG( 2631 job_result_msg->appendOutput(AVO_STRDUP(touch_cmd->string_mb)); 2632 ); 2633 } 2634 /* Run the touch command, or simulate it */ 2635 if (!do_not_exec_rule) { 2636 2637 SEND_MTOOL_MSG( 2638 (void) sprintf(mbstring, 2639 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"), 2640 tmpdir, 2641 getpid(), 2642 file_number++); 2643 2644 int tmp_fd = mkstemp(mbstring); 2645 if(tmp_fd) { 2646 (void) close(tmp_fd); 2647 } 2648 2649 stdout_file = strdup(mbstring); 2650 stderr_file = NULL; 2651 child_pid = pollResults(stdout_file, 2652 (char *)NULL, 2653 (char *)NULL); 2654 ); 2655 2656 result = dosys(touch_cmd, 2657 false, 2658 false, 2659 false, 2660 false, 2661 name, 2662 send_mtool_msgs); 2663 2664 SEND_MTOOL_MSG( 2665 append_job_result_msg(job_result_msg); 2666 if (child_pid > 0) { 2667 kill(child_pid, SIGUSR1); 2668 while (!((waitpid(child_pid, 0, 0) == -1) 2669 && (errno == ECHILD))); 2670 } 2671 child_pid = 0; 2672 (void) unlink(stdout_file); 2673 retmem_mb(stdout_file); 2674 stdout_file = NULL; 2675 ); 2676 2677 } else { 2678 result = build_ok; 2679 } 2680 } else { 2681 result = build_ok; 2682 } 2683 if (target_group == NULL) { 2684 target_group = line->body.line.target_group; 2685 } else { 2686 target_group = target_group->next; 2687 } 2688 if (target_group != NULL) { 2689 name = target_group->name; 2690 } else { 2691 name = NULL; 2692 } 2693 } 2694 SEND_MTOOL_MSG( 2695 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE); 2696 xdr_msg = (RWCollectable*) job_result_msg; 2697 xdr(&xdrs, xdr_msg); 2698 (void) fflush(mtool_msgs_fp); 2699 delete job_result_msg; 2700 ); 2701 return result; 2702 } 2703 2704 /* 2705 * update_target(line, result) 2706 * 2707 * updates the status of a target after executing its commands. 2708 * 2709 * Parameters: 2710 * line The command line block to update 2711 * result Indicates that build is OK so can update 2712 * 2713 * Global variables used: 2714 * do_not_exec_rule Indicates that -n is on 2715 * touch Fake the new timestamp if we are just touching 2716 */ 2717 void 2718 update_target(Property line, Doname result) 2719 { 2720 Name target; 2721 Chain target_group; 2722 Property line2; 2723 timestruc_t old_stat_time; 2724 Property member; 2725 2726 /* 2727 * [tolik] Additional fix for bug 1063790. It was fixed 2728 * for serial make long ago, but DMake dumps core when 2729 * target is a symlink and sccs file is newer then target. 2730 * In this case, finish_children() calls update_target() 2731 * with line==NULL. 2732 */ 2733 if(line == NULL) { 2734 /* XXX. Should we do anything here? */ 2735 return; 2736 } 2737 2738 target = line->body.line.target; 2739 2740 if ((result == build_ok) && (line->body.line.command_used != NULL)) { 2741 if (do_not_exec_rule || 2742 touch || 2743 (target->is_member && 2744 (line->body.line.command_template != NULL) && 2745 (line->body.line.command_template->command_line->string_mb[0] == 0) && 2746 (line->body.line.command_template->next == NULL))) { 2747 /* If we are simulating execution we need to fake a */ 2748 /* new timestamp for the target we didnt build */ 2749 target->stat.time = file_max_time; 2750 } else { 2751 /* 2752 * If we really built the target we read the new 2753 * timestamp. 2754 * Fix for bug #1110906: if .c file is newer than 2755 * the corresponding .o file which is in an archive 2756 * file, make will compile the .c file but it won't 2757 * update the object in the .a file. 2758 */ 2759 old_stat_time = target->stat.time; 2760 target->stat.time = file_no_time; 2761 (void) exists(target); 2762 if ((target->is_member) && 2763 (target->stat.time == old_stat_time)) { 2764 member = get_prop(target->prop, member_prop); 2765 if (member != NULL) { 2766 target->stat.time = member->body.member.library->stat.time; 2767 target->stat.time.tv_sec++; 2768 } 2769 } 2770 } 2771 /* If the target is part of a group we need to propagate the */ 2772 /* result of the run to all members */ 2773 for (target_group = line->body.line.target_group; 2774 target_group != NULL; 2775 target_group = target_group->next) { 2776 target_group->name->stat.time = target->stat.time; 2777 line2 = maybe_append_prop(target_group->name, 2778 line_prop); 2779 line2->body.line.command_used = 2780 line->body.line.command_used; 2781 line2->body.line.target = target_group->name; 2782 } 2783 } 2784 target->has_built = true; 2785 } 2786 2787 /* 2788 * sccs_get(target, command) 2789 * 2790 * Figures out if it possible to sccs get a file 2791 * and builds the command to do it if it is. 2792 * 2793 * Return value: 2794 * Indicates if sccs get failed or not 2795 * 2796 * Parameters: 2797 * target Target to get 2798 * command Where to deposit command to use 2799 * 2800 * Global variables used: 2801 * debug_level Should we trace activities? 2802 * recursion_level Used for tracing 2803 * sccs_get_rule The rule to used for sccs getting 2804 */ 2805 static Doname 2806 sccs_get(register Name target, register Property *command) 2807 { 2808 register int result; 2809 char link[MAXPATHLEN]; 2810 String_rec string; 2811 wchar_t name[MAXPATHLEN]; 2812 register wchar_t *p; 2813 timestruc_t sccs_time; 2814 register Property line; 2815 int sym_link_depth = 0; 2816 2817 /* For sccs, we need to chase symlinks. */ 2818 while (target->stat.is_sym_link) { 2819 if (sym_link_depth++ > 90) { 2820 fatal(catgets(catd, 1, 95, "Can't read symbolic link `%s': Number of symbolic links encountered during path name traversal exceeds 90."), 2821 target->string_mb); 2822 } 2823 /* Read the value of the link. */ 2824 result = readlink_vroot(target->string_mb, 2825 link, 2826 sizeof(link), 2827 NULL, 2828 VROOT_DEFAULT); 2829 if (result == -1) { 2830 fatal(catgets(catd, 1, 36, "Can't read symbolic link `%s': %s"), 2831 target->string_mb, errmsg(errno)); 2832 } 2833 link[result] = 0; 2834 /* Use the value to build the proper filename. */ 2835 INIT_STRING_FROM_STACK(string, name); 2836 2837 Wstring wcb(target); 2838 if ((link[0] != slash_char) && 2839 ((p = (wchar_t *) wsrchr(wcb.get_string(), slash_char)) != NULL)) { 2840 append_string(wcb.get_string(), &string, p - wcb.get_string() + 1); 2841 } 2842 append_string(link, &string, result); 2843 /* Replace the old name with the translated name. */ 2844 target = normalize_name(string.buffer.start, string.text.p - string.buffer.start); 2845 (void) exists(target); 2846 if (string.free_after_use) { 2847 retmem(string.buffer.start); 2848 } 2849 } 2850 2851 /* 2852 * read_dir() also reads the ?/SCCS dir and saves information 2853 * about which files have SCSC/s. files. 2854 */ 2855 if (target->stat.has_sccs == DONT_KNOW_SCCS) { 2856 read_directory_of_file(target); 2857 } 2858 switch (target->stat.has_sccs) { 2859 case DONT_KNOW_SCCS: 2860 /* We dont know by now there is no SCCS/s.* */ 2861 target->stat.has_sccs = NO_SCCS; 2862 case NO_SCCS: 2863 /* 2864 * If there is no SCCS/s.* but the plain file exists, 2865 * we say things are OK. 2866 */ 2867 if (target->stat.time > file_doesnt_exist) { 2868 return build_ok; 2869 } 2870 /* If we cant find the plain file, we give up. */ 2871 return build_dont_know; 2872 case HAS_SCCS: 2873 /* 2874 * Pay dirt. We now need to figure out if the plain file 2875 * is out of date relative to the SCCS/s.* file. 2876 */ 2877 sccs_time = exists(get_prop(target->prop, 2878 sccs_prop)->body.sccs.file); 2879 break; 2880 } 2881 2882 if ((!target->has_complained && 2883 (sccs_time != file_doesnt_exist) && 2884 (sccs_get_rule != NULL))) { 2885 /* only checking */ 2886 if (command == NULL) { 2887 return build_ok; 2888 } 2889 /* 2890 * We provide a command line for the target. The line is a 2891 * "sccs get" command from default.mk. 2892 */ 2893 line = maybe_append_prop(target, line_prop); 2894 *command = line; 2895 if (sccs_time > target->stat.time) { 2896 /* 2897 * And only if the plain file is out of date do we 2898 * request execution of the command. 2899 */ 2900 line->body.line.is_out_of_date = true; 2901 if (debug_level > 0) { 2902 (void) printf(catgets(catd, 1, 37, "%*sSccs getting %s because s. file is younger than source file\n"), 2903 recursion_level, 2904 "", 2905 target->string_mb); 2906 } 2907 } 2908 line->body.line.sccs_command = true; 2909 line->body.line.command_template = sccs_get_rule; 2910 if(!svr4 && (!allrules_read || posix)) { 2911 if((target->prop) && 2912 (target->prop->body.sccs.file) && 2913 (target->prop->body.sccs.file->string_mb)) { 2914 if((strlen(target->prop->body.sccs.file->string_mb) == 2915 strlen(target->string_mb) + 2) && 2916 (target->prop->body.sccs.file->string_mb[0] == 's') && 2917 (target->prop->body.sccs.file->string_mb[1] == '.')) { 2918 2919 line->body.line.command_template = get_posix_rule; 2920 } 2921 } 2922 } 2923 line->body.line.target = target; 2924 /* 2925 * Also make sure the rule is build with $* and $< 2926 * bound properly. 2927 */ 2928 line->body.line.star = NULL; 2929 line->body.line.less = NULL; 2930 line->body.line.percent = NULL; 2931 return build_ok; 2932 } 2933 return build_dont_know; 2934 } 2935 2936 /* 2937 * read_directory_of_file(file) 2938 * 2939 * Reads the directory the specified file lives in. 2940 * 2941 * Parameters: 2942 * file The file we need to read dir for 2943 * 2944 * Global variables used: 2945 * dot The Name ".", used as the default dir 2946 */ 2947 void 2948 read_directory_of_file(register Name file) 2949 { 2950 2951 Wstring file_string(file); 2952 wchar_t * wcb = file_string.get_string(); 2953 wchar_t usr_include_buf[MAXPATHLEN]; 2954 wchar_t usr_include_sys_buf[MAXPATHLEN]; 2955 2956 register Name directory = dot; 2957 register wchar_t *p = (wchar_t *) wsrchr(wcb, 2958 (int) slash_char); 2959 register int length = p - wcb; 2960 static Name usr_include; 2961 static Name usr_include_sys; 2962 2963 if (usr_include == NULL) { 2964 MBSTOWCS(usr_include_buf, NOCATGETS("/usr/include")); 2965 usr_include = GETNAME(usr_include_buf, FIND_LENGTH); 2966 MBSTOWCS(usr_include_sys_buf, NOCATGETS("/usr/include/sys")); 2967 usr_include_sys = GETNAME(usr_include_sys_buf, FIND_LENGTH); 2968 } 2969 2970 /* 2971 * If the filename contains a "/" we have to extract the path 2972 * Else the path defaults to ".". 2973 */ 2974 if (p != NULL) { 2975 /* 2976 * Check some popular directories first to possibly 2977 * save time. Compare string length first to gain speed. 2978 */ 2979 if ((usr_include->hash.length == length) && 2980 IS_WEQUALN(usr_include_buf, 2981 wcb, 2982 length)) { 2983 directory = usr_include; 2984 } else if ((usr_include_sys->hash.length == length) && 2985 IS_WEQUALN(usr_include_sys_buf, 2986 wcb, 2987 length)) { 2988 directory = usr_include_sys; 2989 } else { 2990 directory = GETNAME(wcb, length); 2991 } 2992 } 2993 (void) read_dir(directory, 2994 (wchar_t *) NULL, 2995 (Property) NULL, 2996 (wchar_t *) NULL); 2997 } 2998 2999 /* 3000 * add_pattern_conditionals(target) 3001 * 3002 * Scan the list of conditionals defined for pattern targets and add any 3003 * that match this target to its list of conditionals. 3004 * 3005 * Parameters: 3006 * target The target we should add conditionals for 3007 * 3008 * Global variables used: 3009 * conditionals The list of pattern conditionals 3010 */ 3011 static void 3012 add_pattern_conditionals(register Name target) 3013 { 3014 register Property conditional; 3015 Property new_prop; 3016 Property *previous; 3017 Name_rec dummy; 3018 wchar_t *pattern; 3019 wchar_t *percent; 3020 int length; 3021 3022 Wstring wcb(target); 3023 Wstring wcb1; 3024 3025 for (conditional = get_prop(conditionals->prop, conditional_prop); 3026 conditional != NULL; 3027 conditional = get_prop(conditional->next, conditional_prop)) { 3028 wcb1.init(conditional->body.conditional.target); 3029 pattern = wcb1.get_string(); 3030 if (pattern[1] != 0) { 3031 percent = (wchar_t *) wschr(pattern, (int) percent_char); 3032 if (!wcb.equaln(pattern, percent-pattern) || 3033 !IS_WEQUAL(wcb.get_string(wcb.length()-wslen(percent+1)), percent+1)) { 3034 continue; 3035 } 3036 } 3037 for (previous = &target->prop; 3038 *previous != NULL; 3039 previous = &(*previous)->next) { 3040 if (((*previous)->type == conditional_prop) && 3041 ((*previous)->body.conditional.sequence > 3042 conditional->body.conditional.sequence)) { 3043 break; 3044 } 3045 } 3046 if (*previous == NULL) { 3047 new_prop = append_prop(target, conditional_prop); 3048 } else { 3049 dummy.prop = NULL; 3050 new_prop = append_prop(&dummy, conditional_prop); 3051 new_prop->next = *previous; 3052 *previous = new_prop; 3053 } 3054 target->conditional_cnt++; 3055 new_prop->body.conditional = conditional->body.conditional; 3056 } 3057 } 3058 3059 /* 3060 * set_locals(target, old_locals) 3061 * 3062 * Sets any conditional macros for the target. 3063 * Each target carries a possibly empty set of conditional properties. 3064 * 3065 * Parameters: 3066 * target The target to set conditional macros for 3067 * old_locals Space to store old values in 3068 * 3069 * Global variables used: 3070 * debug_level Should we trace activity? 3071 * is_conditional We need to preserve this value 3072 * recursion_level Used for tracing 3073 */ 3074 void 3075 set_locals(register Name target, register Property old_locals) 3076 { 3077 register Property conditional; 3078 register int i; 3079 register Boolean saved_conditional_macro_used; 3080 Chain cond_name; 3081 Chain cond_chain; 3082 3083 if (target->dont_activate_cond_values) { 3084 return; 3085 } 3086 3087 saved_conditional_macro_used = conditional_macro_used; 3088 3089 /* Scan the list of conditional properties and apply each one */ 3090 for (conditional = get_prop(target->prop, conditional_prop), i = 0; 3091 conditional != NULL; 3092 conditional = get_prop(conditional->next, conditional_prop), 3093 i++) { 3094 /* Save the old value */ 3095 old_locals[i].body.macro = 3096 maybe_append_prop(conditional->body.conditional.name, 3097 macro_prop)->body.macro; 3098 if (debug_level > 1) { 3099 (void) printf(catgets(catd, 1, 38, "%*sActivating conditional value: "), 3100 recursion_level, 3101 ""); 3102 } 3103 /* Set the conditional value. Macros are expanded when the */ 3104 /* macro is refd as usual */ 3105 if ((conditional->body.conditional.name != virtual_root) || 3106 (conditional->body.conditional.value != virtual_root)) { 3107 (void) SETVAR(conditional->body.conditional.name, 3108 conditional->body.conditional.value, 3109 (Boolean) conditional->body.conditional.append); 3110 } 3111 cond_name = ALLOC(Chain); 3112 cond_name->name = conditional->body.conditional.name; 3113 } 3114 /* Put this target on the front of the chain of conditional targets */ 3115 cond_chain = ALLOC(Chain); 3116 cond_chain->name = target; 3117 cond_chain->next = conditional_targets; 3118 conditional_targets = cond_chain; 3119 conditional_macro_used = saved_conditional_macro_used; 3120 } 3121 3122 /* 3123 * reset_locals(target, old_locals, conditional, index) 3124 * 3125 * Removes any conditional macros for the target. 3126 * 3127 * Parameters: 3128 * target The target we are retoring values for 3129 * old_locals The values to restore 3130 * conditional The first conditional block for the target 3131 * index into the old_locals vector 3132 * Global variables used: 3133 * debug_level Should we trace activities? 3134 * recursion_level Used for tracing 3135 */ 3136 void 3137 reset_locals(register Name target, register Property old_locals, register Property conditional, register int index) 3138 { 3139 register Property this_conditional; 3140 Chain cond_chain; 3141 3142 if (target->dont_activate_cond_values) { 3143 return; 3144 } 3145 3146 /* Scan the list of conditional properties and restore the old value */ 3147 /* to each one Reverse the order relative to when we assigned macros */ 3148 this_conditional = get_prop(conditional->next, conditional_prop); 3149 if (this_conditional != NULL) { 3150 reset_locals(target, old_locals, this_conditional, index+1); 3151 } else { 3152 /* Remove conditional target from chain */ 3153 if (conditional_targets == NULL || 3154 conditional_targets->name != target) { 3155 warning(catgets(catd, 1, 39, "Internal error: reset target not at head of condtional_targets chain")); 3156 } else { 3157 cond_chain = conditional_targets->next; 3158 retmem_mb((caddr_t) conditional_targets); 3159 conditional_targets = cond_chain; 3160 } 3161 } 3162 get_prop(conditional->body.conditional.name->prop, 3163 macro_prop)->body.macro = old_locals[index].body.macro; 3164 if (conditional->body.conditional.name == virtual_root) { 3165 (void) SETVAR(virtual_root, getvar(virtual_root), false); 3166 } 3167 if (debug_level > 1) { 3168 if (old_locals[index].body.macro.value != NULL) { 3169 (void) printf(catgets(catd, 1, 40, "%*sdeactivating conditional value: %s= %s\n"), 3170 recursion_level, 3171 "", 3172 conditional->body.conditional.name-> 3173 string_mb, 3174 old_locals[index].body.macro.value-> 3175 string_mb); 3176 } else { 3177 (void) printf(catgets(catd, 1, 41, "%*sdeactivating conditional value: %s =\n"), 3178 recursion_level, 3179 "", 3180 conditional->body.conditional.name-> 3181 string_mb); 3182 } 3183 } 3184 } 3185 3186 /* 3187 * check_auto_dependencies(target, auto_count, automatics) 3188 * 3189 * Returns true if the target now has a dependency 3190 * it didn't previously have (saved on automatics). 3191 * 3192 * Return value: 3193 * true if new dependency found 3194 * 3195 * Parameters: 3196 * target Target we check 3197 * auto_count Number of old automatic vars 3198 * automatics Saved old automatics 3199 * 3200 * Global variables used: 3201 * keep_state Indicates that .KEEP_STATE is on 3202 */ 3203 Boolean 3204 check_auto_dependencies(Name target, int auto_count, Name *automatics) 3205 { 3206 Name *p; 3207 int n; 3208 Property line; 3209 Dependency dependency; 3210 3211 if (keep_state) { 3212 if ((line = get_prop(target->prop, line_prop)) == NULL) { 3213 return false; 3214 } 3215 /* Go thru new list of automatic depes */ 3216 for (dependency = line->body.line.dependencies; 3217 dependency != NULL; 3218 dependency = dependency->next) { 3219 /* And make sure that each one existed before we */ 3220 /* built the target */ 3221 if (dependency->automatic && !dependency->stale) { 3222 for (n = auto_count, p = automatics; 3223 n > 0; 3224 n--) { 3225 if (*p++ == dependency->name) { 3226 /* If we can find it on the */ 3227 /* saved list of autos we */ 3228 /* are OK */ 3229 goto not_new; 3230 } 3231 } 3232 /* But if we scan over the old list */ 3233 /* of auto. without finding it it is */ 3234 /* new and we must check it */ 3235 return true; 3236 } 3237 not_new:; 3238 } 3239 return false; 3240 } else { 3241 return false; 3242 } 3243 } 3244 3245 3246 // Recursively delete each of the Chain struct on the chain. 3247 3248 static void 3249 delete_query_chain(Chain ch) 3250 { 3251 if (ch == NULL) { 3252 return; 3253 } else { 3254 delete_query_chain(ch->next); 3255 retmem_mb((char *) ch); 3256 } 3257 } 3258 3259 Doname 3260 target_can_be_built(register Name target) { 3261 Doname result = build_dont_know; 3262 Name true_target = target; 3263 Property line; 3264 3265 if (target == wait_name) { 3266 return(build_ok); 3267 } 3268 /* 3269 * If the target is a constructed one for a "::" target, 3270 * we need to consider that. 3271 */ 3272 if (target->has_target_prop) { 3273 true_target = get_prop(target->prop, 3274 target_prop)->body.target.target; 3275 } 3276 3277 (void) exists(true_target); 3278 3279 if (true_target->state == build_running) { 3280 return(build_running); 3281 } 3282 if (true_target->stat.time != file_doesnt_exist) { 3283 result = build_ok; 3284 } 3285 3286 /* get line property for the target */ 3287 line = get_prop(true_target->prop, line_prop); 3288 3289 /* first check for explicit rule */ 3290 if (line != NULL && line->body.line.command_template != NULL) { 3291 result = build_ok; 3292 } 3293 /* try to find pattern rule */ 3294 if (result == build_dont_know) { 3295 result = find_percent_rule(target, NULL, false); 3296 } 3297 3298 /* try to find double suffix rule */ 3299 if (result == build_dont_know) { 3300 if (target->is_member) { 3301 Property member = get_prop(target->prop, member_prop); 3302 if (member != NULL && member->body.member.member != NULL) { 3303 result = find_ar_suffix_rule(target, member->body.member.member, NULL, false); 3304 } else { 3305 result = find_double_suffix_rule(target, NULL, false); 3306 } 3307 } else { 3308 result = find_double_suffix_rule(target, NULL, false); 3309 } 3310 } 3311 3312 /* try to find suffix rule */ 3313 if ((result == build_dont_know) && second_pass) { 3314 result = find_suffix_rule(target, target, empty_name, NULL, false); 3315 } 3316 3317 /* check for sccs */ 3318 if (result == build_dont_know) { 3319 result = sccs_get(target, NULL); 3320 } 3321 3322 /* try to find dyn target */ 3323 if (result == build_dont_know) { 3324 Name dtarg = find_dyntarget(target); 3325 if (dtarg != NULL) { 3326 result = target_can_be_built(dtarg); 3327 } 3328 } 3329 3330 /* check whether target was mentioned in makefile */ 3331 if (result == build_dont_know) { 3332 if (target->colons != no_colon) { 3333 result = build_ok; 3334 } 3335 } 3336 3337 /* result */ 3338 return result; 3339 }