X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-ar%2Fllvm-ar.cpp;h=fd6841c9f16de57b8555329bcde3437fe4283fcb;hb=55ec2218c448ef9e0d09b5534885b6d2a9786a73;hp=7634a1a9e0ab3e12e32e03a695d7dc054c90e93c;hpb=8d2ff1314901dd61f719b7689e4e2355d13c60f5;p=oota-llvm.git diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 7634a1a9e0a..fd6841c9f16 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -1,370 +1,664 @@ +//===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// //===----------------------------------------------------------------------===// -// LLVM 'ar' UTILITY // -// This utility may be invoked in the following manner: -// llvm-ar archivename files.. +// Builds up (relatively) standard unix archive files (.a) containing LLVM +// bitcode or other files. // //===----------------------------------------------------------------------===// -#include "Support/CommandLine.h" -#include "llvm/Bytecode/Reader.h" -#include "llvm/Module.h" - -#include -#include -#include -#include -#include -#include -#include + +#include "Archive.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" +#include +#include #include +#include + +#if !defined(_MSC_VER) && !defined(__MINGW32__) #include -#include - - -using std::string; -using std::vector; -using std::cout; - - -#define ARFMAG "\n" /* header trailer string */ -#define ARMAG "!\n" /* magic string */ -#define SARMAG 8 /* length of magic string */ - -namespace { - - // Each file member is preceded by a file member header. Which is - // of the following format: - // - // char ar_name[16] - '/' terminated file member name. - // If the file name does not fit, a dummy name is used. - // char ar_date[12] - file date in decimal - // char ar_uid[6] - User id of file owner in decimal. - // char ar_gid[6] - Group ID file belongs to in decimal. - // char ar_mode[8] - File mode in octal. - // char ar_size[10] - Size of file in decimal. - // char ar_fmag[2] - Trailer of header file, a newline. - struct ar_hdr { - char name[16]; - char date[12]; - char uid[6]; - char gid[6]; - char mode[8]; - char size[10]; - char fmag[2]; - void init() { - memset(name,' ',16); - memset(date,' ',12); - memset(uid,' ',6); - memset(gid,' ',6); - memset(mode,' ',8); - memset(size,' ',10); - memset(fmag,' ',2); - } - }; +#else +#include +#endif + +using namespace llvm; + +// Option for compatibility with AIX, not used but must allow it to be present. +static cl::opt +X32Option ("X32_64", cl::Hidden, + cl::desc("Ignored option for compatibility with AIX")); + +// llvm-ar operation code and modifier flags. This must come first. +static cl::opt +Options(cl::Positional, cl::Required, cl::desc("{operation}[modifiers]...")); + +// llvm-ar remaining positional arguments. +static cl::list +RestOfArgs(cl::Positional, cl::OneOrMore, + cl::desc("[relpos] [count] [members]...")); + +// MoreHelp - Provide additional help output explaining the operations and +// modifiers of llvm-ar. This object instructs the CommandLine library +// to print the text of the constructor when the --help option is given. +static cl::extrahelp MoreHelp( + "\nOPERATIONS:\n" + " d[NsS] - delete file(s) from the archive\n" + " m[abiSs] - move file(s) in the archive\n" + " p[kN] - print file(s) found in the archive\n" + " q[ufsS] - quick append file(s) to the archive\n" + " r[abfiuRsS] - replace or insert file(s) into the archive\n" + " t - display contents of archive\n" + " x[No] - extract file(s) from the archive\n" + "\nMODIFIERS (operation specific):\n" + " [a] - put file(s) after [relpos]\n" + " [b] - put file(s) before [relpos] (same as [i])\n" + " [i] - put file(s) before [relpos] (same as [b])\n" + " [N] - use instance [count] of name\n" + " [o] - preserve original dates\n" + " [s] - create an archive index (cf. ranlib)\n" + " [S] - do not build a symbol table\n" + " [u] - update only files newer than archive contents\n" + "\nMODIFIERS (generic):\n" + " [c] - do not warn if the library had to be created\n" + " [v] - be verbose about actions taken\n" +); + +// This enumeration delineates the kinds of operations on an archive +// that are permitted. +enum ArchiveOperation { + Print, ///< Print the contents of the archive + Delete, ///< Delete the specified members + Move, ///< Move members to end or as given by {a,b,i} modifiers + QuickAppend, ///< Quickly append to end of archive + ReplaceOrInsert, ///< Replace or Insert members + DisplayTable, ///< Display the table of contents + Extract ///< Extract files back to file system +}; + +// Modifiers to follow operation to vary behavior +bool AddAfter = false; ///< 'a' modifier +bool AddBefore = false; ///< 'b' modifier +bool Create = false; ///< 'c' modifier +bool OriginalDates = false; ///< 'o' modifier +bool SymTable = true; ///< 's' & 'S' modifiers +bool OnlyUpdate = false; ///< 'u' modifier +bool Verbose = false; ///< 'v' modifier + +// Relative Positional Argument (for insert/move). This variable holds +// the name of the archive member to which the 'a', 'b' or 'i' modifier +// refers. Only one of 'a', 'b' or 'i' can be specified so we only need +// one variable. +std::string RelPos; + +// This variable holds the name of the archive file as given on the +// command line. +std::string ArchiveName; + +// This variable holds the list of member files to proecess, as given +// on the command line. +std::vector Members; + +// This variable holds the (possibly expanded) list of path objects that +// correspond to files we will +std::set Paths; + +// The Archive object to which all the editing operations will be sent. +Archive* TheArchive = 0; + +// The name this program was invoked as. +static const char *program_name; + +// show_help - Show the error message, the help message and exit. +LLVM_ATTRIBUTE_NORETURN static void +show_help(const std::string &msg) { + errs() << program_name << ": " << msg << "\n\n"; + cl::PrintHelpMessage(); + if (TheArchive) + delete TheArchive; + std::exit(1); } -//Option to generate symbol table or not -//running llvm-ar -s is the same as ranlib -cl::opt SymbolTable ("s", cl::desc("Generate an archive symbol table")); - -//Archive name -cl::opt Archive (cl::Positional, cl::desc(""), - cl::Required); - -//For now we require one or more member files, this should change so -//we can just run llvm-ar -s on an archive to generate the symbol -//table -cl::list Members(cl::ConsumeAfter, cl::desc("...")); +// fail - Show the error message and exit. +LLVM_ATTRIBUTE_NORETURN static void +fail(const std::string &msg) { + errs() << program_name << ": " << msg << "\n\n"; + if (TheArchive) + delete TheArchive; + std::exit(1); +} +// getRelPos - Extract the member filename from the command line for +// the [relpos] argument associated with a, b, and i modifiers +void getRelPos() { + if(RestOfArgs.size() == 0) + show_help("Expected [relpos] for a, b, or i modifier"); + RelPos = RestOfArgs[0]; + RestOfArgs.erase(RestOfArgs.begin()); +} -static inline bool Error(std::string *ErrorStr, const char *Message) { - if (ErrorStr) *ErrorStr = Message; - return true; +// getArchive - Get the archive file name from the command line +void getArchive() { + if(RestOfArgs.size() == 0) + show_help("An archive name must be specified"); + ArchiveName = RestOfArgs[0]; + RestOfArgs.erase(RestOfArgs.begin()); } +// getMembers - Copy over remaining items in RestOfArgs to our Members vector +// This is just for clarity. +void getMembers() { + if(RestOfArgs.size() > 0) + Members = std::vector(RestOfArgs); +} -// WriteSymbolTable - Writes symbol table to ArchiveFile, return false -// on errors. Also returns by reference size of symbol table. -// -// Overview of method: -// 1) Generate the header for the symbol table. This is a normal -// archive member header, but it has a zero length name. -// 2) For each archive member file, stat the file and parse the bytecode -// Store cummulative offset (file size + header size). -// 3) Loop over all the symbols for the current member file, -// add offset entry to offset vector, and add symbol name to its vector. -// Note: The symbol name vector is a vector of chars to speed up calculating -// the total size of the symbol table. -// 4) Update offset vector once we know the total size of symbol table. This is -// because the symbol table appears before all archive member file contents. -// We add the size of magic string, and size of symbol table to each offset. -// 5) If the new updated offset it not even, we add 1 byte to offset because -// a newline will be inserted when writing member files. This adjustment is -// cummulative (ie. each time we have an odd offset we add 1 to total adjustment). -// 6) Lastly, write symbol table to file. -// -bool WriteSymbolTable(std::ofstream &ArchiveFile) { - - //Create header for symbol table. This is essentially an empty header with the - //name set to a '/' to indicate its a symbol table. - ar_hdr Hdr; - Hdr.init(); - - //Name of symbol table is '/' - Hdr.name[0] = '/'; - Hdr.name[1] = '\0'; - - //Set the header trailer to a newline - memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG)); - - - //Write header to archive file - ArchiveFile.write((char*)&Hdr, sizeof(Hdr)); - - - unsigned memoff = 0; //Keep Track of total size of files added to archive - vector offsets; //Vector of offsets into archive file - vector names; //Vector of characters that are the symbol names. - - //Loop over archive member files, parse bytecode, and generate symbol table. - for(unsigned i=0; i 1) + show_help("Only one operation may be specified"); + if (NumPositional > 1) + show_help("You may only specify one of a, b, and i modifiers"); + if (AddAfter || AddBefore) { + if (Operation != Move && Operation != ReplaceOrInsert) + show_help("The 'a', 'b' and 'i' modifiers can only be specified with " + "the 'm' or 'r' operations"); + } + if (OriginalDates && Operation != Extract) + show_help("The 'o' modifier is only applicable to the 'x' operation"); + if (OnlyUpdate && Operation != ReplaceOrInsert) + show_help("The 'u' modifier is only applicable to the 'r' operation"); - //Stat the file to get its size. - struct stat StatBuf; - if (stat(Members[i].c_str(), &StatBuf) == -1 || StatBuf.st_size == 0) { - std::cerr << "Error stating file\n"; - return false; + // Return the parsed operation to the caller + return Operation; +} + +// buildPaths - Convert the strings in the Members vector to sys::Path objects +// and make sure they are valid and exist exist. This check is only needed for +// the operations that add/replace files to the archive ('q' and 'r') +bool buildPaths(bool checkExistence, std::string* ErrMsg) { + for (unsigned i = 0; i < Members.size(); i++) { + std::string aPath = Members[i]; + if (checkExistence) { + bool IsDirectory; + error_code EC = sys::fs::is_directory(aPath, IsDirectory); + if (EC) + fail(aPath + ": " + EC.message()); + if (IsDirectory) + fail(aPath + " Is a directory"); + + Paths.insert(aPath); + } else { + Paths.insert(aPath); } + } + return false; +} - //Size of file - unsigned Length = StatBuf.st_size; - - //Read in file into a buffer. - unsigned char *buf = (unsigned char*)mmap(0, Length,PROT_READ, - MAP_PRIVATE, FD, 0); - - //Check if mmap failed. - if (buf == (unsigned char*)MAP_FAILED) { - std::cerr << "Error mmapping file!\n"; - return false; +// doPrint - Implements the 'p' operation. This function traverses the archive +// looking for members that match the path list. It is careful to uncompress +// things that should be and to skip bitcode files unless the 'k' modifier was +// given. +bool doPrint(std::string* ErrMsg) { + if (buildPaths(false, ErrMsg)) + return true; + for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); + I != E; ++I ) { + if (Paths.empty() || + (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { + const char *data = reinterpret_cast(I->getData()); + + // Skip things that don't make sense to print + if (I->isSVR4SymbolTable() || I->isBSD4SymbolTable()) + continue; + + if (Verbose) + outs() << "Printing " << I->getPath().str() << "\n"; + + unsigned len = I->getSize(); + outs().write(data, len); } - - //Parse the bytecode file and get all the symbols. - string ErrorStr; - Module *M = ParseBytecodeBuffer(buf,Length,Members[i],&ErrorStr); - - //Check for errors parsing bytecode. - //if(ErrorStr) { - //std::cerr << "Error Parsing Bytecode\n"; - //return false; - //} - - //Loop over function names and global vars and add to symbol maps - for(Module::iterator I = M->begin(), E=M->end(); I != E; ++I) { - - //get function name - string NM = ((Function*)I)->getName(); - - //Loop over the characters in the name and add to symbol name vector - for(unsigned i=0; ibegin(), E = TheArchive->end(); + I != E; ++I ) { + if (Paths.empty() || + (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { + if (Verbose) { + unsigned mode = I->getMode(); + printMode((mode >> 6) & 007); + printMode((mode >> 3) & 007); + printMode(mode & 007); + outs() << ' ' << I->getUser(); + outs() << "/" << I->getGroup(); + outs() << ' ' << format("%6llu", I->getSize()); + sys::TimeValue ModTime = I->getModTime(); + outs() << " " << ModTime.str(); + outs() << " " << I->getPath().str() << "\n"; + } else { + outs() << I->getPath().str() << "\n"; + } } + } + return false; +} - memoff += Length + sizeof(Hdr); +// doExtract - Implement the 'x' operation. This function extracts files back to +// the file system. +bool +doExtract(std::string* ErrMsg) { + if (buildPaths(false, ErrMsg)) + return true; + for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); + I != E; ++I ) { + if (Paths.empty() || + (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end())) { + + // Open up a file stream for writing + int OpenFlags = O_TRUNC | O_WRONLY | O_CREAT; +#ifdef O_BINARY + OpenFlags |= O_BINARY; +#endif + + // Retain the original mode. + sys::fs::perms Mode = sys::fs::perms(I->getMode()); + + int FD = open(I->getPath().str().c_str(), OpenFlags, Mode); + if (FD < 0) + return true; + + { + raw_fd_ostream file(FD, false); + + // Get the data and its length + const char* data = reinterpret_cast(I->getData()); + unsigned len = I->getSize(); + + // Write the data. + file.write(data, len); + } + + // If we're supposed to retain the original modification times, etc. do so + // now. + if (OriginalDates) { + error_code EC = + sys::fs::setLastModificationAndAccessTime(FD, I->getModTime()); + if (EC) + fail(EC.message()); + } + if (close(FD)) + return true; + } } + return false; +} - //Determine how large our symbol table is. - unsigned symbolTableSize = sizeof(Hdr) + 4 + 4*(offsets.size()) + names.size(); - cout << "Symbol Table Size: " << symbolTableSize << "\n"; - - //Number of symbols should be in network byte order as well - char num[4]; - unsigned temp = offsets.size(); - num[0] = (temp >> 24) & 255; - num[1] = (temp >> 16) & 255; - num[2] = (temp >> 8) & 255; - num[3] = temp & 255; - - //Write number of symbols to archive file - ArchiveFile.write(num,4); - - //Adjustment to offset to start files on even byte boundaries - unsigned adjust = 0; - - //Update offsets write symbol tabel to archive. - for(unsigned i=0; ibegin(), E = TheArchive->end(); + I != E; ) { + if (std::find(Paths.begin(), Paths.end(), I->getPath()) != Paths.end()) { + Archive::iterator J = I; + ++I; + TheArchive->erase(J); + } else { + ++I; } - - cout << "Offset: " << offsets[i] << "\n"; - output[0] = (offsets[i] >> 24) & 255; - output[1] = (offsets[i] >> 16) & 255; - output[2] = (offsets[i] >> 8) & 255; - output[3] = offsets[i] & 255; - ArchiveFile.write(output,4); } + // We're done editting, reconstruct the archive. + if (TheArchive->writeToDisk(ErrMsg)) + return true; + return false; +} + +// doMore - Implement the move operation. This function re-arranges just the +// order of the archive members so that when the archive is written the move +// of the members is accomplished. Note the use of the RelPos variable to +// determine where the items should be moved to. +bool +doMove(std::string* ErrMsg) { + if (buildPaths(false, ErrMsg)) + return true; + + // By default and convention the place to move members to is the end of the + // archive. + Archive::iterator moveto_spot = TheArchive->end(); + + // However, if the relative positioning modifiers were used, we need to scan + // the archive to find the member in question. If we don't find it, its no + // crime, we just move to the end. + if (AddBefore || AddAfter) { + for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end(); + I != E; ++I ) { + if (RelPos == I->getPath().str()) { + if (AddAfter) { + moveto_spot = I; + moveto_spot++; + } else { + moveto_spot = I; + } + break; + } + } + } - //Write out symbol name vector. - for(unsigned i=0; i remaining(Paths); + + // Scan the archive again, this time looking for the members to move to the + // moveto_spot. + for (Archive::iterator I = TheArchive->begin(), E= TheArchive->end(); + I != E && !remaining.empty(); ++I ) { + std::set::iterator found = + std::find(remaining.begin(),remaining.end(), I->getPath()); + if (found != remaining.end()) { + if (I != moveto_spot) + TheArchive->splice(moveto_spot,*TheArchive,I); + remaining.erase(found); + } + } - return true; + // We're done editting, reconstruct the archive. + if (TheArchive->writeToDisk(ErrMsg)) + return true; + return false; } -// AddMemberToArchive - Writes member file to archive. Returns false on errors. -// -// Overview of method: -// 1) Open file, and stat it. -// 2) Fill out header using stat information. If name is longer then 15 -// characters, use "dummy" name. -// 3) Write header and file contents to disk. -// 4) Keep track of total offset into file, and insert a newline if it is odd. -// -bool AddMemberToArchive(string Member, std::ofstream &ArchiveFile) { - - ar_hdr Hdr; //Header for archive member file. - - //stat the file to get info - struct stat StatBuf; - if (stat(Member.c_str(), &StatBuf) == -1 || StatBuf.st_size == 0) - cout << "ERROR\n"; - - //fill in header - - //set name to white spaces - memset(Hdr.name,' ', sizeof(Hdr.name)); - - //check the size of the name, if less than 15, we can copy it directly - //otherwise we give it a dummy name for now - if(Member.length() < 16) - memcpy(Hdr.name,Member.c_str(),Member.length()); - else - memcpy(Hdr.name, "Dummy", 5); - - //terminate name with forward slash - Hdr.name[15] = '/'; - - //file member size in decimal - unsigned Length = StatBuf.st_size; - sprintf(Hdr.size,"%d", Length); - cout << "Size: " << Length << "\n"; - - //file member user id in decimal - sprintf(Hdr.uid, "%d", StatBuf.st_uid); - - //file member group id in decimal - sprintf(Hdr.gid, "%d", StatBuf.st_gid); - - //file member date in decimal - sprintf(Hdr.date,"%d", (int)StatBuf.st_mtime); - - //file member mode in OCTAL - sprintf(Hdr.mode,"%d", StatBuf.st_mode); - - //add our header trailer - memcpy(Hdr.fmag,ARFMAG,sizeof(ARFMAG)); - - //write header to archive file - ArchiveFile.write((char*)&Hdr, sizeof(Hdr)); - - //open Member file for reading and copy to buffer - int FD = open(Member.c_str(),O_RDONLY); - if (FD == -1) { - std::cerr << "Error opening file!\n"; +// doQuickAppend - Implements the 'q' operation. This function just +// indiscriminantly adds the members to the archive and rebuilds it. +bool +doQuickAppend(std::string* ErrMsg) { + // Get the list of paths to append. + if (buildPaths(true, ErrMsg)) + return true; + if (Paths.empty()) return false; + + // Append them quickly. + for (std::set::iterator PI = Paths.begin(), PE = Paths.end(); + PI != PE; ++PI) { + if (TheArchive->addFileBefore(*PI, TheArchive->end(), ErrMsg)) + return true; } - unsigned char *buf = (unsigned char*)mmap(0, Length,PROT_READ, - MAP_PRIVATE, FD, 0); - - //check if mmap failed - if (buf == (unsigned char*)MAP_FAILED) { - std::cerr << "Error mmapping file!\n"; + // We're done editting, reconstruct the archive. + if (TheArchive->writeToDisk(ErrMsg)) + return true; + return false; +} + +// doReplaceOrInsert - Implements the 'r' operation. This function will replace +// any existing files or insert new ones into the archive. +bool +doReplaceOrInsert(std::string* ErrMsg) { + + // Build the list of files to be added/replaced. + if (buildPaths(true, ErrMsg)) + return true; + if (Paths.empty()) return false; - } - //write to archive file - ArchiveFile.write((char*)buf,Length); - - // Unmmap the memberfile - munmap((char*)buf, Length); + // Keep track of the paths that remain to be inserted. + std::set remaining(Paths); - return true; -} + // Default the insertion spot to the end of the archive + Archive::iterator insert_spot = TheArchive->end(); + // Iterate over the archive contents + for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); + I != E && !remaining.empty(); ++I ) { -// CreateArchive - Generates archive with or without symbol table. -// -void CreateArchive() { - - //Create archive file for output. - std::ofstream ArchiveFile(Archive.c_str()); - - //Check for errors opening or creating archive file. - if(!ArchiveFile.is_open() || ArchiveFile.bad() ) { - std::cerr << "Error opening Archive File\n"; - exit(1); - } + // Determine if this archive member matches one of the paths we're trying + // to replace. - //Write magic string to archive. - ArchiveFile << ARMAG; + std::set::iterator found = remaining.end(); + for (std::set::iterator RI = remaining.begin(), + RE = remaining.end(); RI != RE; ++RI ) { + std::string compare(sys::path::filename(*RI)); + if (compare == I->getPath().str()) { + found = RI; + break; + } + } - //If the '-s' option was specified, generate symbol table. - if(SymbolTable) { - cout << "Symbol Table Start: " << ArchiveFile.tellp() << "\n"; - if(!WriteSymbolTable(ArchiveFile)) { - std::cerr << "Error creating symbol table. Exiting program."; - exit(1); + if (found != remaining.end()) { + sys::fs::file_status Status; + error_code EC = sys::fs::status(*found, Status); + if (EC) + return true; + if (!sys::fs::is_directory(Status)) { + if (OnlyUpdate) { + // Replace the item only if it is newer. + if (Status.getLastModificationTime() > I->getModTime()) + if (I->replaceWith(*found, ErrMsg)) + return true; + } else { + // Replace the item regardless of time stamp + if (I->replaceWith(*found, ErrMsg)) + return true; + } + } else { + // We purposefully ignore directories. + } + + // Remove it from our "to do" list + remaining.erase(found); } - cout << "Symbol Table End: " << ArchiveFile.tellp() << "\n"; - } - //Loop over all member files, and add to the archive. - for(unsigned i=0; igetPath().str()) + insert_spot = I; + else if (AddAfter && RelPos == I->getPath().str()) { + insert_spot = I; + insert_spot++; + } + } - if(AddMemberToArchive(Members[i],ArchiveFile) != true) { - std::cerr << "Error adding file to archive. Exiting program."; - exit(1); + // If we didn't replace all the members, some will remain and need to be + // inserted at the previously computed insert-spot. + if (!remaining.empty()) { + for (std::set::iterator PI = remaining.begin(), + PE = remaining.end(); PI != PE; ++PI) { + if (TheArchive->addFileBefore(*PI, insert_spot, ErrMsg)) + return true; } - cout << "Member File End: " << ArchiveFile.tellp() << "\n"; } - - //Close archive file. - ArchiveFile.close(); + + // We're done editting, reconstruct the archive. + if (TheArchive->writeToDisk(ErrMsg)) + return true; + return false; } +bool shouldCreateArchive(ArchiveOperation Op) { + switch (Op) { + case Print: + case Delete: + case Move: + case DisplayTable: + case Extract: + return false; + + case QuickAppend: + case ReplaceOrInsert: + return true; + } + + llvm_unreachable("Missing entry in covered switch."); +} +// main - main program for llvm-ar .. see comments in the code int main(int argc, char **argv) { + program_name = argv[0]; + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + LLVMContext &Context = getGlobalContext(); + llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. + + // Have the command line options parsed and handle things + // like --help and --version. + cl::ParseCommandLineOptions(argc, argv, + "LLVM Archiver (llvm-ar)\n\n" + " This program archives bitcode files into single libraries\n" + ); + + int exitCode = 0; + + // Do our own parsing of the command line because the CommandLine utility + // can't handle the grouped positional parameters without a dash. + ArchiveOperation Operation = parseCommandLine(); + + // Create or open the archive object. + if (shouldCreateArchive(Operation) && !llvm::sys::fs::exists(ArchiveName)) { + // Produce a warning if we should and we're creating the archive + if (!Create) + errs() << argv[0] << ": creating " << ArchiveName << "\n"; + TheArchive = Archive::CreateEmpty(ArchiveName, Context); + TheArchive->writeToDisk(); + } + + if (!TheArchive) { + std::string Error; + TheArchive = Archive::OpenAndLoad(ArchiveName, Context, &Error); + if (TheArchive == 0) { + errs() << argv[0] << ": error loading '" << ArchiveName << "': " + << Error << "!\n"; + return 1; + } + } - //Parse Command line options - cl::ParseCommandLineOptions(argc, argv, " llvm-ar\n"); + // Make sure we're not fooling ourselves. + assert(TheArchive && "Unable to instantiate the archive"); + + // Perform the operation + std::string ErrMsg; + bool haveError = false; + switch (Operation) { + case Print: haveError = doPrint(&ErrMsg); break; + case Delete: haveError = doDelete(&ErrMsg); break; + case Move: haveError = doMove(&ErrMsg); break; + case QuickAppend: haveError = doQuickAppend(&ErrMsg); break; + case ReplaceOrInsert: haveError = doReplaceOrInsert(&ErrMsg); break; + case DisplayTable: haveError = doDisplayTable(&ErrMsg); break; + case Extract: haveError = doExtract(&ErrMsg); break; + } + if (haveError) { + errs() << argv[0] << ": " << ErrMsg << "\n"; + return 1; + } - //Create archive! - CreateArchive(); + delete TheArchive; + TheArchive = 0; - return 0; + // Return result code back to operating system. + return exitCode; }