1 /* 2 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 3 * Copyright (c) 1988, 1989 by Adam de Boor 4 * Copyright (c) 1989 by Berkeley Softworks 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * %sccs.include.redist.c% 11 */ 12 13 #ifndef lint 14 static char sccsid[] = "@(#)arch.c 5.8 (Berkeley) 05/24/93"; 15 #endif /* not lint */ 16 17 /*- 18 * arch.c -- 19 * Functions to manipulate libraries, archives and their members. 20 * 21 * Once again, cacheing/hashing comes into play in the manipulation 22 * of archives. The first time an archive is referenced, all of its members' 23 * headers are read and hashed and the archive closed again. All hashed 24 * archives are kept on a list which is searched each time an archive member 25 * is referenced. 26 * 27 * The interface to this module is: 28 * Arch_ParseArchive Given an archive specification, return a list 29 * of GNode's, one for each member in the spec. 30 * FAILURE is returned if the specification is 31 * invalid for some reason. 32 * 33 * Arch_Touch Alter the modification time of the archive 34 * member described by the given node to be 35 * the current time. 36 * 37 * Arch_TouchLib Update the modification time of the library 38 * described by the given node. This is special 39 * because it also updates the modification time 40 * of the library's table of contents. 41 * 42 * Arch_MTime Find the modification time of a member of 43 * an archive *in the archive*. The time is also 44 * placed in the member's GNode. Returns the 45 * modification time. 46 * 47 * Arch_MemTime Find the modification time of a member of 48 * an archive. Called when the member doesn't 49 * already exist. Looks in the archive for the 50 * modification time. Returns the modification 51 * time. 52 * 53 * Arch_FindLib Search for a library along a path. The 54 * library name in the GNode should be in 55 * -l<name> format. 56 * 57 * Arch_LibOODate Special function to decide if a library node 58 * is out-of-date. 59 * 60 * Arch_Init Initialize this module. 61 */ 62 63 #include <sys/types.h> 64 #include <sys/stat.h> 65 #include <sys/time.h> 66 #include <ctype.h> 67 #include <ar.h> 68 #include <ranlib.h> 69 #include <stdio.h> 70 #include "make.h" 71 #include "hash.h" 72 #include "dir.h" 73 #include "config.h" 74 75 static Lst archives; /* Lst of archives we've already examined */ 76 77 typedef struct Arch { 78 char *name; /* Name of archive */ 79 Hash_Table members; /* All the members of the archive described 80 * by <name, struct ar_hdr *> key/value pairs */ 81 } Arch; 82 83 static int ArchFindArchive __P((Arch *, char *)); 84 static struct ar_hdr *ArchStatMember __P((char *, char *, Boolean)); 85 static FILE *ArchFindMember __P((char *, char *, struct ar_hdr *, char *)); 86 87 /*- 88 *----------------------------------------------------------------------- 89 * Arch_ParseArchive -- 90 * Parse the archive specification in the given line and find/create 91 * the nodes for the specified archive members, placing their nodes 92 * on the given list. 93 * 94 * Results: 95 * SUCCESS if it was a valid specification. The linePtr is updated 96 * to point to the first non-space after the archive spec. The 97 * nodes for the members are placed on the given list. 98 * 99 * Side Effects: 100 * Some nodes may be created. The given list is extended. 101 * 102 *----------------------------------------------------------------------- 103 */ 104 ReturnStatus 105 Arch_ParseArchive (linePtr, nodeLst, ctxt) 106 char **linePtr; /* Pointer to start of specification */ 107 Lst nodeLst; /* Lst on which to place the nodes */ 108 GNode *ctxt; /* Context in which to expand variables */ 109 { 110 register char *cp; /* Pointer into line */ 111 GNode *gn; /* New node */ 112 char *libName; /* Library-part of specification */ 113 char *memName; /* Member-part of specification */ 114 char nameBuf[MAKE_BSIZE]; /* temporary place for node name */ 115 char saveChar; /* Ending delimiter of member-name */ 116 Boolean subLibName; /* TRUE if libName should have/had 117 * variable substitution performed on it */ 118 119 libName = *linePtr; 120 121 subLibName = FALSE; 122 123 for (cp = libName; *cp != '(' && *cp != '\0'; cp++) { 124 if (*cp == '$') { 125 /* 126 * Variable spec, so call the Var module to parse the puppy 127 * so we can safely advance beyond it... 128 */ 129 int length; 130 Boolean freeIt; 131 char *result; 132 133 result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt); 134 if (result == var_Error) { 135 return(FAILURE); 136 } else { 137 subLibName = TRUE; 138 } 139 140 if (freeIt) { 141 free(result); 142 } 143 cp += length-1; 144 } 145 } 146 147 *cp++ = '\0'; 148 if (subLibName) { 149 libName = Var_Subst(NULL, libName, ctxt, TRUE); 150 } 151 152 153 for (;;) { 154 /* 155 * First skip to the start of the member's name, mark that 156 * place and skip to the end of it (either white-space or 157 * a close paren). 158 */ 159 Boolean doSubst = FALSE; /* TRUE if need to substitute in memName */ 160 161 while (*cp != '\0' && *cp != ')' && isspace (*cp)) { 162 cp++; 163 } 164 memName = cp; 165 while (*cp != '\0' && *cp != ')' && !isspace (*cp)) { 166 if (*cp == '$') { 167 /* 168 * Variable spec, so call the Var module to parse the puppy 169 * so we can safely advance beyond it... 170 */ 171 int length; 172 Boolean freeIt; 173 char *result; 174 175 result=Var_Parse(cp, ctxt, TRUE, &length, &freeIt); 176 if (result == var_Error) { 177 return(FAILURE); 178 } else { 179 doSubst = TRUE; 180 } 181 182 if (freeIt) { 183 free(result); 184 } 185 cp += length; 186 } else { 187 cp++; 188 } 189 } 190 191 /* 192 * If the specification ends without a closing parenthesis, 193 * chances are there's something wrong (like a missing backslash), 194 * so it's better to return failure than allow such things to happen 195 */ 196 if (*cp == '\0') { 197 printf("No closing parenthesis in archive specification\n"); 198 return (FAILURE); 199 } 200 201 /* 202 * If we didn't move anywhere, we must be done 203 */ 204 if (cp == memName) { 205 break; 206 } 207 208 saveChar = *cp; 209 *cp = '\0'; 210 211 /* 212 * XXX: This should be taken care of intelligently by 213 * SuffExpandChildren, both for the archive and the member portions. 214 */ 215 /* 216 * If member contains variables, try and substitute for them. 217 * This will slow down archive specs with dynamic sources, of course, 218 * since we'll be (non-)substituting them three times, but them's 219 * the breaks -- we need to do this since SuffExpandChildren calls 220 * us, otherwise we could assume the thing would be taken care of 221 * later. 222 */ 223 if (doSubst) { 224 char *buf; 225 char *sacrifice; 226 char *oldMemName = memName; 227 228 memName = Var_Subst(NULL, memName, ctxt, TRUE); 229 230 /* 231 * Now form an archive spec and recurse to deal with nested 232 * variables and multi-word variable values.... The results 233 * are just placed at the end of the nodeLst we're returning. 234 */ 235 buf = sacrifice = emalloc(strlen(memName)+strlen(libName)+3); 236 237 sprintf(buf, "%s(%s)", libName, memName); 238 239 if (strchr(memName, '$') && strcmp(memName, oldMemName) == 0) { 240 /* 241 * Must contain dynamic sources, so we can't deal with it now. 242 * Just create an ARCHV node for the thing and let 243 * SuffExpandChildren handle it... 244 */ 245 gn = Targ_FindNode(buf, TARG_CREATE); 246 247 if (gn == NILGNODE) { 248 free(buf); 249 return(FAILURE); 250 } else { 251 gn->type |= OP_ARCHV; 252 (void)Lst_AtEnd(nodeLst, (ClientData)gn); 253 } 254 } else if (Arch_ParseArchive(&sacrifice, nodeLst, ctxt)!=SUCCESS) { 255 /* 256 * Error in nested call -- free buffer and return FAILURE 257 * ourselves. 258 */ 259 free(buf); 260 return(FAILURE); 261 } 262 /* 263 * Free buffer and continue with our work. 264 */ 265 free(buf); 266 } else if (Dir_HasWildcards(memName)) { 267 Lst members = Lst_Init(FALSE); 268 char *member; 269 270 Dir_Expand(memName, dirSearchPath, members); 271 while (!Lst_IsEmpty(members)) { 272 member = (char *)Lst_DeQueue(members); 273 274 sprintf(nameBuf, "%s(%s)", libName, member); 275 free(member); 276 gn = Targ_FindNode (nameBuf, TARG_CREATE); 277 if (gn == NILGNODE) { 278 return (FAILURE); 279 } else { 280 /* 281 * We've found the node, but have to make sure the rest of 282 * the world knows it's an archive member, without having 283 * to constantly check for parentheses, so we type the 284 * thing with the OP_ARCHV bit before we place it on the 285 * end of the provided list. 286 */ 287 gn->type |= OP_ARCHV; 288 (void) Lst_AtEnd (nodeLst, (ClientData)gn); 289 } 290 } 291 Lst_Destroy(members, NOFREE); 292 } else { 293 sprintf(nameBuf, "%s(%s)", libName, memName); 294 gn = Targ_FindNode (nameBuf, TARG_CREATE); 295 if (gn == NILGNODE) { 296 return (FAILURE); 297 } else { 298 /* 299 * We've found the node, but have to make sure the rest of the 300 * world knows it's an archive member, without having to 301 * constantly check for parentheses, so we type the thing with 302 * the OP_ARCHV bit before we place it on the end of the 303 * provided list. 304 */ 305 gn->type |= OP_ARCHV; 306 (void) Lst_AtEnd (nodeLst, (ClientData)gn); 307 } 308 } 309 if (doSubst) { 310 free(memName); 311 } 312 313 *cp = saveChar; 314 } 315 316 /* 317 * If substituted libName, free it now, since we need it no longer. 318 */ 319 if (subLibName) { 320 free(libName); 321 } 322 323 /* 324 * We promised the pointer would be set up at the next non-space, so 325 * we must advance cp there before setting *linePtr... (note that on 326 * entrance to the loop, cp is guaranteed to point at a ')') 327 */ 328 do { 329 cp++; 330 } while (*cp != '\0' && isspace (*cp)); 331 332 *linePtr = cp; 333 return (SUCCESS); 334 } 335 336 /*- 337 *----------------------------------------------------------------------- 338 * ArchFindArchive -- 339 * See if the given archive is the one we are looking for. Called 340 * From ArchStatMember and ArchFindMember via Lst_Find. 341 * 342 * Results: 343 * 0 if it is, non-zero if it isn't. 344 * 345 * Side Effects: 346 * None. 347 * 348 *----------------------------------------------------------------------- 349 */ 350 static int 351 ArchFindArchive (ar, archName) 352 Arch *ar; /* Current list element */ 353 char *archName; /* Name we want */ 354 { 355 return (strcmp (archName, ar->name)); 356 } 357 358 /*- 359 *----------------------------------------------------------------------- 360 * ArchStatMember -- 361 * Locate a member of an archive, given the path of the archive and 362 * the path of the desired member. 363 * 364 * Results: 365 * A pointer to the current struct ar_hdr structure for the member. Note 366 * That no position is returned, so this is not useful for touching 367 * archive members. This is mostly because we have no assurances that 368 * The archive will remain constant after we read all the headers, so 369 * there's not much point in remembering the position... 370 * 371 * Side Effects: 372 * 373 *----------------------------------------------------------------------- 374 */ 375 static struct ar_hdr * 376 ArchStatMember (archive, member, hash) 377 char *archive; /* Path to the archive */ 378 char *member; /* Name of member. If it is a path, only the 379 * last component is used. */ 380 Boolean hash; /* TRUE if archive should be hashed if not 381 * already so. */ 382 { 383 #define AR_MAX_NAME_LEN (sizeof(arh.ar_name)-1) 384 FILE * arch; /* Stream to archive */ 385 int size; /* Size of archive member */ 386 char *cp; /* Useful character pointer */ 387 char magic[SARMAG]; 388 int len; 389 LstNode ln; /* Lst member containing archive descriptor */ 390 Arch *ar; /* Archive descriptor */ 391 Hash_Entry *he; /* Entry containing member's description */ 392 struct ar_hdr arh; /* archive-member header for reading archive */ 393 char memName[AR_MAX_NAME_LEN+1]; 394 /* Current member name while hashing. The name is 395 * truncated to AR_MAX_NAME_LEN bytes, but we need 396 * room for the null byte... */ 397 char copy[AR_MAX_NAME_LEN+1]; 398 /* Holds copy of last path element from member, if 399 * it has to be truncated, so we don't have to 400 * figure it out again once the table is hashed. */ 401 402 /* 403 * Because of space constraints and similar things, files are archived 404 * using their final path components, not the entire thing, so we need 405 * to point 'member' to the final component, if there is one, to make 406 * the comparisons easier... 407 */ 408 cp = strrchr (member, '/'); 409 if (cp != (char *) NULL) { 410 member = cp + 1; 411 } 412 len = strlen (member); 413 if (len > AR_MAX_NAME_LEN) { 414 len = AR_MAX_NAME_LEN; 415 strncpy(copy, member, AR_MAX_NAME_LEN); 416 copy[AR_MAX_NAME_LEN] = '\0'; 417 member = copy; 418 } 419 420 ln = Lst_Find (archives, (ClientData) archive, ArchFindArchive); 421 if (ln != NILLNODE) { 422 ar = (Arch *) Lst_Datum (ln); 423 424 he = Hash_FindEntry (&ar->members, member); 425 426 if (he != (Hash_Entry *) NULL) { 427 return ((struct ar_hdr *) Hash_GetValue (he)); 428 } else { 429 return ((struct ar_hdr *) NULL); 430 } 431 } 432 433 if (!hash) { 434 /* 435 * Caller doesn't want the thing hashed, just use ArchFindMember 436 * to read the header for the member out and close down the stream 437 * again. Since the archive is not to be hashed, we assume there's 438 * no need to allocate extra room for the header we're returning, 439 * so just declare it static. 440 */ 441 static struct ar_hdr sarh; 442 443 arch = ArchFindMember(archive, member, &sarh, "r"); 444 445 if (arch == (FILE *)NULL) { 446 return ((struct ar_hdr *)NULL); 447 } else { 448 fclose(arch); 449 return (&sarh); 450 } 451 } 452 453 /* 454 * We don't have this archive on the list yet, so we want to find out 455 * everything that's in it and cache it so we can get at it quickly. 456 */ 457 arch = fopen (archive, "r"); 458 if (arch == (FILE *) NULL) { 459 return ((struct ar_hdr *) NULL); 460 } 461 462 /* 463 * We use the ARMAG string to make sure this is an archive we 464 * can handle... 465 */ 466 if ((fread (magic, SARMAG, 1, arch) != 1) || 467 (strncmp (magic, ARMAG, SARMAG) != 0)) { 468 fclose (arch); 469 return ((struct ar_hdr *) NULL); 470 } 471 472 ar = (Arch *)emalloc (sizeof (Arch)); 473 ar->name = strdup (archive); 474 Hash_InitTable (&ar->members, -1); 475 memName[AR_MAX_NAME_LEN] = '\0'; 476 477 while (fread ((char *)&arh, sizeof (struct ar_hdr), 1, arch) == 1) { 478 if (strncmp ( arh.ar_fmag, ARFMAG, sizeof (arh.ar_fmag)) != 0) { 479 /* 480 * The header is bogus, so the archive is bad 481 * and there's no way we can recover... 482 */ 483 fclose (arch); 484 Hash_DeleteTable (&ar->members); 485 free ((Address)ar); 486 return ((struct ar_hdr *) NULL); 487 } else { 488 (void) strncpy (memName, arh.ar_name, sizeof(arh.ar_name)); 489 for (cp = &memName[AR_MAX_NAME_LEN]; *cp == ' '; cp--) { 490 continue; 491 } 492 cp[1] = '\0'; 493 494 he = Hash_CreateEntry (&ar->members, strdup (memName), 495 (Boolean *)NULL); 496 Hash_SetValue (he, (ClientData)emalloc (sizeof (struct ar_hdr))); 497 memcpy ((Address)Hash_GetValue (he), (Address)&arh, 498 sizeof (struct ar_hdr)); 499 } 500 /* 501 * We need to advance the stream's pointer to the start of the 502 * next header. Files are padded with newlines to an even-byte 503 * boundary, so we need to extract the size of the file from the 504 * 'size' field of the header and round it up during the seek. 505 */ 506 arh.ar_size[sizeof(arh.ar_size)-1] = '\0'; 507 (void) sscanf (arh.ar_size, "%10d", &size); 508 fseek (arch, (size + 1) & ~1, 1); 509 } 510 511 fclose (arch); 512 513 (void) Lst_AtEnd (archives, (ClientData) ar); 514 515 /* 516 * Now that the archive has been read and cached, we can look into 517 * the hash table to find the desired member's header. 518 */ 519 he = Hash_FindEntry (&ar->members, member); 520 521 if (he != (Hash_Entry *) NULL) { 522 return ((struct ar_hdr *) Hash_GetValue (he)); 523 } else { 524 return ((struct ar_hdr *) NULL); 525 } 526 } 527 528 /*- 529 *----------------------------------------------------------------------- 530 * ArchFindMember -- 531 * Locate a member of an archive, given the path of the archive and 532 * the path of the desired member. If the archive is to be modified, 533 * the mode should be "r+", if not, it should be "r". 534 * 535 * Results: 536 * An FILE *, opened for reading and writing, positioned at the 537 * start of the member's struct ar_hdr, or NULL if the member was 538 * nonexistent. The current struct ar_hdr for member. 539 * 540 * Side Effects: 541 * The passed struct ar_hdr structure is filled in. 542 * 543 *----------------------------------------------------------------------- 544 */ 545 static FILE * 546 ArchFindMember (archive, member, arhPtr, mode) 547 char *archive; /* Path to the archive */ 548 char *member; /* Name of member. If it is a path, only the 549 * last component is used. */ 550 struct ar_hdr *arhPtr; /* Pointer to header structure to be filled in */ 551 char *mode; /* The mode for opening the stream */ 552 { 553 FILE * arch; /* Stream to archive */ 554 int size; /* Size of archive member */ 555 char *cp; /* Useful character pointer */ 556 char magic[SARMAG]; 557 int len; 558 559 arch = fopen (archive, mode); 560 if (arch == (FILE *) NULL) { 561 return ((FILE *) NULL); 562 } 563 564 /* 565 * We use the ARMAG string to make sure this is an archive we 566 * can handle... 567 */ 568 if ((fread (magic, SARMAG, 1, arch) != 1) || 569 (strncmp (magic, ARMAG, SARMAG) != 0)) { 570 fclose (arch); 571 return ((FILE *) NULL); 572 } 573 574 /* 575 * Because of space constraints and similar things, files are archived 576 * using their final path components, not the entire thing, so we need 577 * to point 'member' to the final component, if there is one, to make 578 * the comparisons easier... 579 */ 580 cp = strrchr (member, '/'); 581 if (cp != (char *) NULL) { 582 member = cp + 1; 583 } 584 len = strlen (member); 585 if (len > sizeof (arhPtr->ar_name)) { 586 len = sizeof (arhPtr->ar_name); 587 } 588 589 while (fread ((char *)arhPtr, sizeof (struct ar_hdr), 1, arch) == 1) { 590 if (strncmp(arhPtr->ar_fmag, ARFMAG, sizeof (arhPtr->ar_fmag) ) != 0) { 591 /* 592 * The header is bogus, so the archive is bad 593 * and there's no way we can recover... 594 */ 595 fclose (arch); 596 return ((FILE *) NULL); 597 } else if (strncmp (member, arhPtr->ar_name, len) == 0) { 598 /* 599 * If the member's name doesn't take up the entire 'name' field, 600 * we have to be careful of matching prefixes. Names are space- 601 * padded to the right, so if the character in 'name' at the end 602 * of the matched string is anything but a space, this isn't the 603 * member we sought. 604 */ 605 if (len != sizeof(arhPtr->ar_name) && arhPtr->ar_name[len] != ' '){ 606 continue; 607 } else { 608 /* 609 * To make life easier, we reposition the file at the start 610 * of the header we just read before we return the stream. 611 * In a more general situation, it might be better to leave 612 * the file at the actual member, rather than its header, but 613 * not here... 614 */ 615 fseek (arch, -sizeof(struct ar_hdr), 1); 616 return (arch); 617 } 618 } else { 619 /* 620 * This isn't the member we're after, so we need to advance the 621 * stream's pointer to the start of the next header. Files are 622 * padded with newlines to an even-byte boundary, so we need to 623 * extract the size of the file from the 'size' field of the 624 * header and round it up during the seek. 625 */ 626 arhPtr->ar_size[sizeof(arhPtr->ar_size)-1] = '\0'; 627 (void)sscanf (arhPtr->ar_size, "%10d", &size); 628 fseek (arch, (size + 1) & ~1, 1); 629 } 630 } 631 632 /* 633 * We've looked everywhere, but the member is not to be found. Close the 634 * archive and return NULL -- an error. 635 */ 636 fclose (arch); 637 return ((FILE *) NULL); 638 } 639 640 /*- 641 *----------------------------------------------------------------------- 642 * Arch_Touch -- 643 * Touch a member of an archive. 644 * 645 * Results: 646 * The 'time' field of the member's header is updated. 647 * 648 * Side Effects: 649 * The modification time of the entire archive is also changed. 650 * For a library, this could necessitate the re-ranlib'ing of the 651 * whole thing. 652 * 653 *----------------------------------------------------------------------- 654 */ 655 void 656 Arch_Touch (gn) 657 GNode *gn; /* Node of member to touch */ 658 { 659 FILE * arch; /* Stream open to archive, positioned properly */ 660 struct ar_hdr arh; /* Current header describing member */ 661 662 arch = ArchFindMember(Var_Value (ARCHIVE, gn), 663 Var_Value (TARGET, gn), 664 &arh, "r+"); 665 sprintf(arh.ar_date, "%-12d", now); 666 667 if (arch != (FILE *) NULL) { 668 (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); 669 fclose (arch); 670 } 671 } 672 673 /*- 674 *----------------------------------------------------------------------- 675 * Arch_TouchLib -- 676 * Given a node which represents a library, touch the thing, making 677 * sure that the table of contents also is touched. 678 * 679 * Results: 680 * None. 681 * 682 * Side Effects: 683 * Both the modification time of the library and of the RANLIBMAG 684 * member are set to 'now'. 685 * 686 *----------------------------------------------------------------------- 687 */ 688 void 689 Arch_TouchLib (gn) 690 GNode *gn; /* The node of the library to touch */ 691 { 692 FILE * arch; /* Stream open to archive */ 693 struct ar_hdr arh; /* Header describing table of contents */ 694 struct timeval times[2]; /* Times for utimes() call */ 695 696 arch = ArchFindMember (gn->path, RANLIBMAG, &arh, "r+"); 697 sprintf(arh.ar_date, "%-12d", now); 698 699 if (arch != (FILE *) NULL) { 700 (void)fwrite ((char *)&arh, sizeof (struct ar_hdr), 1, arch); 701 fclose (arch); 702 703 times[0].tv_sec = times[1].tv_sec = now; 704 times[0].tv_usec = times[1].tv_usec = 0; 705 utimes(gn->path, times); 706 } 707 } 708 709 /*- 710 *----------------------------------------------------------------------- 711 * Arch_MTime -- 712 * Return the modification time of a member of an archive. 713 * 714 * Results: 715 * The modification time (seconds). 716 * 717 * Side Effects: 718 * The mtime field of the given node is filled in with the value 719 * returned by the function. 720 * 721 *----------------------------------------------------------------------- 722 */ 723 int 724 Arch_MTime (gn) 725 GNode *gn; /* Node describing archive member */ 726 { 727 struct ar_hdr *arhPtr; /* Header of desired member */ 728 int modTime; /* Modification time as an integer */ 729 730 arhPtr = ArchStatMember (Var_Value (ARCHIVE, gn), 731 Var_Value (TARGET, gn), 732 TRUE); 733 if (arhPtr != (struct ar_hdr *) NULL) { 734 (void)sscanf (arhPtr->ar_date, "%12d", &modTime); 735 } else { 736 modTime = 0; 737 } 738 739 gn->mtime = modTime; 740 return (modTime); 741 } 742 743 /*- 744 *----------------------------------------------------------------------- 745 * Arch_MemMTime -- 746 * Given a non-existent archive member's node, get its modification 747 * time from its archived form, if it exists. 748 * 749 * Results: 750 * The modification time. 751 * 752 * Side Effects: 753 * The mtime field is filled in. 754 * 755 *----------------------------------------------------------------------- 756 */ 757 int 758 Arch_MemMTime (gn) 759 GNode *gn; 760 { 761 LstNode ln; 762 GNode *pgn; 763 char *nameStart, 764 *nameEnd; 765 766 if (Lst_Open (gn->parents) != SUCCESS) { 767 gn->mtime = 0; 768 return (0); 769 } 770 while ((ln = Lst_Next (gn->parents)) != NILLNODE) { 771 pgn = (GNode *) Lst_Datum (ln); 772 773 if (pgn->type & OP_ARCHV) { 774 /* 775 * If the parent is an archive specification and is being made 776 * and its member's name matches the name of the node we were 777 * given, record the modification time of the parent in the 778 * child. We keep searching its parents in case some other 779 * parent requires this child to exist... 780 */ 781 nameStart = strchr (pgn->name, '(') + 1; 782 nameEnd = strchr (nameStart, ')'); 783 784 if (pgn->make && 785 strncmp(nameStart, gn->name, nameEnd - nameStart) == 0) { 786 gn->mtime = Arch_MTime(pgn); 787 } 788 } else if (pgn->make) { 789 /* 790 * Something which isn't a library depends on the existence of 791 * this target, so it needs to exist. 792 */ 793 gn->mtime = 0; 794 break; 795 } 796 } 797 798 Lst_Close (gn->parents); 799 800 return (gn->mtime); 801 } 802 803 /*- 804 *----------------------------------------------------------------------- 805 * Arch_FindLib -- 806 * Search for a library along the given search path. 807 * 808 * Results: 809 * None. 810 * 811 * Side Effects: 812 * The node's 'path' field is set to the found path (including the 813 * actual file name, not -l...). If the system can handle the -L 814 * flag when linking (or we cannot find the library), we assume that 815 * the user has placed the .LIBRARIES variable in the final linking 816 * command (or the linker will know where to find it) and set the 817 * TARGET variable for this node to be the node's name. Otherwise, 818 * we set the TARGET variable to be the full path of the library, 819 * as returned by Dir_FindFile. 820 * 821 *----------------------------------------------------------------------- 822 */ 823 void 824 Arch_FindLib (gn, path) 825 GNode *gn; /* Node of library to find */ 826 Lst path; /* Search path */ 827 { 828 char *libName; /* file name for archive */ 829 830 libName = (char *)emalloc (strlen (gn->name) + 6 - 2); 831 sprintf(libName, "lib%s.a", &gn->name[2]); 832 833 gn->path = Dir_FindFile (libName, path); 834 835 free (libName); 836 837 #ifdef LIBRARIES 838 Var_Set (TARGET, gn->name, gn); 839 #else 840 Var_Set (TARGET, gn->path == (char *) NULL ? gn->name : gn->path, gn); 841 #endif LIBRARIES 842 } 843 844 /*- 845 *----------------------------------------------------------------------- 846 * Arch_LibOODate -- 847 * Decide if a node with the OP_LIB attribute is out-of-date. Called 848 * from Make_OODate to make its life easier. 849 * 850 * There are several ways for a library to be out-of-date that are 851 * not available to ordinary files. In addition, there are ways 852 * that are open to regular files that are not available to 853 * libraries. A library that is only used as a source is never 854 * considered out-of-date by itself. This does not preclude the 855 * library's modification time from making its parent be out-of-date. 856 * A library will be considered out-of-date for any of these reasons, 857 * given that it is a target on a dependency line somewhere: 858 * Its modification time is less than that of one of its 859 * sources (gn->mtime < gn->cmtime). 860 * Its modification time is greater than the time at which the 861 * make began (i.e. it's been modified in the course 862 * of the make, probably by archiving). 863 * Its modification time doesn't agree with the modification 864 * time of its RANLIBMAG member (i.e. its table of contents 865 * is out-of-date). 866 * 867 * 868 * Results: 869 * TRUE if the library is out-of-date. FALSE otherwise. 870 * 871 * Side Effects: 872 * The library will be hashed if it hasn't been already. 873 * 874 *----------------------------------------------------------------------- 875 */ 876 Boolean 877 Arch_LibOODate (gn) 878 GNode *gn; /* The library's graph node */ 879 { 880 Boolean oodate; 881 882 if (OP_NOP(gn->type) && Lst_IsEmpty(gn->children)) { 883 oodate = FALSE; 884 } else if ((gn->mtime > now) || (gn->mtime < gn->cmtime)) { 885 oodate = TRUE; 886 } else { 887 struct ar_hdr *arhPtr; /* Header for __.SYMDEF */ 888 int modTimeTOC; /* The table-of-contents's mod time */ 889 890 arhPtr = ArchStatMember (gn->path, RANLIBMAG, FALSE); 891 892 if (arhPtr != (struct ar_hdr *)NULL) { 893 (void)sscanf (arhPtr->ar_date, "%12d", &modTimeTOC); 894 895 if (DEBUG(ARCH) || DEBUG(MAKE)) { 896 printf("%s modified %s...", RANLIBMAG, Targ_FmtTime(modTimeTOC)); 897 } 898 oodate = (gn->mtime > modTimeTOC); 899 } else { 900 /* 901 * A library w/o a table of contents is out-of-date 902 */ 903 if (DEBUG(ARCH) || DEBUG(MAKE)) { 904 printf("No t.o.c...."); 905 } 906 oodate = TRUE; 907 } 908 } 909 return (oodate); 910 } 911 912 /*- 913 *----------------------------------------------------------------------- 914 * Arch_Init -- 915 * Initialize things for this module. 916 * 917 * Results: 918 * None. 919 * 920 * Side Effects: 921 * The 'archives' list is initialized. 922 * 923 *----------------------------------------------------------------------- 924 */ 925 void 926 Arch_Init () 927 { 928 archives = Lst_Init (FALSE); 929 } 930