From 115d7c1036c899c135ddebde01d12c98cda67489 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sun, 7 Jun 2015 02:55:19 +0000 Subject: [PATCH] COFF: Support resonpse files. llvm-svn: 239242 --- lld/COFF/Driver.cpp | 23 +----------- lld/COFF/Driver.h | 27 ++++++++++++-- lld/COFF/DriverUtils.cpp | 66 +++++++++++++++++++++++++++++++-- lld/test/COFF/responsefile.test | 7 ++++ 4 files changed, 96 insertions(+), 27 deletions(-) create mode 100644 lld/test/COFF/responsefile.test diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index b40a3a7ce41d..be4cf5381b94 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -77,31 +77,12 @@ ErrorOr> LinkerDriver::openFile(StringRef Path) { return std::unique_ptr(new ObjectFile(MBRef)); } -namespace { -class BumpPtrStringSaver : public llvm::cl::StringSaver { -public: - BumpPtrStringSaver(lld::coff::StringAllocator *A) : Alloc(A) {} - const char *SaveString(const char *S) override { - return Alloc->save(S).data(); - } - lld::coff::StringAllocator *Alloc; -}; -} - // Parses .drectve section contents and returns a list of files // specified by /defaultlib. std::error_code LinkerDriver::parseDirectives(StringRef S, std::vector> *Res) { - SmallVector Tokens; - Tokens.push_back("link"); // argv[0] value. Will be ignored. - BumpPtrStringSaver Saver(&Alloc); - llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens); - Tokens.push_back(nullptr); - int Argc = Tokens.size() - 1; - const char **Argv = &Tokens[0]; - - auto ArgsOrErr = parseArgs(Argc, Argv); + auto ArgsOrErr = Parser.parse(S); if (auto EC = ArgsOrErr.getError()) return EC; std::unique_ptr Args = std::move(ArgsOrErr.get()); @@ -204,7 +185,7 @@ bool LinkerDriver::link(int Argc, const char *Argv[]) { llvm::InitializeAllDisassemblers(); // Parse command line options. - auto ArgsOrErr = parseArgs(Argc, Argv); + auto ArgsOrErr = Parser.parse(Argc, Argv); if (auto EC = ArgsOrErr.getError()) { llvm::errs() << EC.message() << "\n"; return false; diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 3186074c376d..d66b289256ce 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -35,6 +35,29 @@ class InputFile; // Entry point of the COFF linker. bool link(int Argc, const char *Argv[]); +class ArgParser { +public: + // Parses command line options. + ErrorOr> parse(int Argc, + const char *Argv[]); + + // Tokenizes a given string and then parses as command line options. + ErrorOr> parse(StringRef S) { + return parse(tokenize(S)); + } + +private: + ErrorOr> + parse(std::vector Argv); + + std::vector tokenize(StringRef S); + + ErrorOr> + replaceResponseFiles(std::vector); + + StringAllocator Alloc; +}; + class LinkerDriver { public: LinkerDriver() : SearchPaths(getSearchPaths()) {} @@ -46,6 +69,7 @@ public: private: StringAllocator Alloc; + ArgParser Parser; // Opens a file. Path has to be resolved already. ErrorOr> openFile(StringRef Path); @@ -68,9 +92,6 @@ private: std::vector> OwningMBs; }; -ErrorOr> -parseArgs(int Argc, const char *Argv[]); - // Functions below this line are defined in DriverUtils.cpp. void printHelp(const char *Argv0); diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp index 0fc6f2f90751..643e3c65c3df 100644 --- a/lld/COFF/DriverUtils.cpp +++ b/lld/COFF/DriverUtils.cpp @@ -159,13 +159,24 @@ public: COFFOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable), true) {} }; +// Parses a given list of options. ErrorOr> -parseArgs(int Argc, const char *Argv[]) { +ArgParser::parse(std::vector Argv) { + // First, replace respnose files (@-style options). + auto ArgvOrErr = replaceResponseFiles(Argv); + if (auto EC = ArgvOrErr.getError()) { + llvm::errs() << "error while reading response file: " << EC.message() + << "\n"; + return EC; + } + Argv = std::move(ArgvOrErr.get()); + + // Make InputArgList from string vectors. COFFOptTable Table; unsigned MissingIndex; unsigned MissingCount; - std::unique_ptr Args( - Table.ParseArgs(&Argv[1], &Argv[Argc], MissingIndex, MissingCount)); + std::unique_ptr Args(Table.ParseArgs( + &Argv[0], &Argv[0] + Argv.size(), MissingIndex, MissingCount)); if (MissingCount) { llvm::errs() << "missing arg value for \"" << Args->getArgString(MissingIndex) @@ -178,6 +189,55 @@ parseArgs(int Argc, const char *Argv[]) { return std::move(Args); } +ErrorOr> +ArgParser::parse(int Argc, const char *Argv[]) { + std::vector V; + V.insert(V.end(), Argv + 1, Argv + Argc); + return parse(V); +} + +namespace { +class BumpPtrStringSaver : public llvm::cl::StringSaver { +public: + BumpPtrStringSaver(lld::coff::StringAllocator *A) : Alloc(A) {} + const char *SaveString(const char *S) override { + return Alloc->save(S).data(); + } + lld::coff::StringAllocator *Alloc; +}; +} + +std::vector ArgParser::tokenize(StringRef S) { + SmallVector Tokens; + BumpPtrStringSaver Saver(&Alloc); + llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens); + std::vector V; + V.insert(V.end(), &Tokens[0], &Tokens[0] + Tokens.size()); + return V; +} + +// Creates a new command line by replaceing options starting with '@' +// character. '@' is replaced by the file's contents. +ErrorOr> +ArgParser::replaceResponseFiles(std::vector Argv) { + std::vector V; + for (const char *S : Argv) { + if (S[0] != '@') { + V.push_back(S); + continue; + } + StringRef Path = S + 1; + auto BufOrErr = MemoryBuffer::getFile(Path); + if (auto EC = BufOrErr.getError()) + return EC; + std::unique_ptr Buf = std::move(BufOrErr.get()); + StringRef Str = Alloc.save(Buf->getBuffer()); + std::vector Tokens = tokenize(Str); + V.insert(V.end(), Tokens.begin(), Tokens.end()); + } + return V; +} + void printHelp(const char *Argv0) { COFFOptTable Table; Table.PrintHelp(llvm::outs(), Argv0, "LLVM Linker", false); diff --git a/lld/test/COFF/responsefile.test b/lld/test/COFF/responsefile.test new file mode 100644 index 000000000000..de383f3f1707 --- /dev/null +++ b/lld/test/COFF/responsefile.test @@ -0,0 +1,7 @@ +# RUN: yaml2obj < %p/Inputs/ret42.yaml > %t.obj + +# RUN: echo /out:%t.exe %t.obj > %t.rsp +# RUN: lld -flavor link2 @%t.rsp /heap:0x3000 +# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s + +CHECK: SizeOfHeapReserve: 12288