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