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