Index: llvm/test/tools/llvm-ar/response-utf8.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-ar/response-utf8.test @@ -0,0 +1,8 @@ +## Check that response files can cope with non-ascii characters. + +# RUN: llvm-ar r %t.a %s + +# RUN: echo "r %t-£.a %s" > %t-non-ascii.txt +# RUN: llvm-ar @%t-non-ascii.txt +## Work-around diff not working with non-ascii filenames on windows. +RUN: env LANG=en_US.UTF-8 %python -c "assert open(ur'%t-\U000000A3.a', 'rb').read() == open(r'%t.a', 'rb').read()" Index: llvm/test/tools/llvm-ar/response.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-ar/response.test @@ -0,0 +1,35 @@ +## 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', 'wb').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 "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: no such file or directory + +# RUN: echo "rc %t.a blah\foo" > %t-rsp.txt +# RUN: not llvm-ar -rsp-quoting=posix @%t-rsp.txt 2>&1 | \ +# RUN: FileCheck %s --check-prefix=POSIX +# POSIX: error: blahfoo: no such file or directory Index: llvm/tools/llvm-ar/llvm-ar.cpp =================================================================== --- llvm/tools/llvm-ar/llvm-ar.cpp +++ llvm/tools/llvm-ar/llvm-ar.cpp @@ -80,6 +80,10 @@ =bsd - bsd --plugin= - ignored for compatibility -h --help - display this help and exit + --rsp-quoting - quoting style for response files + =default - default + =posix - posix + =windows - windows --version - print the version and exit @ - read options from @@ -259,6 +263,37 @@ PositionalArgs.erase(PositionalArgs.begin()); } +static cl::TokenizerCallback getRspQuoting(SmallVector &Argv) { + cl::TokenizerCallback Default = + Triple(sys::getProcessTriple()).getOS() == Triple::Win32 + ? cl::TokenizeWindowsCommandLine + : cl::TokenizeGNUCommandLine; + + cl::TokenizerCallback Ret = Default; + size_t j = 1; + + for (size_t i = 1; i < Argv.size(); ++i) { + StringRef Arg = Argv[i]; + if (Arg.startswith("-rsp-quoting=") || Arg.startswith("--rsp-quoting=")) { + + StringRef Match = Arg.split("=").second; + if (Match == "posix") + Ret = cl::TokenizeGNUCommandLine; + else if (Match == "windows") + Ret = cl::TokenizeWindowsCommandLine; + else if (Match == "default") + Ret = Default; + else + fail(std::string("Invalid response file quoting style ") + Match); + + } else + Argv[j++] = Argv[i]; + } + + Argv.set_size(j); + return Ret; +} + static object::Archive &readLibrary(const Twine &Library) { auto BufOrErr = MemoryBuffer::getFile(Library, -1, false); failIfError(BufOrErr.getError(), "could not open library " + Library); @@ -1096,7 +1131,8 @@ static int ar_main(int argc, char **argv) { SmallVector Argv(argv, argv + argc); StringSaver Saver(Alloc); - cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Argv); + + cl::ExpandResponseFiles(Saver, getRspQuoting(Argv), Argv); for (size_t i = 1; i < Argv.size(); ++i) { StringRef Arg = Argv[i]; const char *match = nullptr;