Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -48,18 +48,17 @@ class ArgParser { public: - // Parses command line options. - llvm::opt::InputArgList parse(llvm::ArrayRef Args); - - // Concatenate LINK environment varirable and given arguments and parse them. + // Concatenate LINK environment variable and given arguments and parse them. llvm::opt::InputArgList parseLINK(std::vector Args); // Tokenizes a given string and then parses as command line options. llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } private: + // Parses command line options. + llvm::opt::InputArgList parse(llvm::ArrayRef Args); + std::vector tokenize(StringRef S); - std::vector replaceResponseFiles(std::vector); COFFOptTable Table; }; Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -202,6 +202,7 @@ // specified by /defaultlib. void LinkerDriver::parseDirectives(StringRef S) { ArgParser Parser; + // .drectve is always tokenized using Windows shell rules. opt::InputArgList Args = Parser.parse(S); for (auto *Arg : Args) { Index: COFF/DriverUtils.cpp =================================================================== --- COFF/DriverUtils.cpp +++ COFF/DriverUtils.cpp @@ -38,8 +38,6 @@ using namespace llvm::COFF; using namespace llvm; -using llvm::cl::ExpandResponseFiles; -using llvm::cl::TokenizeWindowsCommandLine; using llvm::sys::Process; namespace lld { @@ -718,20 +716,40 @@ COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {} -// Parses a given list of options. -opt::InputArgList ArgParser::parse(ArrayRef ArgsArr) { - // First, replace respnose files (@-style options). - std::vector Argv = replaceResponseFiles(ArgsArr); +static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { + if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { + StringRef S = Arg->getValue(); + if (S != "windows" && S != "posix") + error("invalid response file quoting: " + S); + if (S == "windows") + return cl::TokenizeWindowsCommandLine; + return cl::TokenizeGNUCommandLine; + } + // The COFF linker always defaults to Windows quoting. + return cl::TokenizeWindowsCommandLine; +} +// Parses a given list of options. +opt::InputArgList ArgParser::parse(ArrayRef Argv) { // Make InputArgList from string vectors. unsigned MissingIndex; unsigned MissingCount; - opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount); + SmallVector Vec(Argv.data(), Argv.data() + Argv.size()); + + // We need to get the quoting style for response files before parsing all + // options so we parse here before and ignore all the options but + // --rsp-quoting. + opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); + + // Expand response files (arguments in the form of @) + // and then parse the argument again. + cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); + Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); // Print the real command line if response files are expanded. - if (Args.hasArg(OPT_verbose) && ArgsArr.size() != Argv.size()) { + if (Args.hasArg(OPT_verbose) && Argv.size() != Vec.size()) { std::string Msg = "Command line:"; - for (const char *S : Argv) + for (const char *S : Vec) Msg += " " + std::string(S); message(Msg); } @@ -746,17 +764,17 @@ // link.exe has an interesting feature. If LINK or _LINK_ environment // variables exist, their contents are handled as command line strings. // So you can pass extra arguments using them. -opt::InputArgList ArgParser::parseLINK(std::vector Args) { +opt::InputArgList ArgParser::parseLINK(std::vector Argv) { // Concatenate LINK env and command line arguments, and then parse them. if (Optional S = Process::GetEnv("LINK")) { std::vector V = tokenize(*S); - Args.insert(Args.begin(), V.begin(), V.end()); + Argv.insert(Argv.begin(), V.begin(), V.end()); } if (Optional S = Process::GetEnv("_LINK_")) { std::vector V = tokenize(*S); - Args.insert(Args.begin(), V.begin(), V.end()); + Argv.insert(Argv.begin(), V.begin(), V.end()); } - return parse(Args); + return parse(Argv); } std::vector ArgParser::tokenize(StringRef S) { @@ -765,15 +783,6 @@ return std::vector(Tokens.begin(), Tokens.end()); } -// Creates a new command line by replacing options starting with '@' -// character. '@' is replaced by the file's contents. -std::vector -ArgParser::replaceResponseFiles(std::vector Argv) { - SmallVector Tokens(Argv.data(), Argv.data() + Argv.size()); - ExpandResponseFiles(Saver, TokenizeWindowsCommandLine, Tokens); - return std::vector(Tokens.begin(), Tokens.end()); -} - void printHelp(const char *Argv0) { COFFOptTable Table; Table.PrintHelp(outs(), Argv0, "LLVM Linker", false); Index: COFF/Options.td =================================================================== --- COFF/Options.td +++ COFF/Options.td @@ -101,6 +101,8 @@ def nopdb : F<"nopdb">, HelpText<"Disable PDB generation for DWARF users">; def nosymtab : F<"nosymtab">; def msvclto : F<"msvclto">; +def rsp_quoting : Joined<["--"], "rsp-quoting=">, + HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">; // Flags for debugging def lldmap : F<"lldmap">; Index: test/COFF/responsefile.test =================================================================== --- test/COFF/responsefile.test +++ test/COFF/responsefile.test @@ -3,5 +3,23 @@ # RUN: echo /out:%t.exe /entry:main %t.obj > %t.rsp # RUN: lld-link @%t.rsp /heap:0x3000 # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s - CHECK: SizeOfHeapReserve: 12288 + +# RUN: not lld-link --rsp-quoting=foobar @%t.rsp 2>&1 | \ +# RUN: FileCheck --check-prefix=INVRSP %s +INVRSP: invalid response file quoting: foobar + +# RUN: echo "blah\foo" > %t.rsp +# RUN: not lld-link @%t.rsp 2>&1 | \ +# RUN: FileCheck --check-prefix=DEFRSP %s +DEFRSP: error: could not open blah\foo + +# RUN: echo "blah\foo" > %t.rsp +# RUN: not lld-link --rsp-quoting=windows @%t.rsp 2>&1 | \ +# RUN: FileCheck --check-prefix=WINRSP %s +WINRSP: error: could not open blah\foo + +# RUN: echo "blah\foo" > %t.rsp +# RUN: not lld-link --rsp-quoting=posix @%t.rsp 2>&1 | \ +# RUN: FileCheck --check-prefix=POSRSP %s +POSRSP: error: could not open blahfoo