X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=tools%2Fllvm-ar%2Fllvm-ar.cpp;h=e1987b107fe1b9f7572634766555fd8f1f947d19;hp=e082687643dbe543f079e5acd1f3298e95736985;hb=1a6eca243f9274b9b371b7306fa939568ce5c37f;hpb=289e241d775565b450286a682d7e8a1a1b625f61 diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index e082687643d..e1987b107fe 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -15,6 +15,7 @@ #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/FileSystem.h" #include "llvm/Support/Format.h" @@ -26,7 +27,6 @@ #include "llvm/Support/raw_ostream.h" #include #include -#include #include #if !defined(_MSC_VER) && !defined(__MINGW32__) @@ -41,10 +41,13 @@ using namespace llvm; static StringRef ToolName; static const char *TemporaryOutput; +static int TmpArchiveFD = -1; // fail - 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); @@ -60,20 +63,13 @@ static void failIfError(error_code EC, Twine Context = "") { fail(Context + ": " + EC.message()); } -// 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. +// llvm-ar/llvm-ranlib remaining positional arguments. static cl::list RestOfArgs(cl::Positional, cl::OneOrMore, cl::desc("[relpos] [count] [members]...")); +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. @@ -109,7 +105,8 @@ enum ArchiveOperation { 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 + Extract, ///< Extract files back to file system + CreateSymTab ///< Create a symbol table in an existing archive }; // Modifiers to follow operation to vary behavior @@ -119,6 +116,7 @@ static bool Create = false; ///< 'c' modifier static bool OriginalDates = false; ///< 'o' modifier static bool OnlyUpdate = false; ///< 'u' modifier static bool Verbose = false; ///< 'v' modifier +static bool Symtab = true; ///< 's' modifier // Relative Positional Argument (for insert/move). This variable holds // the name of the archive member to which the 'a', 'b' or 'i' modifier @@ -151,6 +149,13 @@ static void getRelPos() { RestOfArgs.erase(RestOfArgs.begin()); } +static void getOptions() { + if(RestOfArgs.size() == 0) + show_help("Expected options"); + Options = RestOfArgs[0]; + RestOfArgs.erase(RestOfArgs.begin()); +} + // getArchive - Get the archive file name from the command line static void getArchive() { if(RestOfArgs.size() == 0) @@ -170,6 +175,7 @@ static void getMembers() { // operation specified. Process all modifiers and check to make sure that // constraints on modifier/operation pairs have not been violated. static ArchiveOperation parseCommandLine() { + getOptions(); // Keep track of number of operations. We can only specify one // per execution. @@ -182,6 +188,8 @@ static ArchiveOperation parseCommandLine() { // Keep track of which operation was requested ArchiveOperation Operation; + bool MaybeJustCreateSymTab = false; + for(unsigned i=0; igetAccessMode(); + SmallString<128> Storage = Name; - int FD = open(Name.str().c_str(), OpenFlags, Mode); - if (FD < 0) - fail("Could not open output file"); + int FD; + failIfError( + sys::fs::openFileForWrite(Storage.c_str(), FD, sys::fs::F_None, Mode), + Storage.c_str()); { raw_fd_ostream file(FD, false); @@ -337,6 +352,7 @@ static bool shouldCreateArchive(ArchiveOperation Op) { case Move: case DisplayTable: case Extract: + case CreateSymTab: return false; case QuickAppend: @@ -349,8 +365,8 @@ static bool shouldCreateArchive(ArchiveOperation Op) { static void performReadOperation(ArchiveOperation Operation, object::Archive *OldArchive) { - for (object::Archive::child_iterator I = OldArchive->begin_children(), - E = OldArchive->end_children(); + for (object::Archive::child_iterator I = OldArchive->child_begin(), + E = OldArchive->child_end(); I != E; ++I) { StringRef Name; failIfError(I->getName(Name)); @@ -378,31 +394,39 @@ static void performReadOperation(ArchiveOperation Operation, namespace { class NewArchiveIterator { bool IsNewMember; - SmallString<16> MemberName; + StringRef Name; + object::Archive::child_iterator OldI; - std::vector::const_iterator NewI; + + std::string NewFilename; + mutable int NewFD; + mutable sys::fs::file_status NewStatus; public: - NewArchiveIterator(object::Archive::child_iterator I, Twine Name); - NewArchiveIterator(std::vector::const_iterator I, Twine Name); + 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; - StringRef getMemberName() const { return MemberName; } + int getFD() const; + const sys::fs::file_status &getStatus() const; }; } +NewArchiveIterator::NewArchiveIterator() {} + NewArchiveIterator::NewArchiveIterator(object::Archive::child_iterator I, - Twine Name) - : IsNewMember(false), OldI(I) { - Name.toVector(MemberName); -} + StringRef Name) + : IsNewMember(false), Name(Name), OldI(I) {} -NewArchiveIterator::NewArchiveIterator( - std::vector::const_iterator I, Twine Name) - : IsNewMember(true), NewI(I) { - Name.toVector(MemberName); -} +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; } @@ -413,49 +437,113 @@ object::Archive::child_iterator NewArchiveIterator::getOld() const { const char *NewArchiveIterator::getNew() const { assert(IsNewMember); - return NewI->c_str(); + 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(error_code(errc::is_a_directory, posix_category()), + NewFilename); + + 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, - std::string &StringTable, T I, StringRef Name) { - if (Name.size() < 16) { - NewArchiveIterator NI(I, Twine(Name) + "/"); +void addMember(std::vector &Members, T I, StringRef Name, + int Pos = -1) { + NewArchiveIterator NI(I, Name); + if (Pos == -1) Members.push_back(NI); - } else { - int MapIndex = StringTable.size(); - NewArchiveIterator NI(I, Twine("/") + Twine(MapIndex)); - Members.push_back(NI); - StringTable += Name; - StringTable += "/\n"; - } + else + Members[Pos] = NI; } -namespace { -class HasName { - StringRef Name; - -public: - HasName(StringRef Name) : Name(Name) {} - bool operator()(StringRef Path) { return Name == sys::path::filename(Path); } +enum InsertAction { + IA_AddOldMember, + IA_AddNewMeber, + IA_Delete, + IA_MoveOldMember, + IA_MoveNewMember }; + +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); }); + + if (MI == Members.end()) + return IA_AddOldMember; + + Pos = MI; + + if (Operation == Delete) + return IA_Delete; + + if (Operation == Move) + return IA_MoveOldMember; + + if (Operation == ReplaceOrInsert) { + StringRef PosName = sys::path::filename(RelPos); + if (!OnlyUpdate) { + if (PosName.empty()) + return IA_AddNewMeber; + return IA_MoveNewMember; + } + + // We could try to optimize this to a fstat, but it is not a common + // operation. + sys::fs::file_status Status; + failIfError(sys::fs::status(*MI, Status)); + if (Status.getLastModificationTime() < I->getLastModified()) { + if (PosName.empty()) + return IA_AddOldMember; + return IA_MoveOldMember; + } + + if (PosName.empty()) + return IA_AddNewMeber; + return IA_MoveNewMember; + } + llvm_unreachable("No such operation"); } // We have to walk this twice and computing it is not trivial, so creating an // explicit std::vector is actually fairly efficient. static std::vector computeNewArchiveMembers(ArchiveOperation Operation, - object::Archive *OldArchive, - std::string &StringTable) { + object::Archive *OldArchive) { std::vector Ret; std::vector Moved; int InsertPos = -1; StringRef PosName = sys::path::filename(RelPos); if (OldArchive) { - int Pos = 0; - for (object::Archive::child_iterator I = OldArchive->begin_children(), - E = OldArchive->end_children(); - I != E; ++I, ++Pos) { + for (object::Archive::child_iterator I = OldArchive->child_begin(), + E = OldArchive->child_end(); + I != E; ++I) { + int Pos = Ret.size(); StringRef Name; failIfError(I->getName(Name)); if (Name == PosName) { @@ -465,68 +553,205 @@ computeNewArchiveMembers(ArchiveOperation Operation, else InsertPos = Pos + 1; } - if (Operation != QuickAppend && !Members.empty()) { - std::vector::iterator MI = - std::find_if(Members.begin(), Members.end(), HasName(Name)); - if (MI != Members.end()) { - if (Operation == Move) { - addMember(Moved, StringTable, I, Name); - continue; - } - if (Operation != ReplaceOrInsert || !OnlyUpdate) - continue; - // Ignore if the file if it is older than the member. - sys::fs::file_status Status; - failIfError(sys::fs::status(*MI, Status)); - if (Status.getLastModificationTime() < I->getLastModified()) - Members.erase(MI); - else - continue; - } + + 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); + break; + case IA_Delete: + break; + case IA_MoveOldMember: + addMember(Moved, I, Name); + break; + case IA_MoveNewMember: + addMember(Moved, &*MemberI, Name); + break; } - addMember(Ret, StringTable, I, Name); + if (MemberI != Members.end()) + Members.erase(MemberI); } } if (Operation == Delete) return Ret; - if (Operation == Move) { - if (RelPos.empty()) { - Ret.insert(Ret.end(), Moved.begin(), Moved.end()); - return Ret; - } - if (InsertPos == -1) - fail("Insertion point not found"); - assert(unsigned(InsertPos) <= Ret.size()); - Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); - return Ret; - } + if (!RelPos.empty() && InsertPos == -1) + fail("Insertion point not found"); + if (RelPos.empty()) + InsertPos = Ret.size(); + + assert(unsigned(InsertPos) <= Ret.size()); + Ret.insert(Ret.begin() + InsertPos, Moved.begin(), Moved.end()); + + Ret.insert(Ret.begin() + InsertPos, Members.size(), NewArchiveIterator()); + int Pos = InsertPos; for (std::vector::iterator I = Members.begin(), - E = Members.end(); - I != E; ++I) { + E = Members.end(); + I != E; ++I, ++Pos) { StringRef Name = sys::path::filename(*I); - addMember(Ret, StringTable, I, Name); + addMember(Ret, &*I, Name, Pos); } return Ret; } template -static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { +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; - assert(Size >= SizeSoFar && "Data doesn't fit in Size"); - unsigned Remaining = Size - SizeSoFar; - for (unsigned I = 0; I < Remaining; ++I) - OS << ' '; + 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 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"; + } + if (StartOffset == 0) + 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; + 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 = + object::SymbolicFile::createSymbolicFile( + MemberBuffer, false, sys::fs::file_magic::unknown, &Context); + if (!ObjOrErr) + continue; // FIXME: check only for "not an object file" errors. + 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(); + 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(); + + for (std::vector::iterator I = DeleteIt.begin(), + E = DeleteIt.end(); + I != E; ++I) { + object::SymbolicFile *O = *I; + delete O; + } + + 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) { - int TmpArchiveFD; SmallString<128> TmpArchive; failIfError(sys::fs::createUniqueFile(ArchiveName + ".temp-archive-%%%%%%%.a", TmpArchiveFD, TmpArchive)); @@ -536,68 +761,117 @@ static void performWriteOperation(ArchiveOperation Operation, raw_fd_ostream &Out = Output.os(); Out << "!\n"; - std::string StringTable; std::vector NewMembers = - computeNewArchiveMembers(Operation, OldArchive, StringTable); - if (!StringTable.empty()) { - if (StringTable.size() % 2) - StringTable += '\n'; - printWithSpacePadding(Out, "//", 48); - printWithSpacePadding(Out, StringTable.size(), 10); - Out << "`\n"; - Out << StringTable; - } + computeNewArchiveMembers(Operation, OldArchive); - for (std::vector::iterator I = NewMembers.begin(), - E = NewMembers.end(); - I != E; ++I) { - StringRef Name = I->getMemberName(); - printWithSpacePadding(Out, Name, 16); + std::vector > MemberOffsetRefs; - if (I->isNewMember()) { - // FIXME: we do a stat + open. We should do a open + fstat. - const char *FileName = I->getNew(); - sys::fs::file_status Status; - failIfError(sys::fs::status(FileName, Status), FileName); + std::vector MemberBuffers; + MemberBuffers.resize(NewMembers.size()); - OwningPtr File; - failIfError(MemoryBuffer::getFile(FileName, File), FileName); + for (unsigned I = 0, N = NewMembers.size(); I < N; ++I) { + OwningPtr MemberBuffer; + NewArchiveIterator &Member = NewMembers[I]; - uint64_t secondsSinceEpoch = - Status.getLastModificationTime().toEpochTime(); - printWithSpacePadding(Out, secondsSinceEpoch, 12); + 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); - printWithSpacePadding(Out, Status.getUser(), 6); - printWithSpacePadding(Out, Status.getGroup(), 6); - printWithSpacePadding(Out, format("%o", Status.permissions()), 8); - printWithSpacePadding(Out, Status.getSize(), 10); - Out << "`\n"; - - Out << File->getBuffer(); } else { - object::Archive::child_iterator OldMember = I->getOld(); + object::Archive::child_iterator OldMember = Member.getOld(); + failIfError(OldMember->getMemoryBuffer(MemberBuffer)); + } + MemberBuffers[I] = MemberBuffer.release(); + } - uint64_t secondsSinceEpoch = OldMember->getLastModified().toEpochTime(); - printWithSpacePadding(Out, secondsSinceEpoch, 12); + if (Symtab) { + writeSymbolTable(Out, NewMembers, MemberBuffers, MemberOffsetRefs); + } - printWithSpacePadding(Out, OldMember->getUID(), 6); - printWithSpacePadding(Out, OldMember->getGID(), 6); - printWithSpacePadding(Out, format("%o", OldMember->getAccessMode()), 8); - printWithSpacePadding(Out, OldMember->getSize(), 10); - Out << "`\n"; + 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); - Out << OldMember->getBuffer(); + 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 = NULL; } +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 + // is given, it will have no symbol table. + // In summary, we only need to update the symbol table if we have none. + // This is actually very common because of broken build systems that think + // they have to run ranlib. + if (OldArchive->hasSymbolTable()) + return; + + performWriteOperation(CreateSymTab, OldArchive); +} + static void performOperation(ArchiveOperation Operation, object::Archive *OldArchive) { switch (Operation) { @@ -613,10 +887,16 @@ static void performOperation(ArchiveOperation Operation, case ReplaceOrInsert: performWriteOperation(Operation, OldArchive); return; + case CreateSymTab: + createSymbolTable(OldArchive); + return; } 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]; @@ -632,24 +912,45 @@ int main(int argc, char **argv) { " 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. OwningPtr Buf; error_code EC = MemoryBuffer::getFile(ArchiveName, Buf, -1, false); if (EC && EC != llvm::errc::no_such_file_or_directory) { - errs() << argv[0] << ": error opening '" << ArchiveName + errs() << ToolName << ": error opening '" << ArchiveName << "': " << EC.message() << "!\n"; return 1; } if (!EC) { - object::Archive Archive(Buf.take(), EC); + object::Archive Archive(Buf.release(), EC); if (EC) { - errs() << argv[0] << ": error loading '" << ArchiveName + errs() << ToolName << ": error loading '" << ArchiveName << "': " << EC.message() << "!\n"; return 1; } @@ -664,7 +965,7 @@ int main(int argc, char **argv) { } else { if (!Create) { // Produce a warning if we should and we're creating the archive - errs() << argv[0] << ": creating " << ArchiveName << "\n"; + errs() << ToolName << ": creating " << ArchiveName << "\n"; } }