[llvm] 62fa333 - [llvm-ar] Fix llvm-ar response file reading on Windows
via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 3 05:44:59 PST 2020
Author: gbreynoo
Date: 2020-03-03T13:42:57Z
New Revision: 62fa3332c9c1af1e66dfecd40f5b4e78882998b2
URL: https://github.com/llvm/llvm-project/commit/62fa3332c9c1af1e66dfecd40f5b4e78882998b2
DIFF: https://github.com/llvm/llvm-project/commit/62fa3332c9c1af1e66dfecd40f5b4e78882998b2.diff
LOG: [llvm-ar] Fix llvm-ar response file reading on Windows
Response files where not being correctly read on Windows, this change
fixes the issue and adds some tests.
Differential Revision: https://reviews.llvm.org/D69665
Added:
llvm/test/tools/llvm-ar/response-utf8.test
llvm/test/tools/llvm-ar/response.test
Modified:
llvm/tools/llvm-ar/llvm-ar.cpp
Removed:
################################################################################
diff --git a/llvm/test/tools/llvm-ar/response-utf8.test b/llvm/test/tools/llvm-ar/response-utf8.test
new file mode 100644
index 000000000000..b3e405f85490
--- /dev/null
+++ b/llvm/test/tools/llvm-ar/response-utf8.test
@@ -0,0 +1,11 @@
+## Check that response files can cope with non-ascii characters.
+
+# RUN: echo 'contents' > %t-£.txt
+
+# RUN: rm -f %t-£.a
+# RUN: echo 'r %t-£.a %t-£.txt' > %t-replace.txt
+# RUN: llvm-ar @%t-replace.txt
+
+# RUN: echo 'p %t-£.a %t-£.txt' > %t-print.txt
+# RUN: llvm-ar @%t-print.txt | FileCheck %s
+# CHECK: contents
diff --git a/llvm/test/tools/llvm-ar/response.test b/llvm/test/tools/llvm-ar/response.test
new file mode 100644
index 000000000000..a08a63e88182
--- /dev/null
+++ b/llvm/test/tools/llvm-ar/response.test
@@ -0,0 +1,34 @@
+## llvm-ar should be able to consume response files.
+
+# RUN: echo 'contents' > %t.txt
+# RUN: echo 'rc %t1.a %t.txt' > %t.response1.txt
+# RUN: llvm-ar @%t.response1.txt
+# RUN: llvm-ar p %t1.a | FileCheck %s --check-prefix=CONTENTS
+
+## Quotes and Spaces.
+# RUN: echo 'contents' > '%t space.txt'
+## Python is used here to ensure the quotes are written to the response file
+# RUN: %python -c "import os; open(r'%t.response2.txt', 'w').write(r'%t2.a \"%t space.txt\"'+ '\n')"
+# RUN: llvm-ar rc @%t.response2.txt
+# RUN: llvm-ar p %t2.a | FileCheck %s --check-prefix=CONTENTS
+
+## Arguments after the response file.
+# RUN: echo 'rc %t3.a' > %t.response3.txt
+# RUN: llvm-ar @%t.response3.txt %t.txt
+# RUN: llvm-ar p %t3.a | FileCheck %s --check-prefix=CONTENTS
+
+# CONTENTS: contents
+
+## rsp-quoting
+# RUN: not llvm-ar --rsp-quoting=foobar @%t.response1.txt 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERROR
+# ERROR: Invalid response file quoting style foobar
+
+# RUN: echo -e 'rc %/t.a blah\\foo' > %t-rsp.txt
+# RUN: not llvm-ar --rsp-quoting=windows @%t-rsp.txt 2>&1 | \
+# RUN: FileCheck %s --check-prefix=WIN
+# WIN: error: blah\foo: {{[Nn]}}o such file or directory
+
+# RUN: not llvm-ar -rsp-quoting posix @%t-rsp.txt 2>&1 | \
+# RUN: FileCheck %s --check-prefix=POSIX
+# POSIX: error: blahfoo: {{[Nn]}}o such file or directory
diff --git a/llvm/tools/llvm-ar/llvm-ar.cpp b/llvm/tools/llvm-ar/llvm-ar.cpp
index 401dc7f8c7d2..8e7a85f5a9b0 100644
--- a/llvm/tools/llvm-ar/llvm-ar.cpp
+++ b/llvm/tools/llvm-ar/llvm-ar.cpp
@@ -83,6 +83,9 @@ USAGE: llvm-ar [options] [-]<operation>[modifiers] [relpos] [count] <archive> [f
=bsd - bsd
--plugin=<string> - ignored for compatibility
-h --help - display this help and exit
+ --rsp-quoting - quoting style for response files
+ =posix - posix
+ =windows - windows
--version - print the version and exit
@<file> - read options from <file>
@@ -1096,61 +1099,105 @@ static bool handleGenericOption(StringRef arg) {
return false;
}
+static const char *matchFlagWithArg(StringRef Expected,
+ ArrayRef<const char *>::iterator &ArgIt,
+ ArrayRef<const char *> Args) {
+ StringRef Arg = *ArgIt;
+
+ if (Arg.startswith("--"))
+ Arg = Arg.substr(2);
+ else if (Arg.startswith("-"))
+ Arg = Arg.substr(1);
+
+ size_t len = Expected.size();
+ if (Arg == Expected) {
+ if (++ArgIt == Args.end())
+ fail(std::string(Expected) + " requires an argument");
+
+ return *ArgIt;
+ }
+ if (Arg.startswith(Expected) && Arg.size() > len && Arg[len] == '=')
+ return Arg.data() + len + 1;
+
+ return nullptr;
+}
+
+static cl::TokenizerCallback getRspQuoting(ArrayRef<const char *> ArgsArr) {
+ cl::TokenizerCallback Ret =
+ Triple(sys::getProcessTriple()).getOS() == Triple::Win32
+ ? cl::TokenizeWindowsCommandLine
+ : cl::TokenizeGNUCommandLine;
+
+ for (ArrayRef<const char *>::iterator ArgIt = ArgsArr.begin();
+ ArgIt != ArgsArr.end(); ++ArgIt) {
+ if (const char *Match = matchFlagWithArg("rsp-quoting", ArgIt, ArgsArr)) {
+ StringRef MatchRef = Match;
+ if (MatchRef == "posix")
+ Ret = cl::TokenizeGNUCommandLine;
+ else if (MatchRef == "windows")
+ Ret = cl::TokenizeWindowsCommandLine;
+ else
+ fail(std::string("Invalid response file quoting style ") + Match);
+ }
+ }
+
+ return Ret;
+}
+
static int ar_main(int argc, char **argv) {
- SmallVector<const char *, 0> Argv(argv, argv + argc);
+ SmallVector<const char *, 0> Argv(argv + 1, argv + argc);
StringSaver Saver(Alloc);
- cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv);
- for (size_t i = 1; i < Argv.size(); ++i) {
- StringRef Arg = Argv[i];
- const char *match = nullptr;
- auto MatchFlagWithArg = [&](const char *expected) {
- size_t len = strlen(expected);
- if (Arg == expected) {
- if (++i >= Argv.size())
- fail(std::string(expected) + " requires an argument");
- match = Argv[i];
- return true;
- }
- if (Arg.startswith(expected) && Arg.size() > len && Arg[len] == '=') {
- match = Arg.data() + len + 1;
- return true;
- }
- return false;
- };
- if (handleGenericOption(Argv[i]))
+
+ cl::ExpandResponseFiles(Saver, getRspQuoting(makeArrayRef(argv, argc)), Argv);
+
+ ArrayRef<const char *> ArgsArr = makeArrayRef(argv, argc);
+
+ for (ArrayRef<const char *>::iterator ArgIt = Argv.begin();
+ ArgIt != Argv.end(); ++ArgIt) {
+ const char *Match = nullptr;
+
+ if (handleGenericOption(*ArgIt))
return 0;
- if (Arg == "--") {
- for (; i < Argv.size(); ++i)
- PositionalArgs.push_back(Argv[i]);
+ if (strcmp(*ArgIt, "--") == 0) {
+ ++ArgIt;
+ for (; ArgIt != Argv.end(); ++ArgIt)
+ PositionalArgs.push_back(*ArgIt);
break;
}
- if (Arg[0] == '-') {
- if (Arg.startswith("--"))
- Arg = Argv[i] + 2;
+
+ if (*ArgIt[0] != '-') {
+ if (Options.empty())
+ Options += *ArgIt;
else
- Arg = Argv[i] + 1;
- if (Arg == "M") {
- MRI = true;
- } else if (MatchFlagWithArg("format")) {
- FormatType = StringSwitch<Format>(match)
- .Case("default", Default)
- .Case("gnu", GNU)
- .Case("darwin", DARWIN)
- .Case("bsd", BSD)
- .Default(Unknown);
- if (FormatType == Unknown)
- fail(std::string("Invalid format ") + match);
- } else if (MatchFlagWithArg("plugin")) {
- // Ignored.
- } else {
- Options += Argv[i] + 1;
- }
- } else if (Options.empty()) {
- Options += Argv[i];
- } else {
- PositionalArgs.push_back(Argv[i]);
+ PositionalArgs.push_back(*ArgIt);
+ continue;
}
+
+ if (strcmp(*ArgIt, "-M") == 0) {
+ MRI = true;
+ continue;
+ }
+
+ Match = matchFlagWithArg("format", ArgIt, Argv);
+ if (Match) {
+ FormatType = StringSwitch<Format>(Match)
+ .Case("default", Default)
+ .Case("gnu", GNU)
+ .Case("darwin", DARWIN)
+ .Case("bsd", BSD)
+ .Default(Unknown);
+ if (FormatType == Unknown)
+ fail(std::string("Invalid format ") + Match);
+ continue;
+ }
+
+ if (matchFlagWithArg("plugin", ArgIt, Argv) ||
+ matchFlagWithArg("rsp-quoting", ArgIt, Argv))
+ continue;
+
+ Options += *ArgIt + 1;
}
+
ArchiveOperation Operation = parseCommandLine();
return performOperation(Operation, nullptr);
}
More information about the llvm-commits
mailing list