diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:51:42 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:51:42 +0000 |
commit | 1d5ae1026e831016fc29fd927877c86af904481f (patch) | |
tree | 2cdfd12620fcfa5d9e4a0389f85368e8e36f63f9 /tools/llvm-ar/llvm-ar.cpp | |
parent | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (diff) |
Notes
Diffstat (limited to 'tools/llvm-ar/llvm-ar.cpp')
-rw-r--r-- | tools/llvm-ar/llvm-ar.cpp | 192 |
1 files changed, 118 insertions, 74 deletions
diff --git a/tools/llvm-ar/llvm-ar.cpp b/tools/llvm-ar/llvm-ar.cpp index 91746d0fab37..c9cf217f7688 100644 --- a/tools/llvm-ar/llvm-ar.cpp +++ b/tools/llvm-ar/llvm-ar.cpp @@ -43,6 +43,11 @@ #include <io.h> #endif +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + using namespace llvm; // The name this program was invoked as. @@ -70,14 +75,14 @@ USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] [count] <archive> [f llvm-ar -M [<mri-script] OPTIONS: - --format - Archive format to create + --format - archive format to create =default - default =gnu - gnu =darwin - darwin =bsd - bsd - --plugin=<string> - Ignored for compatibility - --help - Display available options - --version - Display the version of this program + --plugin=<string> - ignored for compatibility + -h --help - display this help and exit + --version - print the version and exit @<file> - read options from <file> OPERATIONS: @@ -95,11 +100,13 @@ MODIFIERS: [b] - put [files] before [relpos] (same as [i]) [c] - do not warn if archive had to be created [D] - use zero for timestamps and uids/gids (default) + [h] - display this help and exit [i] - put [files] before [relpos] (same as [b]) [l] - ignored for compatibility [L] - add archive's contents [N] - use instance [count] of name [o] - preserve original dates + [O] - display member offsets [P] - use full names when matching (implied for thin archives) [s] - create an archive index (cf. ranlib) [S] - do not build a symbol table @@ -107,6 +114,7 @@ MODIFIERS: [u] - update only [files] newer than archive contents [U] - use actual timestamps and uids/gids [v] - be verbose about actions taken + [V] - display the version and exit )"; void printHelpMessage() { @@ -116,10 +124,19 @@ void printHelpMessage() { outs() << ArHelp; } +static unsigned MRILineNumber; +static bool ParsingMRIScript; + // Show the error message and exit. LLVM_ATTRIBUTE_NORETURN static void fail(Twine Error) { - WithColor::error(errs(), ToolName) << Error << ".\n"; - printHelpMessage(); + if (ParsingMRIScript) { + WithColor::error(errs(), ToolName) + << "script line " << MRILineNumber << ": " << Error << "\n"; + } else { + WithColor::error(errs(), ToolName) << Error << "\n"; + printHelpMessage(); + } + exit(1); } @@ -171,17 +188,18 @@ enum ArchiveOperation { }; // Modifiers to follow operation to vary behavior -static bool AddAfter = false; ///< 'a' modifier -static bool AddBefore = false; ///< 'b' modifier -static bool Create = false; ///< 'c' modifier -static bool OriginalDates = false; ///< 'o' modifier -static bool CompareFullPath = false; ///< 'P' 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 -static bool AddLibrary = false; ///< 'L' modifier +static bool AddAfter = false; ///< 'a' modifier +static bool AddBefore = false; ///< 'b' modifier +static bool Create = false; ///< 'c' modifier +static bool OriginalDates = false; ///< 'o' modifier +static bool DisplayMemberOffsets = false; ///< 'O' modifier +static bool CompareFullPath = false; ///< 'P' 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 +static bool AddLibrary = false; ///< 'L' modifier // Relative Positional Argument (for insert/move). This variable holds // the name of the archive member to which the 'a', 'b' or 'i' modifier @@ -198,6 +216,9 @@ static int CountParam = 0; // command line. static std::string ArchiveName; +static std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; +static std::vector<std::unique_ptr<object::Archive>> Archives; + // This variable holds the list of member files to proecess, as given // on the command line. static std::vector<StringRef> Members; @@ -209,7 +230,7 @@ static BumpPtrAllocator Alloc; // associated with a, b, and i modifiers static void getRelPos() { if (PositionalArgs.empty()) - fail("Expected [relpos] for a, b, or i modifier"); + fail("expected [relpos] for 'a', 'b', or 'i' modifier"); RelPos = PositionalArgs[0]; PositionalArgs.erase(PositionalArgs.begin()); } @@ -218,40 +239,31 @@ static void getRelPos() { // associated with the N modifier static void getCountParam() { if (PositionalArgs.empty()) - fail("Expected [count] for N modifier"); + fail("expected [count] for 'N' modifier"); auto CountParamArg = StringRef(PositionalArgs[0]); if (CountParamArg.getAsInteger(10, CountParam)) - fail("Value for [count] must be numeric, got: " + CountParamArg); + fail("value for [count] must be numeric, got: " + CountParamArg); if (CountParam < 1) - fail("Value for [count] must be positive, got: " + CountParamArg); + fail("value for [count] must be positive, got: " + CountParamArg); PositionalArgs.erase(PositionalArgs.begin()); } // Get the archive file name from the command line static void getArchive() { if (PositionalArgs.empty()) - fail("An archive name must be specified"); + fail("an archive name must be specified"); ArchiveName = PositionalArgs[0]; PositionalArgs.erase(PositionalArgs.begin()); } -// Copy over remaining items in PositionalArgs to our Members vector -static void getMembers() { - for (auto &Arg : PositionalArgs) - Members.push_back(Arg); -} - -std::vector<std::unique_ptr<MemoryBuffer>> ArchiveBuffers; -std::vector<std::unique_ptr<object::Archive>> Archives; - static object::Archive &readLibrary(const Twine &Library) { auto BufOrErr = MemoryBuffer::getFile(Library, -1, false); - failIfError(BufOrErr.getError(), "Could not open library " + Library); + failIfError(BufOrErr.getError(), "could not open library " + Library); ArchiveBuffers.push_back(std::move(*BufOrErr)); auto LibOrErr = object::Archive::create(ArchiveBuffers.back()->getMemBufferRef()); failIfError(errorToErrorCode(LibOrErr.takeError()), - "Could not parse library"); + "could not parse library"); Archives.push_back(std::move(*LibOrErr)); return *Archives.back(); } @@ -264,7 +276,7 @@ static void runMRIScript(); static ArchiveOperation parseCommandLine() { if (MRI) { if (!PositionalArgs.empty() || !Options.empty()) - fail("Cannot mix -M and other options"); + fail("cannot mix -M and other options"); runMRIScript(); } @@ -319,6 +331,9 @@ static ArchiveOperation parseCommandLine() { case 'o': OriginalDates = true; break; + case 'O': + DisplayMemberOffsets = true; + break; case 'P': CompareFullPath = true; break; @@ -367,6 +382,12 @@ static ArchiveOperation parseCommandLine() { case 'L': AddLibrary = true; break; + case 'V': + cl::PrintVersionMessage(); + exit(0); + case 'h': + printHelpMessage(); + exit(0); default: fail(std::string("unknown option ") + Options[i]); } @@ -377,37 +398,37 @@ static ArchiveOperation parseCommandLine() { getArchive(); // Everything on the command line at this point is a member. - getMembers(); + Members.assign(PositionalArgs.begin(), PositionalArgs.end()); if (NumOperations == 0 && MaybeJustCreateSymTab) { NumOperations = 1; Operation = CreateSymTab; if (!Members.empty()) - fail("The s operation takes only an archive as argument"); + fail("the 's' operation takes only an archive as argument"); } // Perform various checks on the operation/modifier specification // to make sure we are dealing with a legal request. if (NumOperations == 0) - fail("You must specify at least one of the operations"); + fail("you must specify at least one of the operations"); if (NumOperations > 1) - fail("Only one operation may be specified"); + fail("only one operation may be specified"); if (NumPositional > 1) - fail("You may only specify one of a, b, and i modifiers"); + fail("you may only specify one of 'a', 'b', and 'i' modifiers"); if (AddAfter || AddBefore) if (Operation != Move && Operation != ReplaceOrInsert) - fail("The 'a', 'b' and 'i' modifiers can only be specified with " + fail("the 'a', 'b' and 'i' modifiers can only be specified with " "the 'm' or 'r' operations"); if (CountParam) if (Operation != Extract && Operation != Delete) - fail("The 'N' modifier can only be specified with the 'x' or 'd' " + fail("the 'N' modifier can only be specified with the 'x' or 'd' " "operations"); if (OriginalDates && Operation != Extract) - fail("The 'o' modifier is only applicable to the 'x' operation"); + fail("the 'o' modifier is only applicable to the 'x' operation"); if (OnlyUpdate && Operation != ReplaceOrInsert) - fail("The 'u' modifier is only applicable to the 'r' operation"); + fail("the 'u' modifier is only applicable to the 'r' operation"); if (AddLibrary && Operation != QuickAppend) - fail("The 'L' modifier is only applicable to the 'q' operation"); + fail("the 'L' modifier is only applicable to the 'q' operation"); // Return the parsed operation to the caller return Operation; @@ -470,12 +491,35 @@ static void doDisplayTable(StringRef Name, const object::Archive::Child &C) { if (!ParentDir.empty()) outs() << sys::path::convert_to_slash(ParentDir) << '/'; } + outs() << Name; + } else { + outs() << Name; + if (DisplayMemberOffsets) + outs() << " 0x" << utohexstr(C.getDataOffset(), true); } - outs() << Name << "\n"; + outs() << '\n'; } -static StringRef normalizePath(StringRef Path) { - return CompareFullPath ? Path : sys::path::filename(Path); +static std::string normalizePath(StringRef Path) { + return CompareFullPath ? sys::path::convert_to_slash(Path) + : std::string(sys::path::filename(Path)); +} + +static bool comparePaths(StringRef Path1, StringRef Path2) { +// When on Windows this function calls CompareStringOrdinal +// as Windows file paths are case-insensitive. +// CompareStringOrdinal compares two Unicode strings for +// binary equivalence and allows for case insensitivity. +#ifdef _WIN32 + SmallVector<wchar_t, 128> WPath1, WPath2; + failIfError(sys::path::widenPath(normalizePath(Path1), WPath1)); + failIfError(sys::path::widenPath(normalizePath(Path2), WPath2)); + + return CompareStringOrdinal(WPath1.data(), WPath1.size(), WPath2.data(), + WPath2.size(), true) == CSTR_EQUAL; +#else + return normalizePath(Path1) == normalizePath(Path2); +#endif } // Implement the 'x' operation. This function extracts files back to the file @@ -489,7 +533,7 @@ static void doExtract(StringRef Name, const object::Archive::Child &C) { int FD; failIfError(sys::fs::openFileForWrite(sys::path::filename(Name), FD, sys::fs::CD_CreateAlways, - sys::fs::F_None, Mode), + sys::fs::OF_None, Mode), Name); { @@ -551,7 +595,7 @@ static void performReadOperation(ArchiveOperation Operation, if (Filter) { auto I = find_if(Members, [Name](StringRef Path) { - return Name == normalizePath(Path); + return comparePaths(Name, Path); }); if (I == Members.end()) continue; @@ -588,7 +632,7 @@ static void addChildMember(std::vector<NewArchiveMember> &Members, const object::Archive::Child &M, bool FlattenArchive = false) { if (Thin && !M.getParent()->isThin()) - fail("Cannot convert a regular archive to a thin one"); + fail("cannot convert a regular archive to a thin one"); Expected<NewArchiveMember> NMOrErr = NewArchiveMember::getOldMember(M, Deterministic); failIfError(NMOrErr.takeError()); @@ -681,7 +725,7 @@ static InsertAction computeInsertAction(ArchiveOperation Operation, if (Operation == QuickAppend || Members.empty()) return IA_AddOldMember; auto MI = find_if( - Members, [Name](StringRef Path) { return Name == normalizePath(Path); }); + Members, [Name](StringRef Path) { return comparePaths(Name, Path); }); if (MI == Members.end()) return IA_AddOldMember; @@ -698,9 +742,8 @@ static InsertAction computeInsertAction(ArchiveOperation Operation, return IA_MoveOldMember; if (Operation == ReplaceOrInsert) { - StringRef PosName = normalizePath(RelPos); if (!OnlyUpdate) { - if (PosName.empty()) + if (RelPos.empty()) return IA_AddNewMember; return IA_MoveNewMember; } @@ -712,12 +755,12 @@ static InsertAction computeInsertAction(ArchiveOperation Operation, auto ModTimeOrErr = Member.getLastModified(); failIfError(ModTimeOrErr.takeError()); if (Status.getLastModificationTime() < ModTimeOrErr.get()) { - if (PosName.empty()) + if (RelPos.empty()) return IA_AddOldMember; return IA_MoveOldMember; } - if (PosName.empty()) + if (RelPos.empty()) return IA_AddNewMember; return IA_MoveNewMember; } @@ -732,7 +775,6 @@ computeNewArchiveMembers(ArchiveOperation Operation, std::vector<NewArchiveMember> Ret; std::vector<NewArchiveMember> Moved; int InsertPos = -1; - StringRef PosName = normalizePath(RelPos); if (OldArchive) { Error Err = Error::success(); StringMap<int> MemberCount; @@ -740,8 +782,8 @@ computeNewArchiveMembers(ArchiveOperation Operation, int Pos = Ret.size(); Expected<StringRef> NameOrErr = Child.getName(); failIfError(NameOrErr.takeError()); - StringRef Name = NameOrErr.get(); - if (Name == PosName) { + std::string Name = NameOrErr.get(); + if (comparePaths(Name, RelPos)) { assert(AddAfter || AddBefore); if (AddBefore) InsertPos = Pos; @@ -783,7 +825,7 @@ computeNewArchiveMembers(ArchiveOperation Operation, return Ret; if (!RelPos.empty() && InsertPos == -1) - fail("Insertion point not found"); + fail("insertion point not found"); if (RelPos.empty()) InsertPos = Ret.size(); @@ -859,12 +901,12 @@ static void performWriteOperation(ArchiveOperation Operation, break; case BSD: if (Thin) - fail("Only the gnu format has a thin mode"); + fail("only the gnu format has a thin mode"); Kind = object::Archive::K_BSD; break; case DARWIN: if (Thin) - fail("Only the gnu format has a thin mode"); + fail("only the gnu format has a thin mode"); Kind = object::Archive::K_DARWIN; break; case Unknown: @@ -922,14 +964,12 @@ static int performOperation(ArchiveOperation Operation, 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() + "!"); + fail("error opening '" + ArchiveName + "': " + EC.message()); if (!EC) { Error Err = Error::success(); object::Archive Archive(Buf.get()->getMemBufferRef(), Err); - EC = errorToErrorCode(std::move(Err)); - failIfError(EC, - "error loading '" + ArchiveName + "': " + EC.message() + "!"); + failIfError(std::move(Err), "unable to load '" + ArchiveName + "'"); if (Archive.isThin()) CompareFullPath = true; performOperation(Operation, &Archive, std::move(Buf.get()), NewMembers); @@ -960,8 +1000,10 @@ static void runMRIScript() { const MemoryBuffer &Ref = *Buf.get(); bool Saved = false; std::vector<NewArchiveMember> NewMembers; + ParsingMRIScript = true; for (line_iterator I(Ref, /*SkipBlanks*/ false), E; I != E; ++I) { + ++MRILineNumber; StringRef Line = *I; Line = Line.split(';').first; Line = Line.split('*').first; @@ -1003,15 +1045,15 @@ static void runMRIScript() { case MRICommand::Create: Create = true; if (!ArchiveName.empty()) - fail("Editing multiple archives not supported"); + fail("editing multiple archives not supported"); if (Saved) - fail("File already saved"); + fail("file already saved"); ArchiveName = Rest; break; case MRICommand::Delete: { - StringRef Name = normalizePath(Rest); - llvm::erase_if(NewMembers, - [=](NewArchiveMember &M) { return M.MemberName == Name; }); + llvm::erase_if(NewMembers, [=](NewArchiveMember &M) { + return comparePaths(M.MemberName, Rest); + }); break; } case MRICommand::Save: @@ -1020,10 +1062,12 @@ static void runMRIScript() { case MRICommand::End: break; case MRICommand::Invalid: - fail("Unknown command: " + CommandStr); + fail("unknown command: " + CommandStr); } } - + + ParsingMRIScript = false; + // Nothing to do if not saved. if (Saved) performOperation(ReplaceOrInsert, &NewMembers); @@ -1108,7 +1152,7 @@ static int ranlib_main(int argc, char **argv) { return 0; } else { if (ArchiveSpecified) - fail("Exactly one archive should be specified"); + fail("exactly one archive should be specified"); ArchiveSpecified = true; ArchiveName = argv[i]; } @@ -1136,5 +1180,5 @@ int main(int argc, char **argv) { if (Stem.contains_lower("ar")) return ar_main(argc, argv); - fail("Not ranlib, ar, lib or dlltool!"); + fail("not ranlib, ar, lib or dlltool"); } |