X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;ds=sidebyside;f=tools%2Fllvm-ar%2Fllvm-ar.cpp;h=ef5fab68b9479fdff29375db7bf25130b4d786de;hb=10a5589d08c1de3fcd715ce23697d4e591519595;hp=920a4701b2731a8347f59e889df4282540dcf0f9;hpb=d8fc64e0d1f09abb3265a6ff264629ca33a52c6a;p=oota-llvm.git diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 920a4701b27..ef5fab68b94 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -12,18 +12,25 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Triple.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/LibDriver/LibDriver.h" #include "llvm/Object/Archive.h" +#include "llvm/Object/ArchiveWriter.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/Path.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 @@ -41,16 +48,9 @@ using namespace llvm; // The name this program was invoked as. 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) - close(TmpArchiveFD); - if (TemporaryOutput) - sys::fs::remove(TemporaryOutput); exit(1); } @@ -66,14 +66,26 @@ 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("")); + +namespace { +enum Format { Default, GNU, BSD }; +} + +static cl::opt + FormatOpt("format", cl::desc("Archive format to create"), + cl::values(clEnumValN(Default, "defalut", "default"), + clEnumValN(GNU, "gnu", "gnu"), + clEnumValN(BSD, "bsd", "bsd"), clEnumValEnd)); -std::string Options; +static 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 +99,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" @@ -118,6 +129,8 @@ static bool OriginalDates = false; ///< 'o' modifier static bool OnlyUpdate = false; ///< 'u' modifier static bool Verbose = false; ///< 'v' modifier static bool Symtab = true; ///< 's' modifier +static bool Deterministic = true; ///< 'D' and 'U' modifiers +static bool Thin = false; ///< 'T' modifier // Relative Positional Argument (for insert/move). This variable holds // the name of the archive member to which the 'a', 'b' or 'i' modifier @@ -131,9 +144,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 +154,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 +170,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 +178,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 @@ -227,6 +247,15 @@ static ArchiveOperation parseCommandLine() { AddBefore = true; NumPositional++; break; + case 'D': + Deterministic = true; + break; + case 'U': + Deterministic = false; + break; + case 'T': + Thin = true; + break; default: cl::PrintHelpMessage(); } @@ -270,45 +299,40 @@ static ArchiveOperation parseCommandLine() { // Implements the 'p' operation. This function traverses the archive // looking for members that match the path list. -static void doPrint(StringRef Name, object::Archive::child_iterator I) { +static void doPrint(StringRef Name, const object::Archive::Child &C) { if (Verbose) outs() << "Printing " << Name << "\n"; - StringRef Data = I->getBuffer(); + ErrorOr DataOrErr = C.getBuffer(); + failIfError(DataOrErr.getError()); + StringRef Data = *DataOrErr; 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"; - else - outs() << "-"; - if (mode & 002) - outs() << "w"; - else - outs() << "-"; - if (mode & 001) - outs() << "x"; - else - outs() << "-"; + outs() << ((mode & 004) ? "r" : "-"); + outs() << ((mode & 002) ? "w" : "-"); + outs() << ((mode & 001) ? "x" : "-"); } // Implement the 't' operation. This function prints out just // the file names of each of the members. However, if verbose mode is requested // ('v' modifier) then the file type, permission mode, user, group, size, and // modification time are also printed. -static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) { +static void doDisplayTable(StringRef Name, const object::Archive::Child &C) { if (Verbose) { - sys::fs::perms Mode = I->getAccessMode(); + sys::fs::perms Mode = C.getAccessMode(); printMode((Mode >> 6) & 007); printMode((Mode >> 3) & 007); printMode(Mode & 007); - outs() << ' ' << I->getUID(); - outs() << '/' << I->getGID(); - outs() << ' ' << format("%6llu", I->getSize()); - outs() << ' ' << I->getLastModified().str(); + outs() << ' ' << C.getUID(); + outs() << '/' << C.getGID(); + ErrorOr Size = C.getSize(); + failIfError(Size.getError()); + outs() << ' ' << format("%6llu", Size.get()); + outs() << ' ' << C.getLastModified().str(); outs() << ' '; } outs() << Name << "\n"; @@ -316,9 +340,9 @@ static void doDisplayTable(StringRef Name, object::Archive::child_iterator I) { // Implement the 'x' operation. This function extracts files back to the file // system. -static void doExtract(StringRef Name, object::Archive::child_iterator I) { +static void doExtract(StringRef Name, const object::Archive::Child &C) { // Retain the original mode. - sys::fs::perms Mode = I->getAccessMode(); + sys::fs::perms Mode = C.getAccessMode(); SmallString<128> Storage = Name; int FD; @@ -330,7 +354,7 @@ static void doExtract(StringRef Name, object::Archive::child_iterator I) { raw_fd_ostream file(FD, false); // Get the data and its length - StringRef Data = I->getBuffer(); + StringRef Data = *C.getBuffer(); // Write the data. file.write(Data.data(), Data.size()); @@ -340,7 +364,7 @@ static void doExtract(StringRef Name, object::Archive::child_iterator I) { // now. if (OriginalDates) failIfError( - sys::fs::setLastModificationAndAccessTime(FD, I->getLastModified())); + sys::fs::setLastModificationAndAccessTime(FD, C.getLastModified())); if (close(FD)) fail("Could not close the file"); @@ -366,110 +390,61 @@ static bool shouldCreateArchive(ArchiveOperation Op) { static void performReadOperation(ArchiveOperation Operation, object::Archive *OldArchive) { - for (object::Archive::child_iterator I = OldArchive->child_begin(), - E = OldArchive->child_end(); - I != E; ++I) { - ErrorOr NameOrErr = I->getName(); + if (Operation == Extract && OldArchive->isThin()) + fail("extracting from a thin archive is not supported"); + + bool Filter = !Members.empty(); + for (auto &ChildOrErr : OldArchive->children()) { + failIfError(ChildOrErr.getError()); + const object::Archive::Child &C = *ChildOrErr; + + ErrorOr NameOrErr = C.getName(); failIfError(NameOrErr.getError()); StringRef Name = NameOrErr.get(); - if (!Members.empty() && - std::find(Members.begin(), Members.end(), Name) == Members.end()) - continue; + if (Filter) { + auto I = std::find(Members.begin(), Members.end(), Name); + if (I == Members.end()) + continue; + Members.erase(I); + } switch (Operation) { default: llvm_unreachable("Not a read operation"); case Print: - doPrint(Name, I); + doPrint(Name, C); break; case DisplayTable: - doDisplayTable(Name, I); + doDisplayTable(Name, C); break; case Extract: - doExtract(Name, I); + doExtract(Name, C); break; } } + if (Members.empty()) + return; + for (StringRef Name : Members) + errs() << Name << " was not found\n"; + std::exit(1); } -namespace { -class NewArchiveIterator { - bool IsNewMember; - StringRef Name; - - object::Archive::child_iterator OldI; - - std::string 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(); - bool isNewMember() const; - StringRef getName() const; - - object::Archive::child_iterator getOld() const; - - const char *getNew() const; - int getFD() const; - const sys::fs::file_status &getStatus() const; -}; -} - -NewArchiveIterator::NewArchiveIterator() {} - -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) {} - -StringRef NewArchiveIterator::getName() const { return Name; } - -bool NewArchiveIterator::isNewMember() const { return IsNewMember; } - -object::Archive::child_iterator NewArchiveIterator::getOld() const { - assert(!IsNewMember); - return OldI; -} - -const char *NewArchiveIterator::getNew() const { - assert(IsNewMember); - return NewFilename.c_str(); -} - -int NewArchiveIterator::getFD() const { - assert(IsNewMember); - if (NewFD != -1) - return NewFD; - failIfError(sys::fs::openFileForRead(NewFilename, NewFD), NewFilename); - assert(NewFD != -1); - - failIfError(sys::fs::status(NewFD, NewStatus), NewFilename); - - // Opening a directory doesn't make sense. Let it fail. - // 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(errc::is_a_directory), NewFilename); - - return NewFD; -} - -const sys::fs::file_status &NewArchiveIterator::getStatus() const { - assert(IsNewMember); - assert(NewFD != -1 && "Must call getFD first"); - return NewStatus; +static void addMember(std::vector &Members, + StringRef FileName, int Pos = -1) { + NewArchiveIterator NI(FileName); + if (Pos == -1) + Members.push_back(NI); + else + Members[Pos] = NI; } -template -void addMember(std::vector &Members, T I, StringRef Name, - int Pos = -1) { - NewArchiveIterator NI(I, Name); +static void addMember(std::vector &Members, + const object::Archive::Child &M, StringRef Name, + int Pos = -1) { + if (Thin && !M.getParent()->isThin()) + fail("Cannot convert a regular archive to a thin one"); + NewArchiveIterator NI(M, Name); if (Pos == -1) Members.push_back(NI); else @@ -484,16 +459,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, + const object::Archive::Child &Member, + 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; @@ -518,7 +494,7 @@ computeInsertAction(ArchiveOperation Operation, // operation. sys::fs::file_status Status; failIfError(sys::fs::status(*MI, Status), *MI); - if (Status.getLastModificationTime() < I->getLastModified()) { + if (Status.getLastModificationTime() < Member.getLastModified()) { if (PosName.empty()) return IA_AddOldMember; return IA_MoveOldMember; @@ -541,11 +517,11 @@ 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 &ChildOrErr : OldArchive->children()) { + failIfError(ChildOrErr.getError()); + auto &Child = ChildOrErr.get(); int Pos = Ret.size(); - ErrorOr NameOrErr = I->getName(); + ErrorOr NameOrErr = Child.getName(); failIfError(NameOrErr.getError()); StringRef Name = NameOrErr.get(); if (Name == PosName) { @@ -556,22 +532,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); 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); break; } if (MemberI != Members.end()) @@ -591,268 +568,47 @@ computeNewArchiveMembers(ArchiveOperation Operation, assert(unsigned(InsertPos) <= Ret.size()); Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); - Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator()); + 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) { + addMember(Ret, Member, Pos); + ++Pos; } return Ret; } -template -static void printWithSpacePadding(raw_fd_ostream &OS, T Data, unsigned Size, - bool MayTruncate = false) { - uint64_t OldPos = OS.tell(); - OS << Data; - unsigned SizeSoFar = OS.tell() - OldPos; - if (Size > SizeSoFar) { - unsigned Remaining = Size - SizeSoFar; - for (unsigned I = 0; I < Remaining; ++I) - OS << ' '; - } else if (Size < SizeSoFar) { - assert(MayTruncate && "Data doesn't fit in Size"); - // Some of the data this is used for (like UID) can be larger than the - // space available in the archive format. Truncate in that case. - OS.seek(OldPos + Size); +static void +performWriteOperation(ArchiveOperation Operation, object::Archive *OldArchive, + std::vector *NewMembersP) { + object::Archive::Kind Kind; + switch (FormatOpt) { + case Default: { + Triple T(sys::getProcessTriple()); + if (T.isOSDarwin()) + Kind = object::Archive::K_BSD; + else + Kind = object::Archive::K_GNU; + break; } -} - -static void print32BE(raw_fd_ostream &Out, unsigned Val) { - for (int I = 3; I >= 0; --I) { - char V = (Val >> (8 * I)) & 0xff; - Out << V; - } -} - -static void printRestOfMemberHeader(raw_fd_ostream &Out, - const sys::TimeValue &ModTime, unsigned UID, - unsigned GID, unsigned Perms, - unsigned Size) { - printWithSpacePadding(Out, ModTime.toEpochTime(), 12); - printWithSpacePadding(Out, UID, 6, true); - printWithSpacePadding(Out, GID, 6, true); - printWithSpacePadding(Out, format("%o", Perms), 8); - printWithSpacePadding(Out, Size, 10); - Out << "`\n"; -} - -static void printMemberHeader(raw_fd_ostream &Out, StringRef Name, - const sys::TimeValue &ModTime, unsigned UID, - unsigned GID, unsigned Perms, unsigned Size) { - printWithSpacePadding(Out, Twine(Name) + "/", 16); - printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); -} - -static void printMemberHeader(raw_fd_ostream &Out, unsigned NameOffset, - const sys::TimeValue &ModTime, unsigned UID, - unsigned GID, unsigned Perms, unsigned Size) { - Out << '/'; - printWithSpacePadding(Out, NameOffset, 15); - printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); -} - -static void writeStringTable(raw_fd_ostream &Out, - ArrayRef Members, - std::vector &StringMapIndexes) { - unsigned StartOffset = 0; - for (ArrayRef::iterator I = Members.begin(), - E = Members.end(); - I != E; ++I) { - StringRef Name = I->getName(); - if (Name.size() < 16) - continue; - if (StartOffset == 0) { - printWithSpacePadding(Out, "//", 58); - Out << "`\n"; - StartOffset = Out.tell(); - } - StringMapIndexes.push_back(Out.tell() - StartOffset); - Out << Name << "/\n"; + case GNU: + Kind = object::Archive::K_GNU; + break; + case BSD: + Kind = object::Archive::K_BSD; + break; } - if (StartOffset == 0) + if (NewMembersP) { + std::pair Result = writeArchive( + ArchiveName, *NewMembersP, Symtab, Kind, Deterministic, Thin); + failIfError(Result.second, Result.first); return; - if (Out.tell() % 2) - Out << '\n'; - int Pos = Out.tell(); - Out.seek(StartOffset - 12); - printWithSpacePadding(Out, Pos - StartOffset, 10); - Out.seek(Pos); -} - -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; - LLVMContext &Context = getGlobalContext(); - for (ArrayRef::iterator I = Members.begin(), - E = Members.end(); - I != E; ++I, ++MemberNum) { - MemoryBuffer *MemberBuffer = Buffers[MemberNum]; - ErrorOr ObjOrErr = - object::SymbolicFile::createSymbolicFile( - MemberBuffer, false, sys::fs::file_magic::unknown, &Context); - if (!ObjOrErr) - continue; // FIXME: check only for "not an object file" errors. - std::unique_ptr Obj(ObjOrErr.get()); - - 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(); - 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)); - NameOS << '\0'; - ++NumSyms; - MemberOffsetRefs.push_back(std::make_pair(Out.tell(), MemberNum)); - print32BE(Out, 0); - } } - Out << NameOS.str(); - - if (StartOffset == 0) - return; - - if (Out.tell() % 2) - Out << '\0'; - - unsigned Pos = Out.tell(); - Out.seek(StartOffset - 12); - printWithSpacePadding(Out, Pos - StartOffset, 10); - Out.seek(StartOffset); - print32BE(Out, NumSyms); - Out.seek(Pos); -} - -static void performWriteOperation(ArchiveOperation Operation, - object::Archive *OldArchive) { - SmallString<128> TmpArchive; - failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", - TmpArchiveFD, TmpArchive)); - - TemporaryOutput = TmpArchive.c_str(); - tool_output_file Output(TemporaryOutput, TmpArchiveFD); - raw_fd_ostream &Out = Output.os(); - Out << "!\n"; - std::vector NewMembers = computeNewArchiveMembers(Operation, OldArchive); - - std::vector > MemberOffsetRefs; - - std::vector MemberBuffers; - MemberBuffers.resize(NewMembers.size()); - - for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { - std::unique_ptr MemberBuffer; - NewArchiveIterator &Member = NewMembers[I]; - - 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); - - } else { - object::Archive::child_iterator OldMember = Member.getOld(); - ErrorOr> MemberBufferOrErr = - OldMember->getMemoryBuffer(); - failIfError(MemberBufferOrErr.getError()); - MemberBuffer = std::move(MemberBufferOrErr.get()); - } - MemberBuffers[I] = MemberBuffer.release(); - } - - if (Symtab) { - writeSymbolTable(Out, NewMembers, MemberBuffers, MemberOffsetRefs); - } - - std::vector StringMapIndexes; - writeStringTable(Out, NewMembers, StringMapIndexes); - - std::vector >::iterator MemberRefsI = - MemberOffsetRefs.begin(); - - unsigned MemberNum = 0; - unsigned LongNameMemberNum = 0; - 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); - - const MemoryBuffer *File = MemberBuffers[MemberNum]; - if (I->isNewMember()) { - const char *FileName = I->getNew(); - const sys::fs::file_status &Status = I->getStatus(); - - StringRef Name = sys::path::filename(FileName); - if (Name.size() < 16) - printMemberHeader(Out, Name, Status.getLastModificationTime(), - Status.getUser(), Status.getGroup(), - Status.permissions(), Status.getSize()); - else - printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], - Status.getLastModificationTime(), Status.getUser(), - Status.getGroup(), Status.permissions(), - Status.getSize()); - } else { - object::Archive::child_iterator OldMember = I->getOld(); - StringRef Name = I->getName(); - - if (Name.size() < 16) - printMemberHeader(Out, Name, OldMember->getLastModified(), - OldMember->getUID(), OldMember->getGID(), - OldMember->getAccessMode(), OldMember->getSize()); - else - printMemberHeader(Out, StringMapIndexes[LongNameMemberNum++], - OldMember->getLastModified(), OldMember->getUID(), - OldMember->getGID(), OldMember->getAccessMode(), - OldMember->getSize()); - } - - 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); - TemporaryOutput = nullptr; + auto Result = + writeArchive(ArchiveName, NewMembers, Symtab, Kind, Deterministic, Thin); + failIfError(Result.second, Result.first); } static void createSymbolTable(object::Archive *OldArchive) { @@ -865,11 +621,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: @@ -881,7 +638,7 @@ static void performOperation(ArchiveOperation Operation, case Move: case QuickAppend: case ReplaceOrInsert: - performWriteOperation(Operation, OldArchive); + performWriteOperation(Operation, OldArchive, NewMembers); return; case CreateSymTab: createSymbolTable(OldArchive); @@ -890,67 +647,20 @@ 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); - if (EC && EC != errc::no_such_file_or_directory) { - errs() << ToolName << ": error opening '" << ArchiveName - << "': " << EC.message() << "!\n"; - return 1; - } + ErrorOr> Buf = + MemoryBuffer::getFile(ArchiveName, -1, false); + std::error_code EC = Buf.getError(); + if (EC && EC != errc::no_such_file_or_directory) + fail("error opening '" + ArchiveName + "': " + EC.message() + "!"); if (!EC) { - object::Archive Archive(Buf.release(), EC); - - if (EC) { - errs() << ToolName << ": error loading '" << ArchiveName - << "': " << EC.message() << "!\n"; - return 1; - } - performOperation(Operation, &Archive); + object::Archive Archive(Buf.get()->getMemBufferRef(), EC); + failIfError(EC, + "error loading '" + ArchiveName + "': " + EC.message() + "!"); + performOperation(Operation, &Archive, NewMembers); return 0; } @@ -965,6 +675,122 @@ 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 &MemberOrErr : Lib.children()) { + failIfError(MemberOrErr.getError()); + auto &Member = MemberOrErr.get(); + ErrorOr NameOrErr = Member.getName(); + failIfError(NameOrErr.getError()); + addMember(NewMembers, Member, *NameOrErr); + } + break; + } + case MRICommand::AddMod: + addMember(NewMembers, 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. + + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + + StringRef Stem = sys::path::stem(ToolName); + if (Stem.find("ranlib") == StringRef::npos && + Stem.find("lib") != StringRef::npos) + return libDriverMain(makeArrayRef(argv, argc)); + + // 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" + ); + + if (Stem.find("ranlib") != StringRef::npos) + return ranlib_main(); + if (Stem.find("ar") != StringRef::npos) + return ar_main(); + fail("Not ranlib, ar or lib!"); +}