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