X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=tools%2Fllvm-ar%2Fllvm-ar.cpp;h=22fa291fbabafda4028d986de999ec9774928a60;hp=77914c5792b27e688efe238fdbd6fae2c475dd7b;hb=c6961f286bb2028474e4005c667e1090e55debba;hpb=7acd886ecfa0adc8a14476eafe8cf1fa981cfe18 diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 77914c5792b..22fa291fbab 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -12,17 +12,21 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringSwitch.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" +#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 @@ -43,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) @@ -53,7 +57,7 @@ LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { exit(1); } -static void failIfError(error_code EC, Twine Context = "") { +static void failIfError(std::error_code EC, Twine Context = "") { if (!EC) return; @@ -65,14 +69,16 @@ static void failIfError(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" @@ -130,9 +136,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"; @@ -140,8 +146,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"); @@ -156,7 +162,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"); @@ -164,17 +170,76 @@ 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); +} + +namespace { +enum class MRICommand { AddMod, Create, Save, End, Invalid }; } -// 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 std::vector MRIMembers; +static ArchiveOperation parseMRIScript() { + ErrorOr> Buf = MemoryBuffer::getSTDIN(); + failIfError(Buf.getError()); + const MemoryBuffer &Ref = *Buf.get(); + bool Saved = false; + + for (line_iterator I(Ref, /*SkipBlanks*/ true, ';'), E; I != E; ++I) { + StringRef Line = *I; + StringRef CommandStr, Rest; + std::tie(CommandStr, Rest) = Line.split(' '); + auto Command = StringSwitch(CommandStr.lower()) + .Case("addmod", MRICommand::AddMod) + .Case("create", MRICommand::Create) + .Case("save", MRICommand::Save) + .Case("end", MRICommand::End) + .Default(MRICommand::Invalid); + + switch (Command) { + case MRICommand::AddMod: + MRIMembers.push_back(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) + exit(0); + + for (auto &M : MRIMembers) + Members.push_back(M); + + return ReplaceOrInsert; +} + +// 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"); + return parseMRIScript(); + } + getOptions(); // Keep track of number of operations. We can only specify one @@ -277,8 +342,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"; @@ -368,8 +433,9 @@ static void performReadOperation(ArchiveOperation Operation, for (object::Archive::child_iterator I = OldArchive->child_begin(), E = OldArchive->child_end(); I != E; ++I) { - StringRef Name; - failIfError(I->getName(Name)); + ErrorOr NameOrErr = I->getName(); + failIfError(NameOrErr.getError()); + StringRef Name = NameOrErr.get(); if (!Members.empty() && std::find(Members.begin(), Members.end(), Name) == Members.end()) @@ -398,20 +464,20 @@ class NewArchiveIterator { object::Archive::child_iterator OldI; - std::string NewFilename; + StringRef NewFilename; mutable int NewFD; mutable sys::fs::file_status NewStatus; 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; + StringRef getNew() const; int getFD() const; const sys::fs::file_status &getStatus() const; }; @@ -423,8 +489,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), NewFD(-1) {} StringRef NewArchiveIterator::getName() const { return Name; } @@ -435,9 +501,9 @@ 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 { @@ -453,7 +519,7 @@ int NewArchiveIterator::getFD() const { // Linux cannot open directories with open(2), although // cygwin and *bsd can. if (NewStatus.type() == sys::fs::file_type::directory_file) - failIfError(make_error_code(std::errc::is_a_directory), NewFilename); + failIfError(make_error_code(errc::is_a_directory), NewFilename); return NewFD; } @@ -482,16 +548,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; @@ -543,8 +610,9 @@ computeNewArchiveMembers(ArchiveOperation Operation, E = OldArchive->child_end(); I != E; ++I) { int Pos = Ret.size(); - StringRef Name; - failIfError(I->getName(Name)); + ErrorOr NameOrErr = I->getName(); + failIfError(NameOrErr.getError()); + StringRef Name = NameOrErr.get(); if (Name == PosName) { assert(AddAfter || AddBefore); if (AddBefore) @@ -553,14 +621,14 @@ computeNewArchiveMembers(ArchiveOperation Operation, InsertPos = Pos + 1; } - std::vector::iterator MemberI = Members.end(); + std::vector::iterator MemberI = Members.end(); InsertAction Action = computeInsertAction(Operation, I, Name, MemberI); switch (Action) { case IA_AddOldMember: addMember(Ret, I, Name); break; case IA_AddNewMeber: - addMember(Ret, &*MemberI, Name); + addMember(Ret, *MemberI, Name); break; case IA_Delete: break; @@ -568,7 +636,7 @@ computeNewArchiveMembers(ArchiveOperation Operation, addMember(Moved, I, Name); break; case IA_MoveNewMember: - addMember(Moved, &*MemberI, Name); + addMember(Moved, *MemberI, Name); break; } if (MemberI != Members.end()) @@ -590,11 +658,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; @@ -680,46 +747,42 @@ static void writeStringTable(raw_fd_ostream &Out, Out.seek(Pos); } -static void writeSymbolTable( - raw_fd_ostream &Out, ArrayRef Members, - ArrayRef Buffers, - std::vector > &MemberOffsetRefs) { +static void +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)); @@ -728,13 +791,6 @@ static void writeSymbolTable( } 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; @@ -765,30 +821,34 @@ static void performWriteOperation(ArchiveOperation Operation, std::vector > MemberOffsetRefs; - std::vector MemberBuffers; - MemberBuffers.resize(NewMembers.size()); + std::vector> Buffers; + std::vector Members; 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(); + StringRef 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); - + ErrorOr> MemberBufferOrErr = + MemoryBuffer::getOpenFile(FD, Filename, Status.getSize(), false); + failIfError(MemberBufferOrErr.getError(), Filename); + Buffers.push_back(std::move(MemberBufferOrErr.get())); + MemberRef = Buffers.back()->getMemBufferRef(); } else { object::Archive::child_iterator OldMember = Member.getOld(); - failIfError(OldMember->getMemoryBuffer(MemberBuffer)); + ErrorOr MemberBufferOrErr = + OldMember->getMemoryBufferRef(); + failIfError(MemberBufferOrErr.getError()); + MemberRef = MemberBufferOrErr.get(); } - MemberBuffers[I] = MemberBuffer.release(); + Members.push_back(MemberRef); } if (Symtab) { - writeSymbolTable(Out, NewMembers, MemberBuffers, MemberOffsetRefs); + writeSymbolTable(Out, NewMembers, Members, MemberOffsetRefs); } std::vector StringMapIndexes; @@ -812,9 +872,9 @@ static void performWriteOperation(ArchiveOperation Operation, } Out.seek(Pos); - const MemoryBuffer *File = MemberBuffers[MemberNum]; + MemoryBufferRef File = Members[MemberNum]; if (I->isNewMember()) { - const char *FileName = I->getNew(); + StringRef FileName = I->getNew(); const sys::fs::file_status &Status = I->getStatus(); StringRef Name = sys::path::filename(FileName); @@ -842,16 +902,12 @@ 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]; - } - Output.keep(); Out.close(); sys::fs::rename(TemporaryOutput, ArchiveName); @@ -893,60 +949,19 @@ 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) { // Create or open the archive object. - std::unique_ptr Buf; - error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); - if (EC && EC != std::errc::no_such_file_or_directory) { + 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"; return 1; } if (!EC) { - object::Archive Archive(Buf.release(), EC); + object::Archive Archive(Buf.get()->getMemBufferRef(), EC); if (EC) { errs() << ToolName << ": error loading '" << ArchiveName @@ -957,7 +972,7 @@ static int performOperation(ArchiveOperation Operation) { return 0; } - assert(EC == std::errc::no_such_file_or_directory); + assert(EC == errc::no_such_file_or_directory); if (!shouldCreateArchive(Operation)) { failIfError(EC, Twine("error loading '") + ArchiveName + "'"); @@ -971,3 +986,43 @@ static int performOperation(ArchiveOperation Operation) { performOperation(Operation, nullptr); return 0; } + +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); +} + +int ranlib_main() { + if (RestOfArgs.size() != 1) + fail(ToolName + "takes just one archive as argument"); + ArchiveName = RestOfArgs[0]; + return performOperation(CreateSymTab); +} + +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(argv); + if (Stem.find("ranlib") != StringRef::npos) + return ranlib_main(); + fail("Not ranlib or ar!"); +}