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