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