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