summaryrefslogtreecommitdiff
path: root/tools/llvm-ar/llvm-ar.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-10-23 17:51:42 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-10-23 17:51:42 +0000
commit1d5ae1026e831016fc29fd927877c86af904481f (patch)
tree2cdfd12620fcfa5d9e4a0389f85368e8e36f63f9 /tools/llvm-ar/llvm-ar.cpp
parente6d1592492a3a379186bfb02bd0f4eda0669c0d5 (diff)
Notes
Diffstat (limited to 'tools/llvm-ar/llvm-ar.cpp')
-rw-r--r--tools/llvm-ar/llvm-ar.cpp192
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");
}