use the clang driver to obtain command line arguments for the clang frontend
authorSven Verdoolaege <skimo@kotnet.org>
Sun, 13 Nov 2011 14:39:55 +0000 (15:39 +0100)
committerSven Verdoolaege <skimo@kotnet.org>
Sun, 13 Nov 2011 14:45:24 +0000 (15:45 +0100)
Recent clang perform the Linux header searching in the driver instead
of the fronted.  We therefore need to call the driver to obtain
the system include paths and pass them along to the frontend.

Helped-by: Chandler Carruth <chandlerc@google.com>
Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
configure.ac
interface/extract_interface.cc

index e16a0fb..f5aaaa1 100644 (file)
@@ -136,6 +136,12 @@ system)
                [AC_DEFINE([DiagnosticsEngine],
                        [Diagnostic],
            [Define to Diagnostic for older versions of clang])])
+       AC_EGREP_HEADER([ArrayRef], [clang/Driver/Driver.h],
+               [AC_DEFINE([USE_ARRAYREF], [],
+                       [Define if Driver::BuildCompilation takes ArrayRef])])
+       AC_EGREP_HEADER([CXXIsProduction], [clang/Driver/Driver.h],
+               [AC_DEFINE([HAVE_CXXISPRODUCTION], [],
+               [Define if Driver constructor takes CXXIsProduction argument])])
        AC_LANG_POP
        CPPFLAGS="$SAVE_CPPFLAGS"
        ;;
index 89baf81..006a3bf 100644 (file)
@@ -44,6 +44,9 @@
 #include <clang/Basic/TargetOptions.h>
 #include <clang/Basic/TargetInfo.h>
 #include <clang/Basic/Version.h>
+#include <clang/Driver/Compilation.h>
+#include <clang/Driver/Driver.h>
+#include <clang/Driver/Tool.h>
 #include <clang/Frontend/CompilerInstance.h>
 #include <clang/Frontend/CompilerInvocation.h>
 #include <clang/Frontend/DiagnosticOptions.h>
@@ -60,6 +63,7 @@
 
 using namespace std;
 using namespace clang;
+using namespace clang::driver;
 
 static llvm::cl::opt<string> InputFilename(llvm::cl::Positional,
                        llvm::cl::Required, llvm::cl::desc("<input file>"));
@@ -127,6 +131,62 @@ struct MyASTConsumer : public ASTConsumer {
        }
 };
 
+#ifdef USE_ARRAYREF
+
+#ifdef HAVE_CXXISPRODUCTION
+static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
+{
+       return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
+                           "", false, false, Diags);
+}
+#else
+static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
+{
+       return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
+                           "", false, Diags);
+}
+#endif
+
+/* Create a CompilerInvocation object that stores the command line
+ * arguments constructed by the driver.
+ * The arguments are mainly useful for setting up the system include
+ * paths on newer clangs and on some platforms.
+ */
+static CompilerInvocation *construct_invocation(const char *filename,
+       DiagnosticsEngine &Diags)
+{
+       const char *binary = CLANG_PREFIX"/bin/clang";
+       const llvm::OwningPtr<Driver> driver(construct_driver(binary, Diags));
+       std::vector<const char *> Argv;
+       Argv.push_back(binary);
+       Argv.push_back(filename);
+       const llvm::OwningPtr<Compilation> compilation(
+               driver->BuildCompilation(ArrayRef<const char *>(Argv)));
+       JobList &Jobs = compilation->getJobs();
+
+       Command *cmd = cast<Command>(*Jobs.begin());
+       if (strcmp(cmd->getCreator().getName(), "clang"))
+               return NULL;
+
+       const ArgStringList *args = &cmd->getArguments();
+
+       CompilerInvocation *invocation = new CompilerInvocation;
+       CompilerInvocation::CreateFromArgs(*invocation, args->data() + 1,
+                                               args->data() + args->size(),
+                                               Diags);
+       return invocation;
+}
+
+#else
+
+static CompilerInvocation *construct_invocation(const char *filename,
+       DiagnosticsEngine &Diags)
+{
+       return NULL;
+}
+
+#endif
+
 int main(int argc, char *argv[])
 {
        llvm::cl::ParseCommandLineOptions(argc, argv);
@@ -137,6 +197,10 @@ int main(int argc, char *argv[])
                                new TextDiagnosticPrinter(llvm::errs(), DO));
        DiagnosticsEngine &Diags = Clang->getDiagnostics();
        Diags.setSuppressSystemWarnings(true);
+       CompilerInvocation *invocation =
+               construct_invocation(InputFilename.c_str(), Diags);
+       if (invocation)
+               Clang->setInvocation(invocation);
        Clang->createFileManager();
        Clang->createSourceManager(Clang->getFileManager());
        TargetOptions TO;