From 8a1af325b424c3cf62a6164a43466b473ec5a666 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Mon, 19 Jul 2010 15:20:12 +0000 Subject: [PATCH] Implement support for reading arguments specified in a file with @file. If there is no file named "file", keep the @file option unchanged. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@108697 91177308-0d34-0410-b5e6-96231b3b80d8 --- test/Driver/at_file.c | 30 ++++++++++ test/Driver/at_file.c.args | 11 ++++ tools/driver/driver.cpp | 114 +++++++++++++++++++++++++++++++------ 3 files changed, 137 insertions(+), 18 deletions(-) create mode 100644 test/Driver/at_file.c create mode 100644 test/Driver/at_file.c.args diff --git a/test/Driver/at_file.c b/test/Driver/at_file.c new file mode 100644 index 0000000000..4ad2a5fde3 --- /dev/null +++ b/test/Driver/at_file.c @@ -0,0 +1,30 @@ +// RUN: %clang -E %s @%s.args -o %t.log +// RUN: FileCheck --input-file=%t.log %s + +// CHECK: bar1 +// CHECK-NEXT: bar2 zed2 +// CHECK-NEXT: bar3 zed3 +// CHECK-NEXT: bar4 zed4 +// CHECK-NEXT: bar5 zed5 +// CHECK-NEXT: 'bar6 zed6' +// CHECK-NEXT: "bar7 zed7" +// CHECK-NEXT: foo8bar8zed8 +// CHECK-NEXT: foo9'bar9'zed9 +// CHECK-NEXT: foo10"bar10"zed10 +// CHECK: bar +// CHECK: zed12 + +foo1 +foo2 +foo3 +foo4 +foo5 +foo6 +foo7 +foo8 +foo9 +foo10 +#ifdef foo11 +bar +#endif +foo12 diff --git a/test/Driver/at_file.c.args b/test/Driver/at_file.c.args new file mode 100644 index 0000000000..9a2b4ee93b --- /dev/null +++ b/test/Driver/at_file.c.args @@ -0,0 +1,11 @@ +-Dfoo1=bar1 -Dfoo2="bar2 zed2" +-Dfoo3='bar3 zed3' +"-Dfoo4=bar4 zed4" +'-Dfoo5=bar5 zed5' +-Dfoo6="'bar6 zed6'" +-Dfoo7='"bar7 zed7"' +-Dfoo8=foo8"bar8"zed8 +-Dfoo9=foo9\'bar9\'zed9 +-Dfoo10=foo10\"bar10\"zed10 +-D foo11 +-Dfoo12=zed12\ diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 22af58fe6c..6dc8d6fceb 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -19,9 +19,12 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Config/config.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Regex.h" #include "llvm/Support/Timer.h" @@ -173,19 +176,97 @@ extern int cc1_main(const char **ArgBegin, const char **ArgEnd, extern int cc1as_main(const char **ArgBegin, const char **ArgEnd, const char *Argv0, void *MainAddr); -int main(int argc, const char **argv) { +static void ExpandArgsFromBuf(const char *Arg, + std::vector &ArgVector, + std::set &SavedStrings) { + const char *FName = Arg + 1; + llvm::MemoryBuffer *MemBuf = llvm::MemoryBuffer::getFile(FName); + if (!MemBuf) { + ArgVector.push_back(SaveStringInSet(SavedStrings, Arg)); + return; + } + + const char *Buf = MemBuf->getBufferStart(); + char InQuote = ' '; + std::string CurArg; + + for (const char *P = Buf; ; ++P) { + if (*P == '\0' || (isspace(*P) && InQuote == ' ')) { + if (!CurArg.empty()) { + + if (CurArg[0] != '@') { + ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg)); + } else { + ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings); + } + + CurArg = ""; + } + if (*P == '\0') + break; + else + continue; + } + + if (isspace(*P)) { + if (InQuote != ' ') + CurArg.push_back(*P); + continue; + } + + if (*P == '"' || *P == '\'') { + if (InQuote == *P) + InQuote = ' '; + else if (InQuote == ' ') + InQuote = *P; + else + CurArg.push_back(*P); + continue; + } + + if (*P == '\\') { + ++P; + if (*P != '\0') + CurArg.push_back(*P); + continue; + } + CurArg.push_back(*P); + } + delete MemBuf; +} + +static void ExpandArgv(int argc, const char **argv, + std::vector &ArgVector, + std::set &SavedStrings) { + for (int i = 0; i < argc; ++i) { + const char *Arg = argv[i]; + if (Arg[0] != '@') { + ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg))); + continue; + } + + ExpandArgsFromBuf(Arg, ArgVector, SavedStrings); + } +} + +int main(int argc_, const char **argv_) { llvm::sys::PrintStackTraceOnErrorSignal(); - llvm::PrettyStackTraceProgram X(argc, argv); + llvm::PrettyStackTraceProgram X(argc_, argv_); + + std::set SavedStrings; + std::vector argv; + + ExpandArgv(argc_, argv_, argv, SavedStrings); // Handle -cc1 integrated tools. - if (argc > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) { + if (argv.size() > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) { llvm::StringRef Tool = argv[1] + 4; if (Tool == "") - return cc1_main(argv+2, argv+argc, argv[0], + return cc1_main(&argv[2], &argv[argv.size()], argv[0], (void*) (intptr_t) GetExecutablePath); if (Tool == "as") - return cc1as_main(argv+2, argv+argc, argv[0], + return cc1as_main(&argv[2], &argv[argv.size()], argv[0], (void*) (intptr_t) GetExecutablePath); // Reject unknown tools. @@ -194,7 +275,7 @@ int main(int argc, const char **argv) { } bool CanonicalPrefixes = true; - for (int i = 1; i < argc; ++i) { + for (int i = 1, size = argv.size(); i < size; ++i) { if (llvm::StringRef(argv[i]) == "-no-canonical-prefixes") { CanonicalPrefixes = false; break; @@ -230,7 +311,8 @@ int main(int argc, const char **argv) { // being a symlink. // // We use *argv instead of argv[0] to work around a bogus g++ warning. - std::string ProgName(llvm::sys::Path(*argv).getBasename()); + const char *progname = argv_[0]; + std::string ProgName(llvm::sys::Path(progname).getBasename()); if (llvm::StringRef(ProgName).endswith("++") || llvm::StringRef(ProgName).rsplit('-').first.endswith("++")) { TheDriver.CCCIsCXX = true; @@ -246,34 +328,30 @@ int main(int argc, const char **argv) { // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a // command line behind the scenes. - std::set SavedStrings; - std::vector StringPointers(argv, argv + argc); if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) { // FIXME: Driver shouldn't take extra initial argument. - ApplyQAOverride(StringPointers, OverrideStr, SavedStrings); + ApplyQAOverride(argv, OverrideStr, SavedStrings); } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) { // FIXME: Driver shouldn't take extra initial argument. - StringPointers.clear(); - StringPointers.push_back(argv[0]); + std::vector ExtraArgs; for (;;) { const char *Next = strchr(Cur, ','); if (Next) { - StringPointers.push_back(SaveStringInSet(SavedStrings, - std::string(Cur, Next))); + ExtraArgs.push_back(SaveStringInSet(SavedStrings, + std::string(Cur, Next))); Cur = Next + 1; } else { if (*Cur != '\0') - StringPointers.push_back(SaveStringInSet(SavedStrings, Cur)); + ExtraArgs.push_back(SaveStringInSet(SavedStrings, Cur)); break; } } - StringPointers.insert(StringPointers.end(), argv + 1, argv + argc); + argv.insert(++argv.begin(), ExtraArgs.begin(), ExtraArgs.end()); } - C.reset(TheDriver.BuildCompilation(StringPointers.size(), - &StringPointers[0])); + C.reset(TheDriver.BuildCompilation(argv.size(), &argv[0])); int Res = 0; if (C.get()) -- 2.40.0