X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-ar%2Fllvm-ar.cpp;h=2f1eb3b486a18197c0dfed473aea8dd0446291d1;hb=2a0d0dedf0c419256c2827f4e8506237e087a09e;hp=196240a0c2d4a75579545f3cb76415078451ea66;hpb=0659928fec02d5a953e528739cc036f7a68deb63;p=oota-llvm.git diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 196240a0c2d..2f1eb3b486a 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" @@ -20,10 +21,12 @@ #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" +#include "llvm/Support/LineIterator.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/TargetSelect.h" #include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" #include @@ -44,7 +47,7 @@ static StringRef ToolName; static const char *TemporaryOutput; static int TmpArchiveFD = -1; -// fail - Show the error message and exit. +// Show the error message and exit. LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { outs() << ToolName << ": " << Error << ".\n"; if (TmpArchiveFD != -1) @@ -66,14 +69,16 @@ static void failIfError(std::error_code EC, Twine Context = "") { // llvm-ar/llvm-ranlib remaining positional arguments. static cl::list -RestOfArgs(cl::Positional, cl::OneOrMore, - cl::desc("[relpos] [count] [members]...")); + RestOfArgs(cl::Positional, cl::ZeroOrMore, + cl::desc("[relpos] [count] [members]...")); + +static cl::opt MRI("M", cl::desc("")); std::string Options; -// 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. +// 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" @@ -87,7 +92,6 @@ static cl::extrahelp MoreHelp( " [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" @@ -131,9 +135,9 @@ static std::string ArchiveName; // This variable holds the list of member files to proecess, as given // on the command line. -static std::vector Members; +static std::vector Members; -// show_help - Show the error message, the help message and exit. +// Show the error message, the help message and exit. LLVM_ATTRIBUTE_NORETURN static void show_help(const std::string &msg) { errs() << ToolName << ": " << msg << "\n\n"; @@ -141,8 +145,8 @@ show_help(const std::string &msg) { std::exit(1); } -// getRelPos - Extract the member filename from the command line for -// the [relpos] argument associated with a, b, and i modifiers +// Extract the member filename from the command line for the [relpos] argument +// associated with a, b, and i modifiers static void getRelPos() { if(RestOfArgs.size() == 0) show_help("Expected [relpos] for a, b, or i modifier"); @@ -157,7 +161,7 @@ static void getOptions() { RestOfArgs.erase(RestOfArgs.begin()); } -// getArchive - Get the archive file name from the command line +// Get the archive file name from the command line static void getArchive() { if(RestOfArgs.size() == 0) show_help("An archive name must be specified"); @@ -165,17 +169,24 @@ static void getArchive() { RestOfArgs.erase(RestOfArgs.begin()); } -// getMembers - Copy over remaining items in RestOfArgs to our Members vector -// This is just for clarity. +// Copy over remaining items in RestOfArgs to our Members vector static void getMembers() { - if(RestOfArgs.size() > 0) - Members = std::vector(RestOfArgs); + for (auto &Arg : RestOfArgs) + Members.push_back(Arg); } -// 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. +static void runMRIScript(); + +// 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. static ArchiveOperation parseCommandLine() { + if (MRI) { + if (!RestOfArgs.empty()) + fail("Cannot mix -M and other options"); + runMRIScript(); + } + getOptions(); // Keep track of number of operations. We can only specify one @@ -278,8 +289,8 @@ static void doPrint(StringRef Name, object::Archive::child_iterator I) { outs().write(Data.data(), Data.size()); } -// putMode - utility function for printing out the file mode when the 't' -// operation is in verbose mode. +// Utility function for printing out the file mode when the 't' operation is in +// verbose mode. static void printMode(unsigned mode) { if (mode & 004) outs() << "r"; @@ -400,21 +411,19 @@ class NewArchiveIterator { object::Archive::child_iterator OldI; - std::string NewFilename; - mutable int NewFD; - mutable sys::fs::file_status NewStatus; + StringRef NewFilename; public: NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); - NewArchiveIterator(std::string *I, StringRef Name); + NewArchiveIterator(StringRef I, StringRef Name); NewArchiveIterator(); bool isNewMember() const; StringRef getName() const; object::Archive::child_iterator getOld() const; - const char *getNew() const; - int getFD() const; + StringRef getNew() const; + int getFD(sys::fs::file_status &NewStatus) const; const sys::fs::file_status &getStatus() const; }; } @@ -425,8 +434,8 @@ NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, StringRef Name) : IsNewMember(false), Name(Name), OldI(I) {} -NewArchiveIterator::NewArchiveIterator(std::string *NewFilename, StringRef Name) - : IsNewMember(true), Name(Name), NewFilename(*NewFilename), NewFD(-1) {} +NewArchiveIterator::NewArchiveIterator(StringRef NewFilename, StringRef Name) + : IsNewMember(true), Name(Name), NewFilename(NewFilename) {} StringRef NewArchiveIterator::getName() const { return Name; } @@ -437,15 +446,14 @@ object::Archive::child_iterator NewArchiveIterator::getOld() const { return OldI; } -const char *NewArchiveIterator::getNew() const { +StringRef NewArchiveIterator::getNew() const { assert(IsNewMember); - return NewFilename.c_str(); + return NewFilename; } -int NewArchiveIterator::getFD() const { +int NewArchiveIterator::getFD(sys::fs::file_status &NewStatus) const { assert(IsNewMember); - if (NewFD != -1) - return NewFD; + int NewFD; failIfError(sys::fs::openFileForRead(NewFilename, NewFD), NewFilename); assert(NewFD != -1); @@ -460,12 +468,6 @@ int NewArchiveIterator::getFD() const { return NewFD; } -const sys::fs::file_status &NewArchiveIterator::getStatus() const { - assert(IsNewMember); - assert(NewFD != -1 && "Must call getFD first"); - return NewStatus; -} - template void addMember(std::vector &Members, T I, StringRef Name, int Pos = -1) { @@ -484,16 +486,17 @@ enum InsertAction { IA_MoveNewMember }; -static InsertAction -computeInsertAction(ArchiveOperation Operation, - object::Archive::child_iterator I, StringRef Name, - std::vector::iterator &Pos) { +static InsertAction computeInsertAction(ArchiveOperation Operation, + object::Archive::child_iterator I, + StringRef Name, + std::vector::iterator &Pos) { if (Operation == QuickAppend || Members.empty()) return IA_AddOldMember; - std::vector::iterator MI = std::find_if( - Members.begin(), Members.end(), - [Name](StringRef Path) { return Name == sys::path::filename(Path); }); + auto MI = + std::find_if(Members.begin(), Members.end(), [Name](StringRef Path) { + return Name == sys::path::filename(Path); + }); if (MI == Members.end()) return IA_AddOldMember; @@ -541,11 +544,9 @@ computeNewArchiveMembers(ArchiveOperation Operation, int InsertPos = -1; StringRef PosName = sys::path::filename(RelPos); if (OldArchive) { - for (object::Archive::child_iterator I = OldArchive->child_begin(), - E = OldArchive->child_end(); - I != E; ++I) { + for (auto &Child : OldArchive->children()) { int Pos = Ret.size(); - ErrorOr NameOrErr = I->getName(); + ErrorOr NameOrErr = Child.getName(); failIfError(NameOrErr.getError()); StringRef Name = NameOrErr.get(); if (Name == PosName) { @@ -556,22 +557,23 @@ computeNewArchiveMembers(ArchiveOperation Operation, InsertPos = Pos + 1; } - std::vector::iterator MemberI = Members.end(); - InsertAction Action = computeInsertAction(Operation, I, Name, MemberI); + std::vector::iterator MemberI = Members.end(); + InsertAction Action = + computeInsertAction(Operation, Child, Name, MemberI); switch (Action) { case IA_AddOldMember: - addMember(Ret, I, Name); + addMember(Ret, Child, Name); break; case IA_AddNewMeber: - addMember(Ret, &*MemberI, Name); + addMember(Ret, *MemberI, Name); break; case IA_Delete: break; case IA_MoveOldMember: - addMember(Moved, I, Name); + addMember(Moved, Child, Name); break; case IA_MoveNewMember: - addMember(Moved, &*MemberI, Name); + addMember(Moved, *MemberI, Name); break; } if (MemberI != Members.end()) @@ -593,11 +595,10 @@ computeNewArchiveMembers(ArchiveOperation Operation, Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator()); int Pos = InsertPos; - for (std::vector::iterator I = Members.begin(), - E = Members.end(); - I != E; ++I, ++Pos) { - StringRef Name = sys::path::filename(*I); - addMember(Ret, &*I, Name, Pos); + for (auto &Member : Members) { + StringRef Name = sys::path::filename(Member); + addMember(Ret, Member, Name, Pos); + ++Pos; } return Ret; @@ -683,63 +684,53 @@ static void writeStringTable(raw_fd_ostream &Out, Out.seek(Pos); } -static void writeSymbolTable( - raw_fd_ostream &Out, ArrayRef Members, - ArrayRef Buffers, - std::vector > &MemberOffsetRefs) { +// Returns the offset of the first reference to a member offset. +static unsigned writeSymbolTable(raw_fd_ostream &Out, + ArrayRef Members, + ArrayRef Buffers, + std::vector &MemberOffsetRefs) { unsigned StartOffset = 0; unsigned MemberNum = 0; std::string NameBuf; raw_string_ostream NameOS(NameBuf); unsigned NumSyms = 0; - std::vector DeleteIt; LLVMContext &Context = getGlobalContext(); for (ArrayRef::iterator I = Members.begin(), E = Members.end(); I != E; ++I, ++MemberNum) { - MemoryBuffer *MemberBuffer = Buffers[MemberNum]; - ErrorOr ObjOrErr = + MemoryBufferRef MemberBuffer = Buffers[MemberNum]; + ErrorOr> ObjOrErr = object::SymbolicFile::createSymbolicFile( - MemberBuffer, false, sys::fs::file_magic::unknown, &Context); + MemberBuffer, sys::fs::file_magic::unknown, &Context); if (!ObjOrErr) continue; // FIXME: check only for "not an object file" errors. - object::SymbolicFile *Obj = ObjOrErr.get(); + object::SymbolicFile &Obj = *ObjOrErr.get(); - DeleteIt.push_back(Obj); if (!StartOffset) { printMemberHeader(Out, "", sys::TimeValue::now(), 0, 0, 0, 0); StartOffset = Out.tell(); print32BE(Out, 0); } - for (object::basic_symbol_iterator I = Obj->symbol_begin(), - E = Obj->symbol_end(); - I != E; ++I) { - uint32_t Symflags = I->getFlags(); + for (const object::BasicSymbolRef &S : Obj.symbols()) { + uint32_t Symflags = S.getFlags(); if (Symflags & object::SymbolRef::SF_FormatSpecific) continue; if (!(Symflags & object::SymbolRef::SF_Global)) continue; if (Symflags & object::SymbolRef::SF_Undefined) continue; - failIfError(I->printName(NameOS)); + failIfError(S.printName(NameOS)); NameOS << '\0'; ++NumSyms; - MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); + MemberOffsetRefs.push_back(MemberNum); print32BE(Out, 0); } } Out << NameOS.str(); - for (std::vector::iterator I = DeleteIt.begin(), - E = DeleteIt.end(); - I != E; ++I) { - object::SymbolicFile *O = *I; - delete O; - } - if (StartOffset == 0) - return; + return 0; if (Out.tell() % 2) Out << '\0'; @@ -750,10 +741,12 @@ static void writeSymbolTable( Out.seek(StartOffset); print32BE(Out, NumSyms); Out.seek(Pos); + return StartOffset + 4; } -static void performWriteOperation(ArchiveOperation Operation, - object::Archive *OldArchive) { +static void +performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, + std::vector &NewMembers) { SmallString<128> TmpArchive; failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", TmpArchiveFD, TmpArchive)); @@ -763,65 +756,63 @@ static void performWriteOperation(ArchiveOperation Operation, raw_fd_ostream &Out = Output.os(); Out << "!\n"; - std::vector NewMembers = - computeNewArchiveMembers(Operation, OldArchive); - - std::vector > MemberOffsetRefs; + std::vector MemberOffsetRefs; - std::vector MemberBuffers; - MemberBuffers.resize(NewMembers.size()); + std::vector> Buffers; + std::vector Members; + std::vector NewMemberStatus; for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { - std::unique_ptr MemberBuffer; NewArchiveIterator &Member = NewMembers[I]; + MemoryBufferRef MemberRef; if (Member.isNewMember()) { - const char *Filename = Member.getNew(); - int FD = Member.getFD(); - const sys::fs::file_status &Status = Member.getStatus(); - failIfError(MemoryBuffer::getOpenFile(FD, Filename, MemberBuffer, - Status.getSize(), false), - Filename); - + StringRef Filename = Member.getNew(); + NewMemberStatus.resize(NewMemberStatus.size() + 1); + sys::fs::file_status &Status = NewMemberStatus.back(); + int FD = Member.getFD(Status); + ErrorOr> MemberBufferOrErr = + MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false); + failIfError(MemberBufferOrErr.getError(), Filename); + if (close(FD) != 0) + fail("Could not close file"); + Buffers.push_back(std::move(MemberBufferOrErr.get())); + MemberRef = Buffers.back()->getMemBufferRef(); } else { object::Archive::child_iterator OldMember = Member.getOld(); - ErrorOr> MemberBufferOrErr = - OldMember->getMemoryBuffer(); + ErrorOr MemberBufferOrErr = + OldMember->getMemoryBufferRef(); failIfError(MemberBufferOrErr.getError()); - MemberBuffer = std::move(MemberBufferOrErr.get()); + MemberRef = MemberBufferOrErr.get(); } - MemberBuffers[I] = MemberBuffer.release(); + Members.push_back(MemberRef); } + unsigned MemberReferenceOffset = 0; if (Symtab) { - writeSymbolTable(Out, NewMembers, MemberBuffers, MemberOffsetRefs); + MemberReferenceOffset = + writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs); } std::vector StringMapIndexes; writeStringTable(Out, NewMembers, StringMapIndexes); - std::vector >::iterator MemberRefsI = - MemberOffsetRefs.begin(); - unsigned MemberNum = 0; unsigned LongNameMemberNum = 0; + unsigned NewMemberNum = 0; + std::vector MemberOffset; for (std::vector::iterator I = NewMembers.begin(), E = NewMembers.end(); I != E; ++I, ++MemberNum) { unsigned Pos = Out.tell(); - while (MemberRefsI != MemberOffsetRefs.end() && - MemberRefsI->second == MemberNum) { - Out.seek(MemberRefsI->first); - print32BE(Out, Pos); - ++MemberRefsI; - } - Out.seek(Pos); + MemberOffset.push_back(Pos); - const MemoryBuffer *File = MemberBuffers[MemberNum]; + MemoryBufferRef File = Members[MemberNum]; if (I->isNewMember()) { - const char *FileName = I->getNew(); - const sys::fs::file_status &Status = I->getStatus(); + StringRef FileName = I->getNew(); + const sys::fs::file_status &Status = NewMemberStatus[NewMemberNum]; + NewMemberNum++; StringRef Name = sys::path::filename(FileName); if (Name.size() < 16) @@ -848,14 +839,16 @@ static void performWriteOperation(ArchiveOperation Operation, OldMember->getSize()); } - Out << File->getBuffer(); + Out << File.getBuffer(); if (Out.tell() % 2) Out << '\n'; } - for (unsigned I = 0, N = MemberBuffers.size(); I < N; ++I) { - delete MemberBuffers[I]; + if (MemberReferenceOffset) { + Out.seek(MemberReferenceOffset); + for (unsigned MemberNum : MemberOffsetRefs) + print32BE(Out, MemberOffset[MemberNum]); } Output.keep(); @@ -864,6 +857,18 @@ static void performWriteOperation(ArchiveOperation Operation, TemporaryOutput = nullptr; } +static void +performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, + std::vector *NewMembersP) { + if (NewMembersP) { + performWriteOperation(Operation, OldArchive, *NewMembersP); + return; + } + std::vector NewMembers = + computeNewArchiveMembers(Operation, OldArchive); + performWriteOperation(Operation, OldArchive, NewMembers); +} + static void createSymbolTable(object::Archive *OldArchive) { // When an archive is created or modified, if the s option is given, the // resulting archive will have a current symbol table. If the S option @@ -874,11 +879,12 @@ static void createSymbolTable(object::Archive *OldArchive) { if (OldArchive->hasSymbolTable()) return; - performWriteOperation(CreateSymTab, OldArchive); + performWriteOperation(CreateSymTab, OldArchive, nullptr); } static void performOperation(ArchiveOperation Operation, - object::Archive *OldArchive) { + object::Archive *OldArchive, + std::vector *NewMembers) { switch (Operation) { case Print: case DisplayTable: @@ -890,7 +896,7 @@ static void performOperation(ArchiveOperation Operation, case Move: case QuickAppend: case ReplaceOrInsert: - performWriteOperation(Operation, OldArchive); + performWriteOperation(Operation, OldArchive, NewMembers); return; case CreateSymTab: createSymbolTable(OldArchive); @@ -899,52 +905,12 @@ static void performOperation(ArchiveOperation Operation, llvm_unreachable("Unknown operation."); } -static int ar_main(char **argv); -static int ranlib_main(); - -// main - main program for llvm-ar .. see comments in the code -int main(int argc, char **argv) { - ToolName = argv[0]; - // Print a stack trace if we signal out. - sys::PrintStackTraceOnErrorSignal(); - PrettyStackTraceProgram X(argc, argv); - 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" - ); - - StringRef Stem = sys::path::stem(ToolName); - if (Stem.find("ar") != StringRef::npos) - return ar_main(argv); - if (Stem.find("ranlib") != StringRef::npos) - return ranlib_main(); - fail("Not ranlib or ar!"); -} - -static int performOperation(ArchiveOperation Operation); - -int ranlib_main() { - if (RestOfArgs.size() != 1) - fail(ToolName + "takes just one archive as argument"); - ArchiveName = RestOfArgs[0]; - return performOperation(CreateSymTab); -} - -int ar_main(char **argv) { - // 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(); - return performOperation(Operation); -} - -static int performOperation(ArchiveOperation Operation) { +static int performOperation(ArchiveOperation Operation, + std::vector *NewMembers) { // Create or open the archive object. - std::unique_ptr Buf; - std::error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); + ErrorOr> Buf = + MemoryBuffer::getFile(ArchiveName, -1, false); + std::error_code EC = Buf.getError(); if (EC && EC != errc::no_such_file_or_directory) { errs() << ToolName << ": error opening '" << ArchiveName << "': " << EC.message() << "!\n"; @@ -952,14 +918,14 @@ static int performOperation(ArchiveOperation Operation) { } if (!EC) { - object::Archive Archive(Buf.release(), EC); + object::Archive Archive(Buf.get()->getMemBufferRef(), EC); if (EC) { errs() << ToolName << ": error loading '" << ArchiveName << "': " << EC.message() << "!\n"; return 1; } - performOperation(Operation, &Archive); + performOperation(Operation, &Archive, NewMembers); return 0; } @@ -974,6 +940,116 @@ static int performOperation(ArchiveOperation Operation) { } } - performOperation(Operation, nullptr); + performOperation(Operation, nullptr, NewMembers); return 0; } + +static void runMRIScript() { + enum class MRICommand { AddLib, AddMod, Create, Save, End, Invalid }; + + ErrorOr> Buf = MemoryBuffer::getSTDIN(); + failIfError(Buf.getError()); + const MemoryBuffer &Ref = *Buf.get(); + bool Saved = false; + std::vector NewMembers; + std::vector> ArchiveBuffers; + std::vector> Archives; + + for (line_iterator I(Ref, /*SkipBlanks*/ true, ';'), E; I != E; ++I) { + StringRef Line = *I; + StringRef CommandStr, Rest; + std::tie(CommandStr, Rest) = Line.split(' '); + Rest = Rest.trim(); + if (!Rest.empty() && Rest.front() == '"' && Rest.back() == '"') + Rest = Rest.drop_front().drop_back(); + auto Command = StringSwitch(CommandStr.lower()) + .Case("addlib", MRICommand::AddLib) + .Case("addmod", MRICommand::AddMod) + .Case("create", MRICommand::Create) + .Case("save", MRICommand::Save) + .Case("end", MRICommand::End) + .Default(MRICommand::Invalid); + + switch (Command) { + case MRICommand::AddLib: { + auto BufOrErr = MemoryBuffer::getFile(Rest, -1, false); + failIfError(BufOrErr.getError(), "Could not open library"); + ArchiveBuffers.push_back(std::move(*BufOrErr)); + auto LibOrErr = + object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); + failIfError(LibOrErr.getError(), "Could not parse library"); + Archives.push_back(std::move(*LibOrErr)); + object::Archive &Lib = *Archives.back(); + for (auto &Member : Lib.children()) { + ErrorOr NameOrErr = Member.getName(); + failIfError(NameOrErr.getError()); + addMember(NewMembers, Member, *NameOrErr); + } + break; + } + case MRICommand::AddMod: + addMember(NewMembers, Rest, sys::path::filename(Rest)); + break; + case MRICommand::Create: + Create = true; + if (!ArchiveName.empty()) + fail("Editing multiple archives not supported"); + if (Saved) + fail("File already saved"); + ArchiveName = Rest; + break; + case MRICommand::Save: + Saved = true; + break; + case MRICommand::End: + break; + case MRICommand::Invalid: + fail("Unknown command: " + CommandStr); + } + } + + // Nothing to do if not saved. + if (Saved) + performOperation(ReplaceOrInsert, &NewMembers); + exit(0); +} + +static int ar_main() { + // 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(); + return performOperation(Operation, nullptr); +} + +static int ranlib_main() { + if (RestOfArgs.size() != 1) + fail(ToolName + "takes just one archive as argument"); + ArchiveName = RestOfArgs[0]; + return performOperation(CreateSymTab, nullptr); +} + +int main(int argc, char **argv) { + ToolName = argv[0]; + // Print a stack trace if we signal out. + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + 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" + ); + + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + + StringRef Stem = sys::path::stem(ToolName); + if (Stem.find("ar") != StringRef::npos) + return ar_main(); + if (Stem.find("ranlib") != StringRef::npos) + return ranlib_main(); + fail("Not ranlib or ar!"); +}