Author: joerg
Date: Tue Dec  6 10:33:22 2016
New Revision: 288821

URL: http://llvm.org/viewvc/llvm-project?rev=288821&view=rev
Log:
Allow clang to write compilation database records.

When integrating compilation database output into existing build
systems, two approaches dominate so far. Ad-hoc implementation of the
JSON output rules or using compiler wrappers. This patch adds a new
option "-MJ foo.json" which gives a slightly cleaned up compilation
record. The output is a fragment, i.e. you still need to add the array
markers, but it allows multiple files to be easy merged.

This way the only change in a build system is adding the option with
potentially a per-target output file and merging the files with
something like
  (echo '['; cat *.o.json; echo ']' > compilation_database.json
or some additional filtering to remove the trailing comma for strict
JSON compliance.

Differential Revision: https://reviews.llvm.org/D27140

Added:
    cfe/trunk/test/Driver/compilation_database.c
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
    cfe/trunk/include/clang/Driver/Options.td
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Driver/Tools.h

Modified: cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td?rev=288821&r1=288820&r2=288821&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticDriverKinds.td Tue Dec  6 10:33:22 
2016
@@ -87,6 +87,8 @@ def err_drv_clang_unsupported_opt_cxx_da
   "the clang compiler does not support '%0' for C++ on Darwin/i386">;
 def err_drv_command_failed : Error<
   "%0 command failed with exit code %1 (use -v to see invocation)">;
+def err_drv_compilationdatabase : Error<
+  "compilation database '%0' could not be opened: %1">;
 def err_drv_command_signalled : Error<
   "%0 command failed due to signal (use -v to see invocation)">;
 def err_drv_force_crash : Error<

Modified: cfe/trunk/include/clang/Driver/Options.td
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=288821&r1=288820&r2=288821&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Options.td (original)
+++ cfe/trunk/include/clang/Driver/Options.td Tue Dec  6 10:33:22 2016
@@ -266,6 +266,8 @@ def MF : JoinedOrSeparate<["-"], "MF">,
     MetaVarName<"<file>">;
 def MG : Flag<["-"], "MG">, Group<M_Group>, Flags<[CC1Option]>,
     HelpText<"Add missing headers to depfile">;
+def MJ : JoinedOrSeparate<["-"], "MJ">, Group<M_Group>,
+    HelpText<"Write a compilation database entry per input">;
 def MP : Flag<["-"], "MP">, Group<M_Group>, Flags<[CC1Option]>,
     HelpText<"Create phony target for each dependency (other than main file)">;
 def MQ : JoinedOrSeparate<["-"], "MQ">, Group<M_Group>, Flags<[CC1Option]>,

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=288821&r1=288820&r2=288821&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Tue Dec  6 10:33:22 2016
@@ -40,9 +40,9 @@
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Process.h"
 #include "llvm/Support/Program.h"
-#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/ScopedPrinter.h"
 #include "llvm/Support/TargetParser.h"
+#include "llvm/Support/YAMLParser.h"
 
 #ifdef LLVM_ON_UNIX
 #include <unistd.h> // For getuid().
@@ -4030,6 +4030,60 @@ static void AddAssemblerKPIC(const ToolC
     CmdArgs.push_back("-KPIC");
 }
 
+void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename,
+                                    StringRef Target, const InputInfo &Output,
+                                    const InputInfo &Input, const ArgList 
&Args) const {
+  // If this is a dry run, do not create the compilation database file.
+  if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
+    return;
+
+  using llvm::yaml::escape;
+  const Driver &D = getToolChain().getDriver();
+
+  if (!CompilationDatabase) {
+    std::error_code EC;
+    auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC, 
llvm::sys::fs::F_Text);
+    if (EC) {
+      D.Diag(clang::diag::err_drv_compilationdatabase) << Filename
+                                                       << EC.message();
+      return;
+    }
+    CompilationDatabase = std::move(File);
+  }
+  auto &CDB = *CompilationDatabase;
+  SmallString<128> Buf;
+  if (llvm::sys::fs::current_path(Buf))
+    Buf = ".";
+  CDB << "{ \"directory\": \"" << escape(Buf) << "\"";
+  CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\"";
+  CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\"";
+  CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\"";
+  Buf = "-x";
+  Buf += types::getTypeName(Input.getType());
+  CDB << ", \"" << escape(Buf) << "\"";
+  CDB << ", \"" << escape(Input.getFilename()) << "\"";
+  for (auto &A: Args) {
+    auto &O = A->getOption();
+    // Skip language selection, which is positional.
+    if (O.getID() == options::OPT_x)
+      continue;
+    // Skip writing dependency output and the compilation database itself.
+    if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group)
+      continue;
+    // Skip inputs.
+    if (O.getKind() == Option::InputClass)
+      continue;
+    // All other arguments are quoted and appended.
+    ArgStringList ASL;
+    A->render(Args, ASL);
+    for (auto &it: ASL)
+      CDB << ", \"" << escape(it) << "\"";
+  }
+  Buf = "--target=";
+  Buf += Target;
+  CDB << ", \"" << escape(Buf) << "\"]},\n";
+}
+
 void Clang::ConstructJob(Compilation &C, const JobAction &JA,
                          const InputInfo &Output, const InputInfoList &Inputs,
                          const ArgList &Args, const char *LinkingOutput) const 
{
@@ -4074,6 +4128,11 @@ void Clang::ConstructJob(Compilation &C,
   CmdArgs.push_back("-triple");
   CmdArgs.push_back(Args.MakeArgString(TripleStr));
 
+  if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) {
+    DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args);
+    Args.ClaimAllArgs(options::OPT_MJ);
+  }
+
   if (IsCuda) {
     // We have to pass the triple of the host if compiling for a CUDA device 
and
     // vice-versa.

Modified: cfe/trunk/lib/Driver/Tools.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.h?rev=288821&r1=288820&r2=288821&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.h (original)
+++ cfe/trunk/lib/Driver/Tools.h Tue Dec  6 10:33:22 2016
@@ -17,6 +17,7 @@
 #include "clang/Driver/Util.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/Option/Option.h"
+#include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/Compiler.h"
 
 namespace clang {
@@ -101,6 +102,12 @@ private:
 
   mutable std::unique_ptr<visualstudio::Compiler> CLFallback;
 
+  mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr;
+  void DumpCompilationDatabase(Compilation &C, StringRef Filename,
+                               StringRef Target,
+                               const InputInfo &Output, const InputInfo &Input,
+                               const llvm::opt::ArgList &Args) const;
+
 public:
   // CAUTION! The first constructor argument ("clang") is not arbitrary,
   // as it is for other tools. Some operations on a Tool actually test

Added: cfe/trunk/test/Driver/compilation_database.c
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/compilation_database.c?rev=288821&view=auto
==============================================================================
--- cfe/trunk/test/Driver/compilation_database.c (added)
+++ cfe/trunk/test/Driver/compilation_database.c Tue Dec  6 10:33:22 2016
@@ -0,0 +1,10 @@
+// RUN: %clang -MD -MP -c -x c %s -xc++ %s -Wall -MJ - 2>&1 | FileCheck %s
+// RUN: not %clang -c -x c %s -MJ %s/non-existant 2>&1 | FileCheck 
--check-prefix=ERROR %s
+
+// CHECK: { "directory": "[[CWD:[^"]+]]",  "file": 
"[[SRC:[^"]+[/|\\]compilation_database.c]]", "output": 
"compilation_database.o", "arguments": ["{{[^"]*}}clang{{[^"]*}}", "-xc", 
"[[SRC]]", "-c", "-Wall", "--target={{[^"]+}}"]},
+// CHECK: { "directory": "[[CWD:[^"]+]]",  "file": 
"[[SRC:[^"]+[/|\\]compilation_database.c]]", "output": 
"compilation_database.o", "arguments": ["{{[^"]*}}clang{{[^"]*}}", "-xc++", 
"[[SRC]]", "-c", "-Wall", "--target={{[^"]+}}"]},
+// ERROR: error: compilation database '{{.*}}/non-existant' could not be 
opened:
+
+int main(void) {
+  return 0;
+}


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to