X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-ar%2Fllvm-ar.cpp;h=fd6841c9f16de57b8555329bcde3437fe4283fcb;hb=55ec2218c448ef9e0d09b5534885b6d2a9786a73;hp=4b79cd367d8fa027b3aaf8720671f53e7fa9c7ca;hpb=9de7b334ec6f80a15f093f11b339f5741c964b34;p=oota-llvm.git diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 4b79cd367d8..fd6841c9f16 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -1,560 +1,664 @@ //===-- llvm-ar.cpp - LLVM archive librarian utility ----------------------===// -// +// // The LLVM Compiler Infrastructure // -// This file was developed by the LLVM research group and is distributed under -// the University of Illinois Open Source License. See LICENSE.TXT for details. -// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// //===----------------------------------------------------------------------===// // -// Builds up standard unix archive files (.a) containing LLVM bytecode. +// Builds up (relatively) standard unix archive files (.a) containing LLVM +// bitcode or other files. // //===----------------------------------------------------------------------===// -#include "llvm/Module.h" -#include "llvm/Bytecode/Reader.h" -#include "Support/CommandLine.h" -#include "Support/FileUtilities.h" -#include "llvm/System/Signals.h" -#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 -#include -using namespace llvm; +#include -using std::string; +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include +#else +#include +#endif +using namespace llvm; -#define ARFMAG "\n" /* header trailer string */ -#define ARMAG "!\n" /* magic string */ -#define SARMAG 8 /* length of magic string */ -#define VERSION "llvm-ar is a part of the LLVM compiler infrastructure.\nPlease see http://llvm.cs.uiuc.edu for more information.\n"; +// 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); +} -// 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); - } -}; +// 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()); +} -//Option for X32_64, not used but must allow it to be present. -cl::opt X32Option ("X32_64", cl::desc("Ignored option spelt -X32_64, for compatibility with AIX"), cl::Optional); +// 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()); +} -//llvm-ar options -cl::opt Options(cl::Positional, cl::desc("{dmpqrstx}[abcfilNoPsSuvV] "), cl::Required); +// 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); +} -//llvm-ar options -cl::list RestofArgs(cl::Positional, cl::desc("[relpos] [count]] [members..]"), cl::Optional); +// parseCommandLine - Parse the command line options as presented and return the +// operation specified. Process all modifiers and check to make sure that +// constraints on modifier/operation pairs have not been violated. +ArchiveOperation parseCommandLine() { -//booleans to represent Operation, only one can be preformed at a time -bool Print, Delete, Move, QuickAppend, InsertWithReplacement, DisplayTable; -bool Extract; + // Keep track of number of operations. We can only specify one + // per execution. + unsigned NumOperations = 0; -//Modifiers to follow operation to vary behavior -bool AddAfter, AddBefore, Create, TruncateNames, InsertBefore, UseCount; -bool OriginalDates, FullPath, SymTable, OnlyUpdate, Verbose; + // Keep track of the number of positional modifiers (a,b,i). Only + // one can be specified. + unsigned NumPositional = 0; -//Realtive Pos Arg -string RelPos; + // Keep track of which operation was requested + ArchiveOperation Operation; -//Count, use for multiple entries in the archive with the same name -int Count; + for(unsigned i=0; i Members; + // Everything on the command line at this point is a member. + getMembers(); + // Perform various checks on the operation/modifier specification + // to make sure we are dealing with a legal request. + if (NumOperations == 0) + show_help("You must specify at least one of the operations"); + if (NumOperations > 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"); -// 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 cumulative 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 - std::vector offsets; //Vector of offsets into archive file - std::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; ibegin(), 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; i> 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 table to archive. - for(unsigned i=0; ibegin(), 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); } - - std::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); } - - - //Write out 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"; + } + } } - - //write to archive file - ArchiveFile.write((char*)buf,Length); - - // Unmmap the memberfile - munmap((char*)buf, Length); - - std::cout << "Member File End: " << ArchiveFile.tellp() << "\n"; - - return true; + return false; } +// 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; +} -// CreateArchive - Generates archive with or without symbol table. -// -void CreateArchive() { - - std::cerr << "Archive File: " << Archive << "\n"; - - //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); +// doDelete - Implement the delete operation. This function deletes zero or more +// members from the archive. Note that if the count is specified, there should +// be no more than one path in the Paths list or else this algorithm breaks. +// That check is enforced in parseCommandLine (above). +bool +doDelete(std::string* ErrMsg) { + if (buildPaths(false, ErrMsg)) + return true; + if (Paths.empty()) + return false; + for (Archive::iterator I = TheArchive->begin(), 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; + } } - //Write magic string to archive. - ArchiveFile << ARMAG; + // We're done editting, reconstruct the archive. + if (TheArchive->writeToDisk(ErrMsg)) + return true; + return false; +} - //If the '-s' option was specified, generate symbol table. - if(SymTable) { - std::cout << "Symbol Table Start: " << ArchiveFile.tellp() << "\n"; - if(!WriteSymbolTable(ArchiveFile)) { - std::cerr << "Error creating symbol table. Exiting program."; - exit(1); +// 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; + } } - std::cout << "Symbol Table End: " << ArchiveFile.tellp() << "\n"; } - //Loop over all member files, and add to the archive. - for(unsigned i=0; i < Members.size(); ++i) { - if(ArchiveFile.tellp() % 2 != 0) - ArchiveFile << ARFMAG; - if(AddMemberToArchive(Members[i],ArchiveFile) != true) { - std::cerr << "Error adding " << Members[i] << "to archive. Exiting program.\n"; - exit(1); + + // Keep a list of the paths remaining to be moved + std::set 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); } } - - //Close archive file. - ArchiveFile.close(); -} -//Print out usage for errors in command line -void printUse() { - std::cout << "USAGE: ar [-X32_64] [-]{dmpqrstx}[abcfilNoPsSuvV] [member-name] [count] archive-file [files..]\n\n"; - - std::cout << "commands:\n" << - "d - delete file(s) from the archive\n" - << "m[ab] - move file(s) in the archive\n" - << "p - print file(s) found in the archive\n" - << "q[f] - quick append file(s) to the archive\n" - << "r[ab][f][u] - replace existing or insert new file(s) into the archive\n" - << "t - display contents of archive\n" - << "x[o] - extract file(s) from the archive\n"; - - std::cout << "\ncommand specific modifiers:\n" - << "[a] - put file(s) after [member-name]\n" - << "[b] - put file(s) before [member-name] (same as [i])\n" - << "[N] - use instance [count] of name\n" - << "[f] - truncate inserted file names\n" - << "[P] - use full path names when matching\n" - << "[o] - preserve original dates\n" - << "[u] - only replace files that are newer than current archive contents\n"; - - std::cout << "generic modifiers:\n" - << "[c] - do not warn if the library had to be created\n" - << "[s] - create an archive index (cf. ranlib)\n" - << "[S] - do not build a symbol table\n" - << "[v] - be verbose\n" - << "[V] - display the version number\n"; - exit(1); + // We're done editting, reconstruct the archive. + if (TheArchive->writeToDisk(ErrMsg)) + return true; + return false; } +// 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; -//Print version -void printVersion() { - std::cout << VERSION; - exit(0); -} - -//Extract the memberfile name from the command line -void getRelPos() { - if(RestofArgs.size() > 0) { - RelPos = RestofArgs[0]; - RestofArgs.erase(RestofArgs.begin()); + // 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; } - //Throw error if needed and not present - else - printUse(); -} -//Extract count from the command line -void getCount() { - if(RestofArgs.size() > 0) { - Count = atoi(RestofArgs[0].c_str()); - RestofArgs.erase(RestofArgs.begin()); - } - //Throw error if needed and not present - else - printUse(); + // We're done editting, reconstruct the archive. + if (TheArchive->writeToDisk(ErrMsg)) + return true; + return false; } -//Get the Archive File Name from the command line -void getArchive() { - std::cerr << RestofArgs.size() << "\n"; - if(RestofArgs.size() > 0) { - Archive = RestofArgs[0]; - RestofArgs.erase(RestofArgs.begin()); - } - //Throw error if needed and not present - else - printUse(); -} +// 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; -//Copy over remaining items in RestofArgs to our Member File vector. -//This is just for clarity. -void getMembers() { - std::cerr << RestofArgs.size() << "\n"; - if(RestofArgs.size() > 0) - Members = std::vector(RestofArgs); -} + // Keep track of the paths that remain to be inserted. + std::set remaining(Paths); -// Parse the operations and operation modifiers -// FIXME: Not all of these options has been implemented, but we still -// do all the command line parsing for them. -void parseCL() { + // Default the insertion spot to the end of the archive + Archive::iterator insert_spot = TheArchive->end(); - //Keep track of number of operations. We can only specify one - //per execution - unsigned NumOperations = 0; + // Iterate over the archive contents + for (Archive::iterator I = TheArchive->begin(), E = TheArchive->end(); + I != E && !remaining.empty(); ++I ) { - for(unsigned i=0; i::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 (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); + } + + // Determine if this is the place where we should insert + if (AddBefore && RelPos == I->getPath().str()) + insert_spot = I; + else if (AddAfter && RelPos == I->getPath().str()) { + insert_spot = I; + insert_spot++; } } - //Check that only one operation has been specified - if(NumOperations > 1) - printUse(); + // 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; + } + } - getArchive(); - getMembers(); + // 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) { - cl::ParseCommandLineOptions(argc, 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; + } + } - parseCL(); + // 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! - if(Create) - CreateArchive(); + delete TheArchive; + TheArchive = 0; - return 0; + // Return result code back to operating system. + return exitCode; } -