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 { 973 timestruc_t depe_time = file_doesnt_exist; 974 975 976 if (true_target->is_member) { 977 depe_time = exists(dependency->name); 978 } 979 if (dependency->built || 980 (dependency->name->state == build_failed)) { 981 dep_result = (Doname) dependency->name->state; 982 } else { 983 dep_result = doname_check(dependency->name, 984 do_get, 985 false, 986 (Boolean) dependency->automatic); 987 } 988 if (true_target->is_member || dependency->name->is_member) { 989 /* should compare only secs, cause lib members does not have nsec time resolution */ 990 if (depe_time.tv_sec != dependency->name->stat.time.tv_sec) { 991 this_dependency_changed = 992 dependency_changed = 993 true; 994 } 995 } else { 996 if (depe_time != dependency->name->stat.time) { 997 this_dependency_changed = 998 dependency_changed = 999 true; 1000 } 1001 } 1002 dependency->built = true; 1003 switch (dep_result) { 1004 case build_running: 1005 dependencies_running = true; 1006 continue; 1007 case build_failed: 1008 *result = build_failed; 1009 break; 1010 case build_dont_know: 1011 /* 1012 * If make can't figure out how to make a dependency, maybe the dependency 1013 * is out of date. In this case, we just declare the target out of date 1014 * and go on. If we really need the dependency, the make'ing of the target 1015 * will fail. This will only happen for automatic (hidden) dependencies. 1016 */ 1017 if(!recheck_conditionals) { 1018 line->body.line.is_out_of_date = true; 1019 } 1020 /* 1021 * Make sure the dependency is not saved 1022 * in the state file. 1023 */ 1024 dependency->stale = true; 1025 rewrite_statefile = 1026 command_changed = 1027 true; 1028 if (debug_level > 0) { 1029 (void) printf(catgets(catd, 1, 19, "Target %s rebuilt because dependency %s does not exist\n"), 1030 true_target->string_mb, 1031 dependency->name->string_mb); 1032 } 1033 break; 1034 } 1035 if (dependency->name->depends_on_conditional) { 1036 target->depends_on_conditional = true; 1037 } 1038 if (dependency->name == force) { 1039 target->stat.time = 1040 dependency->name->stat.time; 1041 } 1042 /* 1043 * Propagate new timestamp from "member" to 1044 * "lib.a(member)". 1045 */ 1046 (void) exists(dependency->name); 1047 1048 /* Collect the timestamp of the youngest dependency */ 1049 line->body.line.dependency_time = 1050 MAX(dependency->name->stat.time, 1051 line->body.line.dependency_time); 1052 1053 /* Correction: do not consider nanosecs for members */ 1054 if(true_target->is_member || dependency->name->is_member) { 1055 line->body.line.dependency_time.tv_nsec = 0; 1056 } 1057 1058 if (debug_level > 1) { 1059 (void) printf(catgets(catd, 1, 20, "%*sDate(%s)=%s \n"), 1060 recursion_level, 1061 "", 1062 dependency->name->string_mb, 1063 time_to_string(dependency->name-> 1064 stat.time)); 1065 if (dependency->name->stat.time > line->body.line.dependency_time) { 1066 (void) printf(catgets(catd, 1, 21, "%*sDate-dependencies(%s) set to %s\n"), 1067 recursion_level, 1068 "", 1069 true_target->string_mb, 1070 time_to_string(line->body.line. 1071 dependency_time)); 1072 } 1073 } 1074 1075 /* Build the $? list */ 1076 if (true_target->is_member) { 1077 if (this_dependency_changed == true) { 1078 true_target->stat.time = dependency->name->stat.time; 1079 true_target->stat.time.tv_sec--; 1080 } else { 1081 /* Dina: 1082 * The next statement is commented 1083 * out as a fix for bug #1051032. 1084 * if dependency hasn't changed 1085 * then there's no need to invalidate 1086 * true_target. This statemnt causes 1087 * make to take much longer to process 1088 * an already-built archive. Soren 1089 * said it was a quick fix for some 1090 * problem he doesn't remember. 1091 true_target->stat.time = file_no_time; 1092 */ 1093 (void) exists(true_target); 1094 } 1095 } else { 1096 (void) exists(true_target); 1097 } 1098 Boolean out_of_date; 1099 if (true_target->is_member || dependency->name->is_member) { 1100 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time, 1101 dependency->name->stat.time); 1102 } else { 1103 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time, 1104 dependency->name->stat.time); 1105 } 1106 if ((build_unconditional || out_of_date) && 1107 (dependency->name != force) && 1108 (dependency->stale == false)) { 1109 *out_of_date_tail = ALLOC(Chain); 1110 if (dependency->name->is_member && 1111 (get_prop(dependency->name->prop, 1112 member_prop) != NULL)) { 1113 (*out_of_date_tail)->name = 1114 get_prop(dependency->name->prop, 1115 member_prop)-> 1116 body.member.member; 1117 } else { 1118 (*out_of_date_tail)->name = 1119 dependency->name; 1120 } 1121 (*out_of_date_tail)->next = NULL; 1122 out_of_date_tail = &(*out_of_date_tail)->next; 1123 if (debug_level > 0) { 1124 if (dependency->name->stat.time == file_max_time) { 1125 (void) printf(catgets(catd, 1, 22, "%*sBuilding %s because %s does not exist\n"), 1126 recursion_level, 1127 "", 1128 true_target->string_mb, 1129 dependency->name->string_mb); 1130 } else { 1131 (void) printf(catgets(catd, 1, 23, "%*sBuilding %s because it is out of date relative to %s\n"), 1132 recursion_level, 1133 "", 1134 true_target->string_mb, 1135 dependency->name->string_mb); 1136 } 1137 } 1138 } 1139 if (dependency->name == force) { 1140 force->stat.time = 1141 file_max_time; 1142 force->state = build_dont_know; 1143 } 1144 } 1145 } 1146 if (dependencies_running) { 1147 if (doing_subtree) { 1148 if (target->conditional_cnt > 0) { 1149 reset_locals(target, 1150 old_locals, 1151 get_prop(target->prop, 1152 conditional_prop), 1153 0); 1154 } 1155 return true; 1156 } else { 1157 target->state = build_running; 1158 add_pending(target, 1159 --recursion_level, 1160 do_get, 1161 implicit, 1162 false); 1163 if (target->conditional_cnt > 0) { 1164 reset_locals(target, 1165 old_locals, 1166 get_prop(target->prop, 1167 conditional_prop), 1168 0); 1169 } 1170 return true; 1171 } 1172 } 1173 /* 1174 * Collect the timestamp of the youngest double colon target 1175 * dependency. 1176 */ 1177 if (target->is_double_colon_parent) { 1178 for (dependency = line->body.line.dependencies; 1179 dependency != NULL; 1180 dependency = dependency->next) { 1181 Property tmp_line; 1182 1183 if ((tmp_line = get_prop(dependency->name->prop, line_prop)) != NULL) { 1184 if(tmp_line->body.line.dependency_time != file_max_time) { 1185 target->stat.time = 1186 MAX(tmp_line->body.line.dependency_time, 1187 target->stat.time); 1188 } 1189 } 1190 } 1191 } 1192 if ((true_target->is_member) && (dependency_changed == true)) { 1193 true_target->stat.time = file_no_time; 1194 } 1195 /* 1196 * After scanning all the dependencies, we check the rule 1197 * if we found one. 1198 */ 1199 if (line->body.line.command_template != NULL) { 1200 if (line->body.line.command_template_redefined) { 1201 warning(catgets(catd, 1, 24, "Too many rules defined for target %s"), 1202 target->string_mb); 1203 } 1204 *command = line; 1205 /* Check if the target is out of date */ 1206 Boolean out_of_date; 1207 if (true_target->is_member) { 1208 out_of_date = (Boolean) OUT_OF_DATE_SEC(true_target->stat.time, 1209 line->body.line.dependency_time); 1210 } else { 1211 out_of_date = (Boolean) OUT_OF_DATE(true_target->stat.time, 1212 line->body.line.dependency_time); 1213 } 1214 if (build_unconditional || out_of_date){ 1215 if(!recheck_conditionals) { 1216 line->body.line.is_out_of_date = true; 1217 } 1218 } 1219 line->body.line.sccs_command = false; 1220 line->body.line.target = true_target; 1221 if(gnu_style) { 1222 1223 // set $< for explicit rule 1224 if(line->body.line.dependencies != NULL) { 1225 less = line->body.line.dependencies->name; 1226 } 1227 1228 // set $* for explicit rule 1229 Name target_body; 1230 Name tt = true_target; 1231 Property member; 1232 register wchar_t *target_end; 1233 register Dependency suffix; 1234 register int suffix_length; 1235 Wstring targ_string; 1236 Wstring suf_string; 1237 1238 if (true_target->is_member && 1239 ((member = get_prop(target->prop, member_prop)) != 1240 NULL)) { 1241 tt = member->body.member.member; 1242 } 1243 targ_string.init(tt); 1244 target_end = targ_string.get_string() + tt->hash.length; 1245 for (suffix = suffixes; suffix != NULL; suffix = suffix->next) { 1246 suffix_length = suffix->name->hash.length; 1247 suf_string.init(suffix->name); 1248 if (tt->hash.length < suffix_length) { 1249 continue; 1250 } else if (!IS_WEQUALN(suf_string.get_string(), 1251 (target_end - suffix_length), 1252 suffix_length)) { 1253 continue; 1254 } 1255 target_body = GETNAME( 1256 targ_string.get_string(), 1257 (int)(tt->hash.length - suffix_length) 1258 ); 1259 line->body.line.star = target_body; 1260 } 1261 1262 // set result = build_ok so that implicit rules are not used. 1263 if(*result == build_dont_know) { 1264 *result = build_ok; 1265 } 1266 } 1267 if (less != NULL) { 1268 line->body.line.less = less; 1269 } 1270 } 1271 1272 return false; 1273 } 1274 1275 /* 1276 * dynamic_dependencies(target) 1277 * 1278 * Checks if any dependency contains a macro ref 1279 * If so, it replaces the dependency with the expanded version. 1280 * Here, "$@" gets translated to target->string. That is 1281 * the current name on the left of the colon in the 1282 * makefile. Thus, 1283 * xyz: s.$@.c 1284 * translates into 1285 * xyz: s.xyz.c 1286 * 1287 * Also, "$(@F)" translates to the same thing without a preceeding 1288 * directory path (if one exists). 1289 * Note, to enter "$@" on a dependency line in a makefile 1290 * "$$@" must be typed. This is because make expands 1291 * macros in dependency lists upon reading them. 1292 * dynamic_dependencies() also expands file wildcards. 1293 * If there are any Shell meta characters in the name, 1294 * search the directory, and replace the dependency 1295 * with the set of files the pattern matches 1296 * 1297 * Parameters: 1298 * target Target to sanitize dependencies for 1299 * 1300 * Global variables used: 1301 * c_at The Name "@", used to set macro value 1302 * debug_level Should we trace actions? 1303 * dot The Name ".", used to read directory 1304 * recursion_level Used for tracing 1305 */ 1306 void 1307 dynamic_dependencies(Name target) 1308 { 1309 wchar_t pattern[MAXPATHLEN]; 1310 register wchar_t *p; 1311 Property line; 1312 register Dependency dependency; 1313 register Dependency *remove; 1314 String_rec string; 1315 wchar_t buffer[MAXPATHLEN]; 1316 register Boolean set_at = false; 1317 register wchar_t *start; 1318 Dependency new_depe; 1319 register Boolean reuse_cell; 1320 Dependency first_member; 1321 Name directory; 1322 Name lib; 1323 Name member; 1324 Property prop; 1325 Name true_target = target; 1326 wchar_t *library; 1327 1328 if ((line = get_prop(target->prop, line_prop)) == NULL) { 1329 return; 1330 } 1331 /* If the target is constructed from a "::" target we consider that */ 1332 if (target->has_target_prop) { 1333 true_target = get_prop(target->prop, 1334 target_prop)->body.target.target; 1335 } 1336 /* Scan all dependencies and process the ones that contain "$" chars */ 1337 for (dependency = line->body.line.dependencies; 1338 dependency != NULL; 1339 dependency = dependency->next) { 1340 if (!dependency->name->dollar) { 1341 continue; 1342 } 1343 target->has_depe_list_expanded = true; 1344 1345 /* The make macro $@ is bound to the target name once per */ 1346 /* invocation of dynamic_dependencies() */ 1347 if (!set_at) { 1348 (void) SETVAR(c_at, true_target, false); 1349 set_at = true; 1350 } 1351 /* Expand this dependency string */ 1352 INIT_STRING_FROM_STACK(string, buffer); 1353 expand_value(dependency->name, &string, false); 1354 /* Scan the expanded string. It could contain whitespace */ 1355 /* which mean it expands to several dependencies */ 1356 start = string.buffer.start; 1357 while (iswspace(*start)) { 1358 start++; 1359 } 1360 /* Remove the cell (later) if the macro was empty */ 1361 if (start[0] == (int) nul_char) { 1362 dependency->name = NULL; 1363 } 1364 1365 /* azv 10/26/95 to fix bug BID_1170218 */ 1366 if ((start[0] == (int) period_char) && 1367 (start[1] == (int) slash_char)) { 1368 start += 2; 1369 } 1370 /* azv */ 1371 1372 first_member = NULL; 1373 /* We use the original dependency cell for the first */ 1374 /* dependency from the expansion */ 1375 reuse_cell = true; 1376 /* We also have to deal with dependencies that expand to */ 1377 /* lib.a(members) notation */ 1378 for (p = start; *p != (int) nul_char; p++) { 1379 if ((*p == (int) parenleft_char)) { 1380 lib = GETNAME(start, p - start); 1381 lib->is_member = true; 1382 first_member = dependency; 1383 start = p + 1; 1384 while (iswspace(*start)) { 1385 start++; 1386 } 1387 break; 1388 } 1389 } 1390 do { 1391 /* First skip whitespace */ 1392 for (p = start; *p != (int) nul_char; p++) { 1393 if ((*p == (int) nul_char) || 1394 iswspace(*p) || 1395 (*p == (int) parenright_char)) { 1396 break; 1397 } 1398 } 1399 /* Enter dependency from expansion */ 1400 if (p != start) { 1401 /* Create new dependency cell if */ 1402 /* this is not the first dependency */ 1403 /* picked from the expansion */ 1404 if (!reuse_cell) { 1405 new_depe = ALLOC(Dependency); 1406 new_depe->next = dependency->next; 1407 new_depe->automatic = false; 1408 new_depe->stale = false; 1409 new_depe->built = false; 1410 dependency->next = new_depe; 1411 dependency = new_depe; 1412 } 1413 reuse_cell = false; 1414 /* Internalize the dependency name */ 1415 // tolik. Fix for bug 4110429: inconsistent expansion for macros that 1416 // include "//" and "/./" 1417 //dependency->name = GETNAME(start, p - start); 1418 dependency->name = normalize_name(start, p - start); 1419 if ((debug_level > 0) && 1420 (first_member == NULL)) { 1421 (void) printf(catgets(catd, 1, 25, "%*sDynamic dependency `%s' for target `%s'\n"), 1422 recursion_level, 1423 "", 1424 dependency->name->string_mb, 1425 true_target->string_mb); 1426 } 1427 for (start = p; iswspace(*start); start++); 1428 p = start; 1429 } 1430 } while ((*p != (int) nul_char) && 1431 (*p != (int) parenright_char)); 1432 /* If the expansion was of lib.a(members) format we now */ 1433 /* enter the proper member cells */ 1434 if (first_member != NULL) { 1435 /* Scan the new dependencies and transform them from */ 1436 /* "foo" to "lib.a(foo)" */ 1437 for (; 1; first_member = first_member->next) { 1438 /* Build "lib.a(foo)" name */ 1439 INIT_STRING_FROM_STACK(string, buffer); 1440 APPEND_NAME(lib, 1441 &string, 1442 (int) lib->hash.length); 1443 append_char((int) parenleft_char, &string); 1444 APPEND_NAME(first_member->name, 1445 &string, 1446 FIND_LENGTH); 1447 append_char((int) parenright_char, &string); 1448 member = first_member->name; 1449 /* Replace "foo" with "lib.a(foo)" */ 1450 first_member->name = 1451 GETNAME(string.buffer.start, FIND_LENGTH); 1452 if (string.free_after_use) { 1453 retmem(string.buffer.start); 1454 } 1455 if (debug_level > 0) { 1456 (void) printf(catgets(catd, 1, 26, "%*sDynamic dependency `%s' for target `%s'\n"), 1457 recursion_level, 1458 "", 1459 first_member->name-> 1460 string_mb, 1461 true_target->string_mb); 1462 } 1463 first_member->name->is_member = lib->is_member; 1464 /* Add member property to member */ 1465 prop = maybe_append_prop(first_member->name, 1466 member_prop); 1467 prop->body.member.library = lib; 1468 prop->body.member.entry = NULL; 1469 prop->body.member.member = member; 1470 if (first_member == dependency) { 1471 break; 1472 } 1473 } 1474 } 1475 } 1476 Wstring wcb; 1477 /* Then scan all the dependencies again. This time we want to expand */ 1478 /* shell file wildcards */ 1479 for (remove = &line->body.line.dependencies, dependency = *remove; 1480 dependency != NULL; 1481 dependency = *remove) { 1482 if (dependency->name == NULL) { 1483 dependency = *remove = (*remove)->next; 1484 continue; 1485 } 1486 /* If dependency name string contains shell wildcards */ 1487 /* replace the name with the expansion */ 1488 if (dependency->name->wildcard) { 1489 wcb.init(dependency->name); 1490 if ((start = (wchar_t *) wschr(wcb.get_string(), 1491 (int) parenleft_char)) != NULL) { 1492 /* lib(*) type pattern */ 1493 library = buffer; 1494 (void) wsncpy(buffer, 1495 wcb.get_string(), 1496 start - wcb.get_string()); 1497 buffer[start-wcb.get_string()] = 1498 (int) nul_char; 1499 (void) wsncpy(pattern, 1500 start + 1, 1501 (int) (dependency->name->hash.length-(start-wcb.get_string())-2)); 1502 pattern[dependency->name->hash.length - 1503 (start-wcb.get_string()) - 2] = 1504 (int) nul_char; 1505 } else { 1506 library = NULL; 1507 (void) wsncpy(pattern, 1508 wcb.get_string(), 1509 (int) dependency->name->hash.length); 1510 pattern[dependency->name->hash.length] = 1511 (int) nul_char; 1512 } 1513 start = (wchar_t *) wsrchr(pattern, (int) slash_char); 1514 if (start == NULL) { 1515 directory = dot; 1516 p = pattern; 1517 } else { 1518 directory = GETNAME(pattern, start-pattern); 1519 p = start+1; 1520 } 1521 /* The expansion is handled by the read_dir() routine*/ 1522 if (read_dir(directory, p, line, library)) { 1523 *remove = (*remove)->next; 1524 } else { 1525 remove = &dependency->next; 1526 } 1527 } else { 1528 remove = &dependency->next; 1529 } 1530 } 1531 1532 /* Then unbind $@ */ 1533 (void) SETVAR(c_at, (Name) NULL, false); 1534 } 1535 1536 /* 1537 * DONE. 1538 * 1539 * run_command(line) 1540 * 1541 * Takes one Cmd_line and runs the commands from it. 1542 * 1543 * Return value: 1544 * Indicates if the command failed or not 1545 * 1546 * Parameters: 1547 * line The command line to run 1548 * 1549 * Global variables used: 1550 * commands_done Set if we do run command 1551 * current_line Set to the line we run a command from 1552 * current_target Set to the target we run a command for 1553 * file_number Used to form temp file name 1554 * keep_state Indicates that .KEEP_STATE is on 1555 * make_state The Name ".make.state", used to check timestamp 1556 * parallel True if currently building in parallel 1557 * parallel_process_cnt Count of parallel processes running 1558 * quest Indicates that make -q is on 1559 * rewrite_statefile Set if we do run a command 1560 * sunpro_dependencies The Name "SUNPRO_DEPENDENCIES", set value 1561 * temp_file_directory Used to form temp fie name 1562 * temp_file_name Set to the name of the temp file 1563 * touch Indicates that make -t is on 1564 */ 1565 static Doname 1566 run_command(register Property line, Boolean) 1567 { 1568 register Doname result = build_ok; 1569 register Boolean remember_only = false; 1570 register Name target = line->body.line.target; 1571 wchar_t *string; 1572 char tmp_file_path[MAXPATHLEN]; 1573 1574 if (!line->body.line.is_out_of_date && target->rechecking_target) { 1575 target->rechecking_target = false; 1576 return build_ok; 1577 } 1578 1579 /* 1580 * Build the command if we know the target is out of date, 1581 * or if we want to check cmd consistency. 1582 */ 1583 if (line->body.line.is_out_of_date || keep_state) { 1584 /* Hack for handling conditional macros in DMake. */ 1585 if (!line->body.line.dont_rebuild_command_used) { 1586 build_command_strings(target, line); 1587 } 1588 } 1589 /* Never mind */ 1590 if (!line->body.line.is_out_of_date) { 1591 return build_ok; 1592 } 1593 /* If quest, then exit(1) because the target is out of date */ 1594 if (quest) { 1595 if (posix) { 1596 result = execute_parallel(line, true); 1597 } 1598 exit_status = 1; 1599 exit(1); 1600 } 1601 /* We actually had to do something this time */ 1602 rewrite_statefile = commands_done = true; 1603 /* 1604 * If this is an sccs command, we have to do some extra checking 1605 * and possibly complain. If the file can't be gotten because it's 1606 * checked out, we complain and behave as if the command was 1607 * executed eventhough we ignored the command. 1608 */ 1609 if (!touch && 1610 line->body.line.sccs_command && 1611 (target->stat.time != file_doesnt_exist) && 1612 ((target->stat.mode & 0222) != 0)) { 1613 fatal(catgets(catd, 1, 27, "%s is writable so it cannot be sccs gotten"), 1614 target->string_mb); 1615 target->has_complained = remember_only = true; 1616 } 1617 /* 1618 * If KEEP_STATE is on, we make sure we have the timestamp for 1619 * .make.state. If .make.state changes during the command run, 1620 * we reread .make.state after the command. We also setup the 1621 * environment variable that asks utilities to report dependencies. 1622 */ 1623 if (!touch && 1624 keep_state && 1625 !remember_only) { 1626 (void) exists(make_state); 1627 if((strlen(temp_file_directory) == 1) && 1628 (temp_file_directory[0] == '/')) { 1629 tmp_file_path[0] = '\0'; 1630 } else { 1631 strcpy(tmp_file_path, temp_file_directory); 1632 } 1633 sprintf(mbs_buffer, 1634 NOCATGETS("%s/.make.dependency.%08x.%d.%d"), 1635 tmp_file_path, 1636 hostid, 1637 getpid(), 1638 file_number++); 1639 MBSTOWCS(wcs_buffer, mbs_buffer); 1640 Boolean fnd; 1641 temp_file_name = getname_fn(wcs_buffer, FIND_LENGTH, false, &fnd); 1642 temp_file_name->stat.is_file = true; 1643 int len = 2*MAXPATHLEN + strlen(target->string_mb) + 2; 1644 wchar_t *to = string = ALLOC_WC(len); 1645 for (wchar_t *from = wcs_buffer; *from != (int) nul_char; ) { 1646 if (*from == (int) space_char) { 1647 *to++ = (int) backslash_char; 1648 } 1649 *to++ = *from++; 1650 } 1651 *to++ = (int) space_char; 1652 MBSTOWCS(to, target->string_mb); 1653 Name sprodep_name = getname_fn(string, FIND_LENGTH, false, &fnd); 1654 (void) SETVAR(sunpro_dependencies, 1655 sprodep_name, 1656 false); 1657 retmem(string); 1658 } else { 1659 temp_file_name = NULL; 1660 } 1661 1662 /* 1663 * In case we are interrupted, we need to know what was going on. 1664 */ 1665 current_target = target; 1666 /* 1667 * We also need to be able to save an empty command instead of the 1668 * interrupted one in .make.state. 1669 */ 1670 current_line = line; 1671 if (remember_only) { 1672 /* Empty block!!! */ 1673 } else if (touch) { 1674 result = touch_command(line, target, result); 1675 if (posix) { 1676 result = execute_parallel(line, true); 1677 } 1678 } else { 1679 /* 1680 * If this is not a touch run, we need to execute the 1681 * proper command(s) for the target. 1682 */ 1683 if (parallel) { 1684 if (!parallel_ok(target, true)) { 1685 /* 1686 * We are building in parallel, but 1687 * this target must be built in serial. 1688 */ 1689 /* 1690 * If nothing else is building, 1691 * do this one, else wait. 1692 */ 1693 if (parallel_process_cnt == 0) { 1694 result = execute_parallel(line, true, target->localhost); 1695 } else { 1696 current_target = NULL; 1697 current_line = NULL; 1698 /* 1699 line->body.line.command_used = NULL; 1700 */ 1701 line->body.line.dont_rebuild_command_used = true; 1702 return build_serial; 1703 } 1704 } else { 1705 result = execute_parallel(line, false); 1706 switch (result) { 1707 case build_running: 1708 return build_running; 1709 case build_serial: 1710 if (parallel_process_cnt == 0) { 1711 result = execute_parallel(line, true, target->localhost); 1712 } else { 1713 current_target = NULL; 1714 current_line = NULL; 1715 target->parallel = false; 1716 line->body.line.command_used = 1717 NULL; 1718 return build_serial; 1719 } 1720 } 1721 } 1722 } else { 1723 result = execute_parallel(line, true, target->localhost); 1724 } 1725 } 1726 temp_file_name = NULL; 1727 if (report_dependencies_level == 0){ 1728 update_target(line, result); 1729 } 1730 current_target = NULL; 1731 current_line = NULL; 1732 return result; 1733 } 1734 1735 /* 1736 * execute_serial(line) 1737 * 1738 * Runs thru the command line for the target and 1739 * executes the rules one by one. 1740 * 1741 * Return value: 1742 * The result of the command build 1743 * 1744 * Parameters: 1745 * line The command to execute 1746 * 1747 * Static variables used: 1748 * 1749 * Global variables used: 1750 * continue_after_error -k flag 1751 * do_not_exec_rule -n flag 1752 * report_dependencies -P flag 1753 * silent Don't echo commands before executing 1754 * temp_file_name Temp file for auto dependencies 1755 * vpath_defined If true, translate path for command 1756 */ 1757 Doname 1758 execute_serial(Property line) 1759 { 1760 int child_pid = 0; 1761 Boolean printed_serial; 1762 Doname result = build_ok; 1763 Cmd_line rule, cmd_tail, command = NULL; 1764 char mbstring[MAXPATHLEN]; 1765 int filed; 1766 Name target = line->body.line.target; 1767 1768 SEND_MTOOL_MSG( 1769 if (!sent_rsrc_info_msg) { 1770 if (userName[0] == '\0') { 1771 avo_get_user(userName, NULL); 1772 } 1773 if (hostName[0] == '\0') { 1774 strcpy(hostName, avo_hostname()); 1775 } 1776 send_rsrc_info_msg(1, hostName, userName); 1777 sent_rsrc_info_msg = 1; 1778 } 1779 send_job_start_msg(line); 1780 job_result_msg = new Avo_MToolJobResultMsg(); 1781 ); 1782 1783 target->has_recursive_dependency = false; 1784 // We have to create a copy of the rules chain for processing because 1785 // the original one can be destroyed during .make.state file rereading. 1786 for (rule = line->body.line.command_used; 1787 rule != NULL; 1788 rule = rule->next) { 1789 if (command == NULL) { 1790 command = cmd_tail = ALLOC(Cmd_line); 1791 } else { 1792 cmd_tail->next = ALLOC(Cmd_line); 1793 cmd_tail = cmd_tail->next; 1794 } 1795 *cmd_tail = *rule; 1796 } 1797 if (command) { 1798 cmd_tail->next = NULL; 1799 } 1800 for (rule = command; rule != NULL; rule = rule->next) { 1801 if (posix && (touch || quest) && !rule->always_exec) { 1802 continue; 1803 } 1804 if (vpath_defined) { 1805 rule->command_line = 1806 vpath_translation(rule->command_line); 1807 } 1808 /* Echo command line, maybe. */ 1809 if ((rule->command_line->hash.length > 0) && 1810 !silent && 1811 (!rule->silent || do_not_exec_rule) && 1812 (report_dependencies_level == 0)) { 1813 (void) printf("%s\n", rule->command_line->string_mb); 1814 SEND_MTOOL_MSG( 1815 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb)); 1816 ); 1817 } 1818 if (rule->command_line->hash.length > 0) { 1819 SEND_MTOOL_MSG( 1820 (void) sprintf(mbstring, 1821 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"), 1822 tmpdir, 1823 getpid(), 1824 file_number++); 1825 1826 int tmp_fd = mkstemp(mbstring); 1827 if(tmp_fd) { 1828 (void) close(tmp_fd); 1829 } 1830 1831 stdout_file = strdup(mbstring); 1832 stderr_file = NULL; 1833 child_pid = pollResults(stdout_file, 1834 (char *)NULL, 1835 (char *)NULL); 1836 ); 1837 /* Do assignment if command line prefixed with "=" */ 1838 if (rule->assign) { 1839 result = build_ok; 1840 do_assign(rule->command_line, target); 1841 } else if (report_dependencies_level == 0) { 1842 /* Execute command line. */ 1843 setvar_envvar(); 1844 result = dosys(rule->command_line, 1845 (Boolean) rule->ignore_error, 1846 (Boolean) rule->make_refd, 1847 /* ds 98.04.23 bug #4085164. make should always show error messages */ 1848 false, 1849 /* BOOLEAN(rule->silent && 1850 rule->ignore_error), */ 1851 (Boolean) rule->always_exec, 1852 target, 1853 send_mtool_msgs); 1854 check_state(temp_file_name); 1855 } 1856 SEND_MTOOL_MSG( 1857 append_job_result_msg(job_result_msg); 1858 if (child_pid > 0) { 1859 kill(child_pid, SIGUSR1); 1860 while (!((waitpid(child_pid, 0, 0) == -1) 1861 && (errno == ECHILD))); 1862 } 1863 child_pid = 0; 1864 (void) unlink(stdout_file); 1865 retmem_mb(stdout_file); 1866 stdout_file = NULL; 1867 ); 1868 } else { 1869 result = build_ok; 1870 } 1871 if (result == build_failed) { 1872 if (silent || rule->silent) { 1873 (void) printf(catgets(catd, 1, 242, "The following command caused the error:\n%s\n"), 1874 rule->command_line->string_mb); 1875 SEND_MTOOL_MSG( 1876 job_result_msg->appendOutput(AVO_STRDUP(catgets(catd, 1, 243, "The following command caused the error:"))); 1877 job_result_msg->appendOutput(AVO_STRDUP(rule->command_line->string_mb)); 1878 ); 1879 } 1880 if (!rule->ignore_error && !ignore_errors) { 1881 if (!continue_after_error) { 1882 SEND_MTOOL_MSG( 1883 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE); 1884 xdr_msg = (RWCollectable*) 1885 job_result_msg; 1886 xdr(&xdrs, xdr_msg); 1887 (void) fflush(mtool_msgs_fp); 1888 delete job_result_msg; 1889 ); 1890 fatal(catgets(catd, 1, 244, "Command failed for target `%s'"), 1891 target->string_mb); 1892 } 1893 /* 1894 * Make sure a failing command is not 1895 * saved in .make.state. 1896 */ 1897 line->body.line.command_used = NULL; 1898 break; 1899 } else { 1900 result = build_ok; 1901 } 1902 } 1903 } 1904 for (rule = command; rule != NULL; rule = cmd_tail) { 1905 cmd_tail = rule->next; 1906 free(rule); 1907 } 1908 command = NULL; 1909 SEND_MTOOL_MSG( 1910 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE); 1911 xdr_msg = (RWCollectable*) job_result_msg; 1912 xdr(&xdrs, xdr_msg); 1913 (void) fflush(mtool_msgs_fp); 1914 1915 delete job_result_msg; 1916 ); 1917 if (temp_file_name != NULL) { 1918 free_name(temp_file_name); 1919 } 1920 temp_file_name = NULL; 1921 1922 Property spro = get_prop(sunpro_dependencies->prop, macro_prop); 1923 if(spro != NULL) { 1924 Name val = spro->body.macro.value; 1925 if(val != NULL) { 1926 free_name(val); 1927 spro->body.macro.value = NULL; 1928 } 1929 } 1930 spro = get_prop(sunpro_dependencies->prop, env_mem_prop); 1931 if(spro) { 1932 char *val = spro->body.env_mem.value; 1933 if(val != NULL) { 1934 /* 1935 * Do not return memory allocated for SUNPRO_DEPENDENCIES 1936 * It will be returned in setvar_daemon() in macro.cc 1937 */ 1938 // retmem_mb(val); 1939 spro->body.env_mem.value = NULL; 1940 } 1941 } 1942 1943 return result; 1944 } 1945 1946 1947 1948 /* 1949 * vpath_translation(cmd) 1950 * 1951 * Translates one command line by 1952 * checking each word. If the word has an alias it is translated. 1953 * 1954 * Return value: 1955 * The translated command 1956 * 1957 * Parameters: 1958 * cmd Command to translate 1959 * 1960 * Global variables used: 1961 */ 1962 Name 1963 vpath_translation(register Name cmd) 1964 { 1965 wchar_t buffer[STRING_BUFFER_LENGTH]; 1966 String_rec new_cmd; 1967 wchar_t *p; 1968 wchar_t *start; 1969 1970 if (!vpath_defined || (cmd == NULL) || (cmd->hash.length == 0)) { 1971 return cmd; 1972 } 1973 INIT_STRING_FROM_STACK(new_cmd, buffer); 1974 1975 Wstring wcb(cmd); 1976 p = wcb.get_string(); 1977 1978 while (*p != (int) nul_char) { 1979 while (iswspace(*p) && (*p != (int) nul_char)) { 1980 append_char(*p++, &new_cmd); 1981 } 1982 start = p; 1983 while (!iswspace(*p) && (*p != (int) nul_char)) { 1984 p++; 1985 } 1986 cmd = GETNAME(start, p - start); 1987 if (cmd->has_vpath_alias_prop) { 1988 cmd = get_prop(cmd->prop, vpath_alias_prop)-> 1989 body.vpath_alias.alias; 1990 APPEND_NAME(cmd, 1991 &new_cmd, 1992 (int) cmd->hash.length); 1993 } else { 1994 append_string(start, &new_cmd, p - start); 1995 } 1996 } 1997 cmd = GETNAME(new_cmd.buffer.start, FIND_LENGTH); 1998 if (new_cmd.free_after_use) { 1999 retmem(new_cmd.buffer.start); 2000 } 2001 return cmd; 2002 } 2003 2004 /* 2005 * check_state(temp_file_name) 2006 * 2007 * Reads and checks the state changed by the previously executed command. 2008 * 2009 * Parameters: 2010 * temp_file_name The auto dependency temp file 2011 * 2012 * Global variables used: 2013 */ 2014 void 2015 check_state(Name temp_file_name) 2016 { 2017 if (!keep_state) { 2018 return; 2019 } 2020 2021 /* 2022 * Then read the temp file that now might 2023 * contain dependency reports from utilities 2024 */ 2025 read_dependency_file(temp_file_name); 2026 2027 /* 2028 * And reread .make.state if it 2029 * changed (the command ran recursive makes) 2030 */ 2031 check_read_state_file(); 2032 if (temp_file_name != NULL) { 2033 (void) unlink(temp_file_name->string_mb); 2034 } 2035 } 2036 2037 /* 2038 * read_dependency_file(filename) 2039 * 2040 * Read the temp file used for reporting dependencies to make 2041 * 2042 * Parameters: 2043 * filename The name of the file with the state info 2044 * 2045 * Global variables used: 2046 * makefile_type The type of makefile being read 2047 * read_trace_level Debug flag 2048 * temp_file_number The always increasing number for unique files 2049 * trace_reader Debug flag 2050 */ 2051 static void 2052 read_dependency_file(register Name filename) 2053 { 2054 register Makefile_type save_makefile_type; 2055 2056 if (filename == NULL) { 2057 return; 2058 } 2059 filename->stat.time = file_no_time; 2060 if (exists(filename) > file_doesnt_exist) { 2061 save_makefile_type = makefile_type; 2062 makefile_type = reading_cpp_file; 2063 if (read_trace_level > 1) { 2064 trace_reader = true; 2065 } 2066 temp_file_number++; 2067 (void) read_simple_file(filename, 2068 false, 2069 false, 2070 false, 2071 false, 2072 false, 2073 false); 2074 trace_reader = false; 2075 makefile_type = save_makefile_type; 2076 } 2077 } 2078 2079 /* 2080 * check_read_state_file() 2081 * 2082 * Check if .make.state has changed 2083 * If it has we reread it 2084 * 2085 * Parameters: 2086 * 2087 * Global variables used: 2088 * make_state Make state file name 2089 * makefile_type Type of makefile being read 2090 * read_trace_level Debug flag 2091 * trace_reader Debug flag 2092 */ 2093 static void 2094 check_read_state_file(void) 2095 { 2096 timestruc_t previous = make_state->stat.time; 2097 register Makefile_type save_makefile_type; 2098 register Property makefile; 2099 2100 make_state->stat.time = file_no_time; 2101 if ((exists(make_state) == file_doesnt_exist) || 2102 (make_state->stat.time == previous)) { 2103 return; 2104 } 2105 save_makefile_type = makefile_type; 2106 makefile_type = rereading_statefile; 2107 /* Make sure we clear the old cached contents of .make.state */ 2108 makefile = maybe_append_prop(make_state, makefile_prop); 2109 if (makefile->body.makefile.contents != NULL) { 2110 retmem(makefile->body.makefile.contents); 2111 makefile->body.makefile.contents = NULL; 2112 } 2113 if (read_trace_level > 1) { 2114 trace_reader = true; 2115 } 2116 temp_file_number++; 2117 (void) read_simple_file(make_state, 2118 false, 2119 false, 2120 false, 2121 false, 2122 false, 2123 true); 2124 trace_reader = false; 2125 makefile_type = save_makefile_type; 2126 } 2127 2128 /* 2129 * do_assign(line, target) 2130 * 2131 * Handles runtime assignments for command lines prefixed with "=". 2132 * 2133 * Parameters: 2134 * line The command that contains an assignment 2135 * target The Name of the target, used for error reports 2136 * 2137 * Global variables used: 2138 * assign_done Set to indicate doname needs to reprocess 2139 */ 2140 static void 2141 do_assign(register Name line, register Name target) 2142 { 2143 Wstring wcb(line); 2144 register wchar_t *string = wcb.get_string(); 2145 register wchar_t *equal; 2146 register Name name; 2147 register Boolean append = false; 2148 2149 /* 2150 * If any runtime assignments are done, doname() must reprocess all 2151 * targets in the future since the macro values used to build the 2152 * command lines for the targets might have changed. 2153 */ 2154 assign_done = true; 2155 /* Skip white space. */ 2156 while (iswspace(*string)) { 2157 string++; 2158 } 2159 equal = string; 2160 /* Find "+=" or "=". */ 2161 while (!iswspace(*equal) && 2162 (*equal != (int) plus_char) && 2163 (*equal != (int) equal_char)) { 2164 equal++; 2165 } 2166 /* Internalize macro name. */ 2167 name = GETNAME(string, equal - string); 2168 /* Skip over "+=" "=". */ 2169 while (!((*equal == (int) nul_char) || 2170 (*equal == (int) equal_char) || 2171 (*equal == (int) plus_char))) { 2172 equal++; 2173 } 2174 switch (*equal) { 2175 case nul_char: 2176 fatal(catgets(catd, 1, 31, "= expected in rule `%s' for target `%s'"), 2177 line->string_mb, 2178 target->string_mb); 2179 case plus_char: 2180 append = true; 2181 equal++; 2182 break; 2183 } 2184 equal++; 2185 /* Skip over whitespace in front of value. */ 2186 while (iswspace(*equal)) { 2187 equal++; 2188 } 2189 /* Enter new macro value. */ 2190 enter_equal(name, 2191 GETNAME(equal, wcb.get_string() + line->hash.length - equal), 2192 append); 2193 } 2194 2195 /* 2196 * build_command_strings(target, line) 2197 * 2198 * Builds the command string to used when 2199 * building a target. If the string is different from the previous one 2200 * is_out_of_date is set. 2201 * 2202 * Parameters: 2203 * target Target to build commands for 2204 * line Where to stuff result 2205 * 2206 * Global variables used: 2207 * c_at The Name "@", used to set macro value 2208 * command_changed Set if command is different from old 2209 * debug_level Should we trace activities? 2210 * do_not_exec_rule Always echo when running -n 2211 * empty_name The Name "", used for empty rule 2212 * funny Semantics of characters 2213 * ignore_errors Used to init field for line 2214 * is_conditional Set to false befor evaling macro, checked 2215 * after expanding macros 2216 * keep_state Indicates that .KEEP_STATE is on 2217 * make_word_mentioned Set by macro eval, inits field for cmd 2218 * query The Name "?", used to set macro value 2219 * query_mentioned Set by macro eval, inits field for cmd 2220 * recursion_level Used for tracing 2221 * silent Used to init field for line 2222 */ 2223 static void 2224 build_command_strings(Name target, register Property line) 2225 { 2226 String_rec command_line; 2227 register Cmd_line command_template = line->body.line.command_template; 2228 register Cmd_line *insert = &line->body.line.command_used; 2229 register Cmd_line used = *insert; 2230 wchar_t buffer[STRING_BUFFER_LENGTH]; 2231 wchar_t *start; 2232 Name new_command_line; 2233 register Boolean new_command_longer = false; 2234 register Boolean ignore_all_command_dependency = true; 2235 Property member; 2236 static Name less_name; 2237 static Name percent_name; 2238 static Name star; 2239 Name tmp_name; 2240 2241 if (less_name == NULL) { 2242 MBSTOWCS(wcs_buffer, "<"); 2243 less_name = GETNAME(wcs_buffer, FIND_LENGTH); 2244 MBSTOWCS(wcs_buffer, "%"); 2245 percent_name = GETNAME(wcs_buffer, FIND_LENGTH); 2246 MBSTOWCS(wcs_buffer, "*"); 2247 star = GETNAME(wcs_buffer, FIND_LENGTH); 2248 } 2249 2250 /* We have to check if a target depends on conditional macros */ 2251 /* Targets that do must be reprocessed by doname() each time around */ 2252 /* since the macro values used when building the target might have */ 2253 /* changed */ 2254 conditional_macro_used = false; 2255 /* If we are building a lib.a(member) target $@ should be bound */ 2256 /* to lib.a */ 2257 if (target->is_member && 2258 ((member = get_prop(target->prop, member_prop)) != NULL)) { 2259 target = member->body.member.library; 2260 } 2261 /* If we are building a "::" help target $@ should be bound to */ 2262 /* the real target name */ 2263 /* A lib.a(member) target is never :: */ 2264 if (target->has_target_prop) { 2265 target = get_prop(target->prop, target_prop)-> 2266 body.target.target; 2267 } 2268 /* Bind the magic macros that make supplies */ 2269 tmp_name = target; 2270 if(tmp_name != NULL) { 2271 if (tmp_name->has_vpath_alias_prop) { 2272 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)-> 2273 body.vpath_alias.alias; 2274 } 2275 } 2276 (void) SETVAR(c_at, tmp_name, false); 2277 2278 tmp_name = line->body.line.star; 2279 if(tmp_name != NULL) { 2280 if (tmp_name->has_vpath_alias_prop) { 2281 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)-> 2282 body.vpath_alias.alias; 2283 } 2284 } 2285 (void) SETVAR(star, tmp_name, false); 2286 2287 tmp_name = line->body.line.less; 2288 if(tmp_name != NULL) { 2289 if (tmp_name->has_vpath_alias_prop) { 2290 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)-> 2291 body.vpath_alias.alias; 2292 } 2293 } 2294 (void) SETVAR(less_name, tmp_name, false); 2295 2296 tmp_name = line->body.line.percent; 2297 if(tmp_name != NULL) { 2298 if (tmp_name->has_vpath_alias_prop) { 2299 tmp_name = get_prop(tmp_name->prop, vpath_alias_prop)-> 2300 body.vpath_alias.alias; 2301 } 2302 } 2303 (void) SETVAR(percent_name, tmp_name, false); 2304 2305 /* $? is seldom used and it is expensive to build */ 2306 /* so we store the list form and build the string on demand */ 2307 Chain query_list = NULL; 2308 Chain *query_list_tail = &query_list; 2309 2310 for (Chain ch = line->body.line.query; ch != NULL; ch = ch->next) { 2311 *query_list_tail = ALLOC(Chain); 2312 (*query_list_tail)->name = ch->name; 2313 if ((*query_list_tail)->name->has_vpath_alias_prop) { 2314 (*query_list_tail)->name = 2315 get_prop((*query_list_tail)->name->prop, 2316 vpath_alias_prop)->body.vpath_alias.alias; 2317 } 2318 (*query_list_tail)->next = NULL; 2319 query_list_tail = &(*query_list_tail)->next; 2320 } 2321 (void) setvar_daemon(query, 2322 (Name) query_list, 2323 false, 2324 chain_daemon, 2325 false, 2326 debug_level); 2327 2328 /* build $^ */ 2329 Chain hat_list = NULL; 2330 Chain *hat_list_tail = &hat_list; 2331 2332 for (Dependency dependency = line->body.line.dependencies; 2333 dependency != NULL; 2334 dependency = dependency->next) { 2335 /* skip automatic dependencies */ 2336 if (!dependency->automatic) { 2337 if ((dependency->name != force) && 2338 (dependency->stale == false)) { 2339 *hat_list_tail = ALLOC(Chain); 2340 2341 if (dependency->name->is_member && 2342 (get_prop(dependency->name->prop, member_prop) != NULL)) { 2343 (*hat_list_tail)->name = 2344 get_prop(dependency->name->prop, 2345 member_prop)->body.member.member; 2346 } else { 2347 (*hat_list_tail)->name = dependency->name; 2348 } 2349 2350 if((*hat_list_tail)->name != NULL) { 2351 if ((*hat_list_tail)->name->has_vpath_alias_prop) { 2352 (*hat_list_tail)->name = 2353 get_prop((*hat_list_tail)->name->prop, 2354 vpath_alias_prop)->body.vpath_alias.alias; 2355 } 2356 } 2357 2358 (*hat_list_tail)->next = NULL; 2359 hat_list_tail = &(*hat_list_tail)->next; 2360 } 2361 } 2362 } 2363 (void) setvar_daemon(hat, 2364 (Name) hat_list, 2365 false, 2366 chain_daemon, 2367 false, 2368 debug_level); 2369 2370 /* We have two command sequences we need to handle */ 2371 /* The old one that we probably read from .make.state */ 2372 /* and the new one we are building that will replace the old one */ 2373 /* Even when KEEP_STATE is not on we build a new command sequence and store */ 2374 /* it in the line prop. This command sequence is then executed by */ 2375 /* run_command(). If KEEP_STATE is on it is also later written to */ 2376 /* .make.state. The routine replaces the old command line by line with the */ 2377 /* new one trying to reuse Cmd_lines */ 2378 2379 /* If there is no old command_used we have to start creating */ 2380 /* Cmd_lines to keep the new cmd in */ 2381 if (used == NULL) { 2382 new_command_longer = true; 2383 *insert = used = ALLOC(Cmd_line); 2384 used->next = NULL; 2385 used->command_line = NULL; 2386 insert = &used->next; 2387 } 2388 /* Run thru the template for the new command and build the expanded */ 2389 /* new command lines */ 2390 for (; 2391 command_template != NULL; 2392 command_template = command_template->next, insert = &used->next, used = *insert) { 2393 /* If there is no old command_used Cmd_line we need to */ 2394 /* create one and say that cmd consistency failed */ 2395 if (used == NULL) { 2396 new_command_longer = true; 2397 *insert = used = ALLOC(Cmd_line); 2398 used->next = NULL; 2399 used->command_line = empty_name; 2400 } 2401 /* Prepare the Cmd_line for the processing */ 2402 /* The command line prefixes "@-=?" are stripped and that */ 2403 /* information is saved in the Cmd_line */ 2404 used->assign = false; 2405 used->ignore_error = ignore_errors; 2406 used->silent = silent; 2407 used->always_exec = false; 2408 /* Expand the macros in the command line */ 2409 INIT_STRING_FROM_STACK(command_line, buffer); 2410 make_word_mentioned = 2411 query_mentioned = 2412 false; 2413 expand_value(command_template->command_line, &command_line, true); 2414 /* If the macro $(MAKE) is mentioned in the command */ 2415 /* "make -n" runs actually execute the command */ 2416 used->make_refd = make_word_mentioned; 2417 used->ignore_command_dependency = query_mentioned; 2418 /* Strip the prefixes */ 2419 start = command_line.buffer.start; 2420 for (; 2421 iswspace(*start) || 2422 (get_char_semantics_value(*start) & (int) command_prefix_sem); 2423 start++) { 2424 switch (*start) { 2425 case question_char: 2426 used->ignore_command_dependency = true; 2427 break; 2428 case exclam_char: 2429 used->ignore_command_dependency = false; 2430 break; 2431 case equal_char: 2432 used->assign = true; 2433 break; 2434 case hyphen_char: 2435 used->ignore_error = true; 2436 break; 2437 case at_char: 2438 if (!do_not_exec_rule) { 2439 used->silent = true; 2440 } 2441 break; 2442 case plus_char: 2443 if(posix) { 2444 used->always_exec = true; 2445 } 2446 break; 2447 } 2448 } 2449 /* If all command lines of the template are prefixed with "?"*/ 2450 /* the VIRTUAL_ROOT is not used for cmd consistency checks */ 2451 if (!used->ignore_command_dependency) { 2452 ignore_all_command_dependency = false; 2453 } 2454 /* Internalize the expanded and stripped command line */ 2455 new_command_line = GETNAME(start, FIND_LENGTH); 2456 if ((used->command_line == NULL) && 2457 (line->body.line.sccs_command)) { 2458 used->command_line = new_command_line; 2459 new_command_longer = false; 2460 } 2461 /* Compare it with the old one for command consistency */ 2462 if (used->command_line != new_command_line) { 2463 Name vpath_translated = vpath_translation(new_command_line); 2464 if (keep_state && 2465 !used->ignore_command_dependency && (vpath_translated != used->command_line)) { 2466 if (debug_level > 0) { 2467 if (used->command_line != NULL 2468 && *used->command_line->string_mb != 2469 '\0') { 2470 (void) printf(catgets(catd, 1, 32, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from old\n\t%s\n"), 2471 recursion_level, 2472 "", 2473 target->string_mb, 2474 vpath_translated->string_mb, 2475 recursion_level, 2476 "", 2477 used-> 2478 command_line-> 2479 string_mb); 2480 } else { 2481 (void) printf(catgets(catd, 1, 33, "%*sBuilding %s because new command \n\t%s\n%*sdifferent from empty old command\n"), 2482 recursion_level, 2483 "", 2484 target->string_mb, 2485 vpath_translated->string_mb, 2486 recursion_level, 2487 ""); 2488 } 2489 } 2490 command_changed = true; 2491 line->body.line.is_out_of_date = true; 2492 } 2493 used->command_line = new_command_line; 2494 } 2495 if (command_line.free_after_use) { 2496 retmem(command_line.buffer.start); 2497 } 2498 } 2499 /* Check if the old command is longer than the new for */ 2500 /* command consistency */ 2501 if (used != NULL) { 2502 *insert = NULL; 2503 if (keep_state && 2504 !ignore_all_command_dependency) { 2505 if (debug_level > 0) { 2506 (void) printf(catgets(catd, 1, 34, "%*sBuilding %s because new command shorter than old\n"), 2507 recursion_level, 2508 "", 2509 target->string_mb); 2510 } 2511 command_changed = true; 2512 line->body.line.is_out_of_date = true; 2513 } 2514 } 2515 /* Check if the new command is longer than the old command for */ 2516 /* command consistency */ 2517 if (new_command_longer && 2518 !ignore_all_command_dependency && 2519 keep_state) { 2520 if (debug_level > 0) { 2521 (void) printf(catgets(catd, 1, 35, "%*sBuilding %s because new command longer than old\n"), 2522 recursion_level, 2523 "", 2524 target->string_mb); 2525 } 2526 command_changed = true; 2527 line->body.line.is_out_of_date = true; 2528 } 2529 /* Unbind the magic macros */ 2530 (void) SETVAR(c_at, (Name) NULL, false); 2531 (void) SETVAR(star, (Name) NULL, false); 2532 (void) SETVAR(less_name, (Name) NULL, false); 2533 (void) SETVAR(percent_name, (Name) NULL, false); 2534 (void) SETVAR(query, (Name) NULL, false); 2535 if (query_list != NULL) { 2536 delete_query_chain(query_list); 2537 } 2538 (void) SETVAR(hat, (Name) NULL, false); 2539 if (hat_list != NULL) { 2540 delete_query_chain(hat_list); 2541 } 2542 2543 if (conditional_macro_used) { 2544 target->conditional_macro_list = cond_macro_list; 2545 cond_macro_list = NULL; 2546 target->depends_on_conditional = true; 2547 } 2548 } 2549 2550 /* 2551 * touch_command(line, target, result) 2552 * 2553 * If this is an "make -t" run we do this. 2554 * We touch all targets in the target group ("foo + fie:") if any. 2555 * 2556 * Return value: 2557 * Indicates if the command failed or not 2558 * 2559 * Parameters: 2560 * line The command line to update 2561 * target The target we are touching 2562 * result Initial value for the result we return 2563 * 2564 * Global variables used: 2565 * do_not_exec_rule Indicates that -n is on 2566 * silent Do not echo commands 2567 */ 2568 static Doname 2569 touch_command(register Property line, register Name target, Doname result) 2570 { 2571 Name name; 2572 register Chain target_group; 2573 String_rec touch_string; 2574 wchar_t buffer[MAXPATHLEN]; 2575 Name touch_cmd; 2576 Cmd_line rule; 2577 2578 2579 SEND_MTOOL_MSG( 2580 if (!sent_rsrc_info_msg) { 2581 if (userName[0] == '\0') { 2582 avo_get_user(userName, NULL); 2583 } 2584 if (hostName[0] == '\0') { 2585 strcpy(hostName, avo_hostname()); 2586 } 2587 send_rsrc_info_msg(1, hostName, userName); 2588 sent_rsrc_info_msg = 1; 2589 } 2590 send_job_start_msg(line); 2591 job_result_msg = new Avo_MToolJobResultMsg(); 2592 ); 2593 for (name = target, target_group = NULL; name != NULL;) { 2594 if (!name->is_member) { 2595 /* 2596 * Build a touch command that can be passed 2597 * to dosys(). If KEEP_STATE is on, "make -t" 2598 * will save the proper command, not the 2599 * "touch" in .make.state. 2600 */ 2601 INIT_STRING_FROM_STACK(touch_string, buffer); 2602 MBSTOWCS(wcs_buffer, NOCATGETS("touch ")); 2603 append_string(wcs_buffer, &touch_string, FIND_LENGTH); 2604 touch_cmd = name; 2605 if (name->has_vpath_alias_prop) { 2606 touch_cmd = get_prop(name->prop, 2607 vpath_alias_prop)-> 2608 body.vpath_alias.alias; 2609 } 2610 APPEND_NAME(touch_cmd, 2611 &touch_string, 2612 FIND_LENGTH); 2613 touch_cmd = GETNAME(touch_string.buffer.start, 2614 FIND_LENGTH); 2615 if (touch_string.free_after_use) { 2616 retmem(touch_string.buffer.start); 2617 } 2618 if (!silent || 2619 do_not_exec_rule && 2620 (target_group == NULL)) { 2621 (void) printf("%s\n", touch_cmd->string_mb); 2622 SEND_MTOOL_MSG( 2623 job_result_msg->appendOutput(AVO_STRDUP(touch_cmd->string_mb)); 2624 ); 2625 } 2626 /* Run the touch command, or simulate it */ 2627 if (!do_not_exec_rule) { 2628 2629 SEND_MTOOL_MSG( 2630 (void) sprintf(mbstring, 2631 NOCATGETS("%s/make.stdout.%d.%d.XXXXXX"), 2632 tmpdir, 2633 getpid(), 2634 file_number++); 2635 2636 int tmp_fd = mkstemp(mbstring); 2637 if(tmp_fd) { 2638 (void) close(tmp_fd); 2639 } 2640 2641 stdout_file = strdup(mbstring); 2642 stderr_file = NULL; 2643 child_pid = pollResults(stdout_file, 2644 (char *)NULL, 2645 (char *)NULL); 2646 ); 2647 2648 result = dosys(touch_cmd, 2649 false, 2650 false, 2651 false, 2652 false, 2653 name, 2654 send_mtool_msgs); 2655 2656 SEND_MTOOL_MSG( 2657 append_job_result_msg(job_result_msg); 2658 if (child_pid > 0) { 2659 kill(child_pid, SIGUSR1); 2660 while (!((waitpid(child_pid, 0, 0) == -1) 2661 && (errno == ECHILD))); 2662 } 2663 child_pid = 0; 2664 (void) unlink(stdout_file); 2665 retmem_mb(stdout_file); 2666 stdout_file = NULL; 2667 ); 2668 2669 } else { 2670 result = build_ok; 2671 } 2672 } else { 2673 result = build_ok; 2674 } 2675 if (target_group == NULL) { 2676 target_group = line->body.line.target_group; 2677 } else { 2678 target_group = target_group->next; 2679 } 2680 if (target_group != NULL) { 2681 name = target_group->name; 2682 } else { 2683 name = NULL; 2684 } 2685 } 2686 SEND_MTOOL_MSG( 2687 job_result_msg->setResult(job_msg_id, (result == build_ok) ? 0 : 1, DONE); 2688 xdr_msg = (RWCollectable*) job_result_msg; 2689 xdr(&xdrs, xdr_msg); 2690 (void) fflush(mtool_msgs_fp); 2691 delete job_result_msg; 2692 ); 2693 return result; 2694 } 2695 2696 /* 2697 * update_target(line, result) 2698 * 2699 * updates the status of a target after executing its commands. 2700 * 2701 * Parameters: 2702 * line The command line block to update 2703 * result Indicates that build is OK so can update 2704 * 2705 * Global variables used: 2706 * do_not_exec_rule Indicates that -n is on 2707 * touch Fake the new timestamp if we are just touching 2708 */ 2709 void 2710 update_target(Property line, Doname result) 2711 { 2712 Name target; 2713 Chain target_group; 2714 Property line2; 2715 timestruc_t old_stat_time; 2716 Property member; 2717 2718 /* 2719 * [tolik] Additional fix for bug 1063790. It was fixed 2720 * for serial make long ago, but DMake dumps core when 2721 * target is a symlink and sccs file is newer then target. 2722 * In this case, finish_children() calls update_target() 2723 * with line==NULL. 2724 */ 2725 if(line == NULL) { 2726 /* XXX. Should we do anything here? */ 2727 return; 2728 } 2729 2730 target = line->body.line.target; 2731 2732 if ((result == build_ok) && (line->body.line.command_used != NULL)) { 2733 if (do_not_exec_rule || 2734 touch || 2735 (target->is_member && 2736 (line->body.line.command_template != NULL) && 2737 (line->body.line.command_template->command_line->string_mb[0] == 0) && 2738 (line->body.line.command_template->next == NULL))) { 2739 /* If we are simulating execution we need to fake a */ 2740 /* new timestamp for the target we didnt build */ 2741 target->stat.time = file_max_time; 2742 } else { 2743 /* 2744 * If we really built the target we read the new 2745 * timestamp. 2746 * Fix for bug #1110906: if .c file is newer than 2747 * the corresponding .o file which is in an archive 2748 * file, make will compile the .c file but it won't 2749 * update the object in the .a file. 2750 */ 2751 old_stat_time = target->stat.time; 2752 target->stat.time = file_no_time; 2753 (void) exists(target); 2754 if ((target->is_member) && 2755 (target->stat.time == old_stat_time)) { 2756 member = get_prop(target->prop, member_prop); 2757 if (member != NULL) { 2758 target->stat.time = member->body.member.library->stat.time; 2759 target->stat.time.tv_sec++; 2760 } 2761 } 2762 } 2763 /* If the target is part of a group we need to propagate the */ 2764 /* result of the run to all members */ 2765 for (target_group = line->body.line.target_group; 2766 target_group != NULL; 2767 target_group = target_group->next) { 2768 target_group->name->stat.time = target->stat.time; 2769 line2 = maybe_append_prop(target_group->name, 2770 line_prop); 2771 line2->body.line.command_used = 2772 line->body.line.command_used; 2773 line2->body.line.target = target_group->name; 2774 } 2775 } 2776 target->has_built = true; 2777 } 2778 2779 /* 2780 * sccs_get(target, command) 2781 * 2782 * Figures out if it possible to sccs get a file 2783 * and builds the command to do it if it is. 2784 * 2785 * Return value: 2786 * Indicates if sccs get failed or not 2787 * 2788 * Parameters: 2789 * target Target to get 2790 * command Where to deposit command to use 2791 * 2792 * Global variables used: 2793 * debug_level Should we trace activities? 2794 * recursion_level Used for tracing 2795 * sccs_get_rule The rule to used for sccs getting 2796 */ 2797 static Doname 2798 sccs_get(register Name target, register Property *command) 2799 { 2800 register int result; 2801 char link[MAXPATHLEN]; 2802 String_rec string; 2803 wchar_t name[MAXPATHLEN]; 2804 register wchar_t *p; 2805 timestruc_t sccs_time; 2806 register Property line; 2807 int sym_link_depth = 0; 2808 2809 /* For sccs, we need to chase symlinks. */ 2810 while (target->stat.is_sym_link) { 2811 if (sym_link_depth++ > 90) { 2812 fatal(catgets(catd, 1, 95, "Can't read symbolic link `%s': Number of symbolic links encountered during path name traversal exceeds 90."), 2813 target->string_mb); 2814 } 2815 /* Read the value of the link. */ 2816 result = readlink_vroot(target->string_mb, 2817 link, 2818 sizeof(link), 2819 NULL, 2820 VROOT_DEFAULT); 2821 if (result == -1) { 2822 fatal(catgets(catd, 1, 36, "Can't read symbolic link `%s': %s"), 2823 target->string_mb, errmsg(errno)); 2824 } 2825 link[result] = 0; 2826 /* Use the value to build the proper filename. */ 2827 INIT_STRING_FROM_STACK(string, name); 2828 2829 Wstring wcb(target); 2830 if ((link[0] != slash_char) && 2831 ((p = (wchar_t *) wsrchr(wcb.get_string(), slash_char)) != NULL)) { 2832 append_string(wcb.get_string(), &string, p - wcb.get_string() + 1); 2833 } 2834 append_string(link, &string, result); 2835 /* Replace the old name with the translated name. */ 2836 target = normalize_name(string.buffer.start, string.text.p - string.buffer.start); 2837 (void) exists(target); 2838 if (string.free_after_use) { 2839 retmem(string.buffer.start); 2840 } 2841 } 2842 2843 /* 2844 * read_dir() also reads the ?/SCCS dir and saves information 2845 * about which files have SCSC/s. files. 2846 */ 2847 if (target->stat.has_sccs == DONT_KNOW_SCCS) { 2848 read_directory_of_file(target); 2849 } 2850 switch (target->stat.has_sccs) { 2851 case DONT_KNOW_SCCS: 2852 /* We dont know by now there is no SCCS/s.* */ 2853 target->stat.has_sccs = NO_SCCS; 2854 case NO_SCCS: 2855 /* 2856 * If there is no SCCS/s.* but the plain file exists, 2857 * we say things are OK. 2858 */ 2859 if (target->stat.time > file_doesnt_exist) { 2860 return build_ok; 2861 } 2862 /* If we cant find the plain file, we give up. */ 2863 return build_dont_know; 2864 case HAS_SCCS: 2865 /* 2866 * Pay dirt. We now need to figure out if the plain file 2867 * is out of date relative to the SCCS/s.* file. 2868 */ 2869 sccs_time = exists(get_prop(target->prop, 2870 sccs_prop)->body.sccs.file); 2871 break; 2872 } 2873 2874 if ((!target->has_complained && 2875 (sccs_time != file_doesnt_exist) && 2876 (sccs_get_rule != NULL))) { 2877 /* only checking */ 2878 if (command == NULL) { 2879 return build_ok; 2880 } 2881 /* 2882 * We provide a command line for the target. The line is a 2883 * "sccs get" command from default.mk. 2884 */ 2885 line = maybe_append_prop(target, line_prop); 2886 *command = line; 2887 if (sccs_time > target->stat.time) { 2888 /* 2889 * And only if the plain file is out of date do we 2890 * request execution of the command. 2891 */ 2892 line->body.line.is_out_of_date = true; 2893 if (debug_level > 0) { 2894 (void) printf(catgets(catd, 1, 37, "%*sSccs getting %s because s. file is younger than source file\n"), 2895 recursion_level, 2896 "", 2897 target->string_mb); 2898 } 2899 } 2900 line->body.line.sccs_command = true; 2901 line->body.line.command_template = sccs_get_rule; 2902 if(!svr4 && (!allrules_read || posix)) { 2903 if((target->prop) && 2904 (target->prop->body.sccs.file) && 2905 (target->prop->body.sccs.file->string_mb)) { 2906 if((strlen(target->prop->body.sccs.file->string_mb) == 2907 strlen(target->string_mb) + 2) && 2908 (target->prop->body.sccs.file->string_mb[0] == 's') && 2909 (target->prop->body.sccs.file->string_mb[1] == '.')) { 2910 2911 line->body.line.command_template = get_posix_rule; 2912 } 2913 } 2914 } 2915 line->body.line.target = target; 2916 /* 2917 * Also make sure the rule is build with $* and $< 2918 * bound properly. 2919 */ 2920 line->body.line.star = NULL; 2921 line->body.line.less = NULL; 2922 line->body.line.percent = NULL; 2923 return build_ok; 2924 } 2925 return build_dont_know; 2926 } 2927 2928 /* 2929 * read_directory_of_file(file) 2930 * 2931 * Reads the directory the specified file lives in. 2932 * 2933 * Parameters: 2934 * file The file we need to read dir for 2935 * 2936 * Global variables used: 2937 * dot The Name ".", used as the default dir 2938 */ 2939 void 2940 read_directory_of_file(register Name file) 2941 { 2942 2943 Wstring file_string(file); 2944 wchar_t * wcb = file_string.get_string(); 2945 wchar_t usr_include_buf[MAXPATHLEN]; 2946 wchar_t usr_include_sys_buf[MAXPATHLEN]; 2947 2948 register Name directory = dot; 2949 register wchar_t *p = (wchar_t *) wsrchr(wcb, 2950 (int) slash_char); 2951 register int length = p - wcb; 2952 static Name usr_include; 2953 static Name usr_include_sys; 2954 2955 if (usr_include == NULL) { 2956 MBSTOWCS(usr_include_buf, NOCATGETS("/usr/include")); 2957 usr_include = GETNAME(usr_include_buf, FIND_LENGTH); 2958 MBSTOWCS(usr_include_sys_buf, NOCATGETS("/usr/include/sys")); 2959 usr_include_sys = GETNAME(usr_include_sys_buf, FIND_LENGTH); 2960 } 2961 2962 /* 2963 * If the filename contains a "/" we have to extract the path 2964 * Else the path defaults to ".". 2965 */ 2966 if (p != NULL) { 2967 /* 2968 * Check some popular directories first to possibly 2969 * save time. Compare string length first to gain speed. 2970 */ 2971 if ((usr_include->hash.length == length) && 2972 IS_WEQUALN(usr_include_buf, 2973 wcb, 2974 length)) { 2975 directory = usr_include; 2976 } else if ((usr_include_sys->hash.length == length) && 2977 IS_WEQUALN(usr_include_sys_buf, 2978 wcb, 2979 length)) { 2980 directory = usr_include_sys; 2981 } else { 2982 directory = GETNAME(wcb, length); 2983 } 2984 } 2985 (void) read_dir(directory, 2986 (wchar_t *) NULL, 2987 (Property) NULL, 2988 (wchar_t *) NULL); 2989 } 2990 2991 /* 2992 * add_pattern_conditionals(target) 2993 * 2994 * Scan the list of conditionals defined for pattern targets and add any 2995 * that match this target to its list of conditionals. 2996 * 2997 * Parameters: 2998 * target The target we should add conditionals for 2999 * 3000 * Global variables used: 3001 * conditionals The list of pattern conditionals 3002 */ 3003 static void 3004 add_pattern_conditionals(register Name target) 3005 { 3006 register Property conditional; 3007 Property new_prop; 3008 Property *previous; 3009 Name_rec dummy; 3010 wchar_t *pattern; 3011 wchar_t *percent; 3012 int length; 3013 3014 Wstring wcb(target); 3015 Wstring wcb1; 3016 3017 for (conditional = get_prop(conditionals->prop, conditional_prop); 3018 conditional != NULL; 3019 conditional = get_prop(conditional->next, conditional_prop)) { 3020 wcb1.init(conditional->body.conditional.target); 3021 pattern = wcb1.get_string(); 3022 if (pattern[1] != 0) { 3023 percent = (wchar_t *) wschr(pattern, (int) percent_char); 3024 if (!wcb.equaln(pattern, percent-pattern) || 3025 !IS_WEQUAL(wcb.get_string(wcb.length()-wslen(percent+1)), percent+1)) { 3026 continue; 3027 } 3028 } 3029 for (previous = &target->prop; 3030 *previous != NULL; 3031 previous = &(*previous)->next) { 3032 if (((*previous)->type == conditional_prop) && 3033 ((*previous)->body.conditional.sequence > 3034 conditional->body.conditional.sequence)) { 3035 break; 3036 } 3037 } 3038 if (*previous == NULL) { 3039 new_prop = append_prop(target, conditional_prop); 3040 } else { 3041 dummy.prop = NULL; 3042 new_prop = append_prop(&dummy, conditional_prop); 3043 new_prop->next = *previous; 3044 *previous = new_prop; 3045 } 3046 target->conditional_cnt++; 3047 new_prop->body.conditional = conditional->body.conditional; 3048 } 3049 } 3050 3051 /* 3052 * set_locals(target, old_locals) 3053 * 3054 * Sets any conditional macros for the target. 3055 * Each target carries a possibly empty set of conditional properties. 3056 * 3057 * Parameters: 3058 * target The target to set conditional macros for 3059 * old_locals Space to store old values in 3060 * 3061 * Global variables used: 3062 * debug_level Should we trace activity? 3063 * is_conditional We need to preserve this value 3064 * recursion_level Used for tracing 3065 */ 3066 void 3067 set_locals(register Name target, register Property old_locals) 3068 { 3069 register Property conditional; 3070 register int i; 3071 register Boolean saved_conditional_macro_used; 3072 Chain cond_name; 3073 Chain cond_chain; 3074 3075 if (target->dont_activate_cond_values) { 3076 return; 3077 } 3078 3079 saved_conditional_macro_used = conditional_macro_used; 3080 3081 /* Scan the list of conditional properties and apply each one */ 3082 for (conditional = get_prop(target->prop, conditional_prop), i = 0; 3083 conditional != NULL; 3084 conditional = get_prop(conditional->next, conditional_prop), 3085 i++) { 3086 /* Save the old value */ 3087 old_locals[i].body.macro = 3088 maybe_append_prop(conditional->body.conditional.name, 3089 macro_prop)->body.macro; 3090 if (debug_level > 1) { 3091 (void) printf(catgets(catd, 1, 38, "%*sActivating conditional value: "), 3092 recursion_level, 3093 ""); 3094 } 3095 /* Set the conditional value. Macros are expanded when the */ 3096 /* macro is refd as usual */ 3097 if ((conditional->body.conditional.name != virtual_root) || 3098 (conditional->body.conditional.value != virtual_root)) { 3099 (void) SETVAR(conditional->body.conditional.name, 3100 conditional->body.conditional.value, 3101 (Boolean) conditional->body.conditional.append); 3102 } 3103 cond_name = ALLOC(Chain); 3104 cond_name->name = conditional->body.conditional.name; 3105 } 3106 /* Put this target on the front of the chain of conditional targets */ 3107 cond_chain = ALLOC(Chain); 3108 cond_chain->name = target; 3109 cond_chain->next = conditional_targets; 3110 conditional_targets = cond_chain; 3111 conditional_macro_used = saved_conditional_macro_used; 3112 } 3113 3114 /* 3115 * reset_locals(target, old_locals, conditional, index) 3116 * 3117 * Removes any conditional macros for the target. 3118 * 3119 * Parameters: 3120 * target The target we are retoring values for 3121 * old_locals The values to restore 3122 * conditional The first conditional block for the target 3123 * index into the old_locals vector 3124 * Global variables used: 3125 * debug_level Should we trace activities? 3126 * recursion_level Used for tracing 3127 */ 3128 void 3129 reset_locals(register Name target, register Property old_locals, register Property conditional, register int index) 3130 { 3131 register Property this_conditional; 3132 Chain cond_chain; 3133 3134 if (target->dont_activate_cond_values) { 3135 return; 3136 } 3137 3138 /* Scan the list of conditional properties and restore the old value */ 3139 /* to each one Reverse the order relative to when we assigned macros */ 3140 this_conditional = get_prop(conditional->next, conditional_prop); 3141 if (this_conditional != NULL) { 3142 reset_locals(target, old_locals, this_conditional, index+1); 3143 } else { 3144 /* Remove conditional target from chain */ 3145 if (conditional_targets == NULL || 3146 conditional_targets->name != target) { 3147 warning(catgets(catd, 1, 39, "Internal error: reset target not at head of condtional_targets chain")); 3148 } else { 3149 cond_chain = conditional_targets->next; 3150 retmem_mb((caddr_t) conditional_targets); 3151 conditional_targets = cond_chain; 3152 } 3153 } 3154 get_prop(conditional->body.conditional.name->prop, 3155 macro_prop)->body.macro = old_locals[index].body.macro; 3156 if (conditional->body.conditional.name == virtual_root) { 3157 (void) SETVAR(virtual_root, getvar(virtual_root), false); 3158 } 3159 if (debug_level > 1) { 3160 if (old_locals[index].body.macro.value != NULL) { 3161 (void) printf(catgets(catd, 1, 40, "%*sdeactivating conditional value: %s= %s\n"), 3162 recursion_level, 3163 "", 3164 conditional->body.conditional.name-> 3165 string_mb, 3166 old_locals[index].body.macro.value-> 3167 string_mb); 3168 } else { 3169 (void) printf(catgets(catd, 1, 41, "%*sdeactivating conditional value: %s =\n"), 3170 recursion_level, 3171 "", 3172 conditional->body.conditional.name-> 3173 string_mb); 3174 } 3175 } 3176 } 3177 3178 /* 3179 * check_auto_dependencies(target, auto_count, automatics) 3180 * 3181 * Returns true if the target now has a dependency 3182 * it didn't previously have (saved on automatics). 3183 * 3184 * Return value: 3185 * true if new dependency found 3186 * 3187 * Parameters: 3188 * target Target we check 3189 * auto_count Number of old automatic vars 3190 * automatics Saved old automatics 3191 * 3192 * Global variables used: 3193 * keep_state Indicates that .KEEP_STATE is on 3194 */ 3195 Boolean 3196 check_auto_dependencies(Name target, int auto_count, Name *automatics) 3197 { 3198 Name *p; 3199 int n; 3200 Property line; 3201 Dependency dependency; 3202 3203 if (keep_state) { 3204 if ((line = get_prop(target->prop, line_prop)) == NULL) { 3205 return false; 3206 } 3207 /* Go thru new list of automatic depes */ 3208 for (dependency = line->body.line.dependencies; 3209 dependency != NULL; 3210 dependency = dependency->next) { 3211 /* And make sure that each one existed before we */ 3212 /* built the target */ 3213 if (dependency->automatic && !dependency->stale) { 3214 for (n = auto_count, p = automatics; 3215 n > 0; 3216 n--) { 3217 if (*p++ == dependency->name) { 3218 /* If we can find it on the */ 3219 /* saved list of autos we */ 3220 /* are OK */ 3221 goto not_new; 3222 } 3223 } 3224 /* But if we scan over the old list */ 3225 /* of auto. without finding it it is */ 3226 /* new and we must check it */ 3227 return true; 3228 } 3229 not_new:; 3230 } 3231 return false; 3232 } else { 3233 return false; 3234 } 3235 } 3236 3237 3238 // Recursively delete each of the Chain struct on the chain. 3239 3240 static void 3241 delete_query_chain(Chain ch) 3242 { 3243 if (ch == NULL) { 3244 return; 3245 } else { 3246 delete_query_chain(ch->next); 3247 retmem_mb((char *) ch); 3248 } 3249 } 3250 3251 Doname 3252 target_can_be_built(register Name target) { 3253 Doname result = build_dont_know; 3254 Name true_target = target; 3255 Property line; 3256 3257 if (target == wait_name) { 3258 return(build_ok); 3259 } 3260 /* 3261 * If the target is a constructed one for a "::" target, 3262 * we need to consider that. 3263 */ 3264 if (target->has_target_prop) { 3265 true_target = get_prop(target->prop, 3266 target_prop)->body.target.target; 3267 } 3268 3269 (void) exists(true_target); 3270 3271 if (true_target->state == build_running) { 3272 return(build_running); 3273 } 3274 if (true_target->stat.time != file_doesnt_exist) { 3275 result = build_ok; 3276 } 3277 3278 /* get line property for the target */ 3279 line = get_prop(true_target->prop, line_prop); 3280 3281 /* first check for explicit rule */ 3282 if (line != NULL && line->body.line.command_template != NULL) { 3283 result = build_ok; 3284 } 3285 /* try to find pattern rule */ 3286 if (result == build_dont_know) { 3287 result = find_percent_rule(target, NULL, false); 3288 } 3289 3290 /* try to find double suffix rule */ 3291 if (result == build_dont_know) { 3292 if (target->is_member) { 3293 Property member = get_prop(target->prop, member_prop); 3294 if (member != NULL && member->body.member.member != NULL) { 3295 result = find_ar_suffix_rule(target, member->body.member.member, NULL, false); 3296 } else { 3297 result = find_double_suffix_rule(target, NULL, false); 3298 } 3299 } else { 3300 result = find_double_suffix_rule(target, NULL, false); 3301 } 3302 } 3303 3304 /* try to find suffix rule */ 3305 if ((result == build_dont_know) && second_pass) { 3306 result = find_suffix_rule(target, target, empty_name, NULL, false); 3307 } 3308 3309 /* check for sccs */ 3310 if (result == build_dont_know) { 3311 result = sccs_get(target, NULL); 3312 } 3313 3314 /* try to find dyn target */ 3315 if (result == build_dont_know) { 3316 Name dtarg = find_dyntarget(target); 3317 if (dtarg != NULL) { 3318 result = target_can_be_built(dtarg); 3319 } 3320 } 3321 3322 /* check whether target was mentioned in makefile */ 3323 if (result == build_dont_know) { 3324 if (target->colons != no_colon) { 3325 result = build_ok; 3326 } 3327 } 3328 3329 /* result */ 3330 return result; 3331 }