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