mykes@3comvax.UUCP (Mike Schwartz) (12/29/85)
*** REPLACE THIS LINE WITH YOUR MESSAGE *** Here is a simple utility I wrote a while back for the Amiga, which can save a lot of compilation time. It is a Lattice and AmigaDos compatible object module librarian with basic replace/add, delete, and directory functions. ALib is like an archive-type tool for those .o files created by the Lattice 'C' compler. Smaller program modules can be compiled and added together into libraries, which can be linked with other object modules. ALib is totally portable between the IBM PC and Native Amiga environments. Theory of Operation: AmigaDos object files have a structure that allows them to be concatonated together and still be valid input to the linker (ALink). ALink reads in object modules in two ways, although it may seem like there are two types of object modules. The filenames listed in the from field are considered object modules, and ALL THE OBJECT CODE in the module will be included in the output (executable) file (Note: This last statement may not be true, but for purposes of this librarian, it doesn't matter). The filenames listed after the library= flag on the linker command line represent library modules from which the linker will only include the code for those objects referenced by the object modules (this appears to be the case from the way my disk drives appear to be seeking thousands of times through lc.lib and amiga.lib during Alink). ALib allows you to create both object modules and libraries. All of the modules (input files to ALink) created by ALib have .lib extensions on them, but may be used as either object modules or libraries, or as both. This allows the programmer the flexibility of including any or all of the linker's options while compiling smaller modules and building libraries of functions that can be used in multiple programs. ALib also creates a .dir file for each .lib file, which contains the information necessary to dynamically substitute, add, or remove any of the individual modules that make up a library. This information includes the name of the .o files used to build the library, the offset into the .lib file where the object module from the .o can be found, and the size of the object module. ALib works "in-place" on a library, which conserves on disk space tremendously. This limits the size of output .lib files to the amount of free memory that ALib has available to it (over 300K on my Amiga). A block of memory is allocated for each object module already existing in the library, as well as for the object modules that are to be added. These blocks of memory are exactly large enough to hold the entire .o input file. Disk access by ALink is extremely efficient, with the minimal amount of head seeks, because it reads the entire .o file with one Lattice read() call. The final output library is also written in Large chunks of Lattice write() calls. The Replace module option is actually a delete module and an add module operation. The delete module operation is simply "forgetting" about it - freeing up the memory used by the module, and deleting the directory entry for the module. The add module is simply reading the new module into memory and adding a directory entry for it. When all the new additions or deletions are done, the new library is recorded back on disk. Comments and Ideas: I used ALib to make clib.lib, which contains lc.lib, amiga.lib, and debug.lib. I can use Library=clib.lib instead of Library=lc.lib+amiga.lib+debug.lib when ALink-ing Lattice 'C' Programs. I use clib.lib all the time, and it works fine. I think that it even saves some seek time to have one big file instead of 3 separate ones. ALink seems to do a lot of head seeks to clib.lib on disk, but from ramdisk, I imagine ALink might actually run fast??? I also am building some libraries, which contain some real useful subroutines and functions to complement the AmigaDos, Intuition, and Rom Kernel functions. Things like serial port/modem protocols, multiple window management, etc. I hope to use these in more than one program. Enjoy! =============================Cut Here===================================== /* * ALIB Rev. 1.0 * Amiga Object Module Librarian * Programmed by Mike Schwartz * (C)1985, MS Software, all rights reserved. * * Feel free to distribute this program on a no-charge basis. * * Use: * ALIB option library filelist * Where * option may be one of the following: * D = delete object modules from library * R = replace object modules (or add if not defined) * L = directory of library * library is the name of the library file to be created or modified. * if no .lib extension is provided on the command line, it is * appended. Also note that a file library.dir is created for * each library file and is managed by this program. * filelist is a list of object module filenames separated by spaces * or commas. Note that if .o is not present in the filenames, * .o will be appended. */ #include "stdio.h" #include "fcntl.h" /* * The following structure defines the records in the .dir file for * the library. */ #define LD struct libdir_def struct libdir_def { char object_filename[80]; /* name of .o file */ long module_offset; /* offset of module in .lib file */ long module_size; /* size of module in bytes */ }; /* * When the library is openned, each object module is read into memory * and managed with the following structure. */ #define LL struct liblist_def struct liblist_def { struct libdir_def dir_entry; /* directory entry for module */ char *object_module; /* actual text of module */ LL *next; /* pointer to next in list */ }; /* * external functions */ extern char *getmem(); extern long lseek(); /* * Global variables */ LL *objlist=NULL; /* linked list of object modules */ char libname[80]; /* name of library file */ int libfd; /* file descriptor for library file */ char objname[80]; /* name of object file */ int objfd; /* file descriptor for object file */ char dirname[80]; /* name of directory file */ int dirfd; /* file descriptor for directory file */ char buf[512]; /* misc buffer */ char option; /* user selected option */ /* * This function prints the help messages and exits. */ help() { printf("Use:\n"); printf(" ALIB option library filelist \n"); printf("Where\n"); printf(" option may be one of the following:\n"); printf(" D = delete object modules from library\n"); printf(" R = replace object modules (or add if not defined) \n"); printf(" L = directory of library\n"); printf(" library is the name of the library file to be created or modified.\n"); printf(" if no .lib extension is provided on the command line, it is \n"); printf(" appended. Also note that a file library.dir is created for\n"); printf(" each library file and is managed by this program. \n"); printf(" filelist is a list of object module filenames separated by spaces\n"); printf(" or commas. Note that if .o is not present in the filenames, \n"); printf(" .o will be appended. \n"); exit(1); } /* * The following function opens the library and directory file. If the * file does not exist, then the user is asked if he wants to create it. * If the library exists, then it is read in and built in a linked list. */ open_library() { LL *lp; /* pointer to module node */ /* * Open the library file and directory file. */ libfd = open(libname, O_RDONLY | O_RAW); if (libfd == -1) { /* * Library does not exist, prompt user for creation. */ while (1) { printf("%s does not exist, create it? (Y/N): ", libname); gets(buf); if (buf[0] == 'y' || buf[0] == 'Y') return !0; if (buf[0] == 'n' || buf[0] == 'N') { printf("Alib abandoned\n"); exit(1); } } } dirfd = open(dirname, O_RDONLY | O_RAW); if (dirfd == -1) { printf("%s has been corrupted\n", dirname); printf("Alib abandoned\n"); exit(1); } /* * library and directory files are open, read in the library. */ while (1) { /* * Allocate a node to hold the object module. */ lp = (LL *)getmem(sizeof(LL)); if (lp == NULL) { printf("Not enough memory.\nAlib abandoned\n"); exit(1); } /* * Check for end of file. */ if (read(dirfd, (char *)&lp->dir_entry, sizeof(LD)) != sizeof(LD)) break; /* * Allocate a buffer to hold the object file image. */ lp->object_module = getmem(lp->dir_entry.module_size); if (lp->object_module == NULL) { printf("Not enough memory.\nAlib abandoned\n"); exit(1); } /* * Read in the object module */ if (read(libfd, lp->object_module, lp->dir_entry.module_size) != lp->dir_entry.module_size) { printf("Library file is corrupted.\nAlib abandoned\n"); exit(1); } /* * Add module to linked list. */ lp->next = objlist; objlist = lp; } /* * Library has been read in ok. Close files and return. */ close(libfd); close(dirfd); printf("Library file read in ok\n"); } /* * The following function removes an object module from the linked list * and frees up any memory used by it. */ kill_module(name) char *name; { LL *lp; LL *lp2; if (objlist == NULL) return 0; strcpy(objname, name); strcat(objname, ".o"); if (strcmp(objlist->dir_entry.object_filename, objname) == 0) { lp = objlist->next; rlsmem(objlist->object_module, objlist->dir_entry.module_size); rlsmem((char *)objlist, sizeof(LL)); objlist = lp; return !0; } for (lp = objlist; lp->next != NULL; lp=lp->next) if (strcmp(lp->next->dir_entry.object_filename, objname) == 0) { lp2 = lp->next; lp->next = lp2->next; rlsmem(lp2->object_module, lp2->dir_entry.module_size); rlsmem((char *)lp2, sizeof(LL)); return !0; } return 0; } /* * The following function */ add_module(name) char *name; { LL *lp; int len; strcpy(objname, name); strcat(objname, ".o"); printf("adding %s\n", objname); /* * Open the object file */ objfd = open(objname, O_RDONLY | O_RAW); if (objfd == -1) { printf("%s cannot be added\nAlib abandoned\n", objname); exit(1); } /* * Allocate a node to hold the file. */ lp = (LL *)getmem(sizeof(LL)); if (lp == NULL) { printf("Not enough memory.\nAlib abandoned\n"); exit(1); } /* * Initialize it. */ strcpy(lp->dir_entry.object_filename, objname); lp->dir_entry.module_size = lseek(objfd, 0, 2); printf("module size = %d\n", lp->dir_entry.module_size); lseek(objfd, 0, 0); /* * Allocate the buffer to read the object module into. */ lp->object_module = getmem(lp->dir_entry.module_size); if (lp->object_module == NULL) { printf("Not enough memory.\nAlib abandoned\n"); exit(1); } /* * Read in the file. */ if (read(objfd, lp->object_module, lp->dir_entry.module_size) != lp->dir_entry.module_size) { printf("Library file is corrupted.\nAlib abandoned\n"); exit(1); } /* * Add module to linked list. */ lp->next = objlist; objlist = lp; /* * Close object file and return. */ close(objfd); printf("%s added\n", name); } /* * The following routine writes the library from memory and exits. */ close_library() { LL *lp; long file_position; long length; /* * Open the library */ libfd = open(libname, O_CREAT | O_RAW | O_WRONLY); if (libfd == -1) { printf("Error openning %s for output\nAlib abandoned", libname); exit(1); } dirfd = open(dirname, O_CREAT | O_RAW | O_WRONLY); if (dirfd == -1) { printf("Error openning %s for output\nAlib abandoned", dirname); exit(1); } /* * Write out the individual modules and directory records. */ file_position = 0; for (lp = objlist; lp != NULL; lp = lp->next) { length = write(libfd, lp->object_module, lp->dir_entry.module_size); if (length != lp->dir_entry.module_size) { printf("Error writing to library file\nAlib abandoned\n"); exit(1); } lp->dir_entry.module_offset = file_position; file_position += length; if (write(dirfd, (char *)&lp->dir_entry, sizeof(LD)) != sizeof(LD)) { printf("Error writing to directory file\nAlib abandoned\n"); exit(1); } } /* * Close the library files */ close(libfd); close(dirfd); printf("library is %ld bytes\nAlib complete\n", file_position); exit(0); } /* * Main program. */ main(argc, argv) int argc; char *argv[]; { int count; printf("ALIB Rev. 1.0 \n"); printf("Amiga Object Module Librarian\n"); printf("Programmed by Mike Schwartz\n"); printf("(C)1985 MS Software, all rights reserved\n"); /* * check for command line parameters present. */ if (argc < 3) help(); /* * setup the option and filenames */ option = argv[1][0]; strcpy(libname, argv[2]); strcpy(dirname, argv[2]); strcat(libname, ".lib"); strcat(dirname, ".dir"); if (option == 'l' || option == 'L') { directory(); exit(0); } if (option != 'd' && option != 'D' && option != 'r' && option != 'R') help(); /* * Open the library file */ open_library(); for (count = 3; count < argc; count++) { switch(option) { case 'd': case 'D': printf("deleting %s from library\n", argv[count]); if (!kill_module(argv[count])) printf("%s not defined in library\n", argv[count]); else printf("deleted.\n"); break; case 'r': case 'R': kill_module(argv[count]); add_module(argv[count]); break; } } close_library(); } directory() { LD d_entry; int count; int bytes; dirfd = open(dirname, O_RDONLY | O_RAW); if (dirfd == -1) { printf("%s not found\n", dirname); exit(1); } printf("Directory of library %s\n", libname); printf("Module Name Size Offset\n"); count = bytes = 0; while (read(dirfd, (char *)&d_entry, sizeof(LD)) == sizeof(LD)) { printf("%-30.30s %-6d %-6d\n", d_entry.object_filename, d_entry.module_size, d_entry.module_offset); count++; bytes += d_entry.module_size; } printf("Library consists of %d entries totalling %d bytes\n", count, bytes); close(dirfd); }