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